diff options
author | Fred Quintana <fredq@google.com> | 2009-05-07 17:35:38 -0700 |
---|---|---|
committer | Fred Quintana <fredq@google.com> | 2009-05-13 12:49:04 -0700 |
commit | 6a8d5332f00bdfade6674b312e7166940aa28348 (patch) | |
tree | c45f5e5bc0fb4918e3df45821c723845d64506d3 /core | |
parent | 7dfc85f1199790a3c3dab701cec45045d100d7d3 (diff) | |
download | frameworks_base-6a8d5332f00bdfade6674b312e7166940aa28348.zip frameworks_base-6a8d5332f00bdfade6674b312e7166940aa28348.tar.gz frameworks_base-6a8d5332f00bdfade6674b312e7166940aa28348.tar.bz2 |
content provider entities
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/content/AbstractCursorEntityIterator.java | 112 | ||||
-rw-r--r-- | core/java/android/content/ContentProvider.java | 45 | ||||
-rw-r--r-- | core/java/android/content/ContentProviderClient.java | 58 | ||||
-rw-r--r-- | core/java/android/content/ContentProviderNative.java | 165 | ||||
-rw-r--r-- | core/java/android/content/ContentResolver.java | 97 | ||||
-rw-r--r-- | core/java/android/content/Entity.aidl | 20 | ||||
-rw-r--r-- | core/java/android/content/Entity.java | 26 | ||||
-rw-r--r-- | core/java/android/content/EntityIterator.java | 49 | ||||
-rw-r--r-- | core/java/android/content/IContentProvider.java | 8 | ||||
-rw-r--r-- | core/java/android/content/IEntityIterator.java | 187 |
10 files changed, 758 insertions, 9 deletions
diff --git a/core/java/android/content/AbstractCursorEntityIterator.java b/core/java/android/content/AbstractCursorEntityIterator.java new file mode 100644 index 0000000..bf3c4de --- /dev/null +++ b/core/java/android/content/AbstractCursorEntityIterator.java @@ -0,0 +1,112 @@ +package android.content; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.RemoteException; + +/** + * An abstract class that makes it easy to implement an EntityIterator over a cursor. + * The user must implement {@link #newEntityFromCursorLocked}, which runs inside of a + * database transaction. + */ +public abstract class AbstractCursorEntityIterator implements EntityIterator { + private final Cursor mEntityCursor; + private final SQLiteDatabase mDb; + private volatile Entity mNextEntity; + private volatile boolean mIsClosed; + + public AbstractCursorEntityIterator(SQLiteDatabase db, Cursor entityCursor) { + mEntityCursor = entityCursor; + mDb = db; + mNextEntity = null; + mIsClosed = false; + } + + /** + * If there are entries left in the cursor then advance the cursor and use the new row to + * populate mNextEntity. If the cursor is at the end or if advancing it causes the cursor + * to become at the end then set mEntityCursor to null. If newEntityFromCursor returns null + * then continue advancing until it either returns a non-null Entity or the cursor reaches + * the end. + */ + private void fillEntityIfAvailable() { + while (mNextEntity == null) { + if (!mEntityCursor.moveToNext()) { + // the cursor is at then end, bail out + return; + } + // This may return null if newEntityFromCursor is not able to create an entity + // from the current cursor position. In that case this method will loop and try + // the next cursor position + mNextEntity = newEntityFromCursorLocked(mEntityCursor); + } + mDb.beginTransaction(); + try { + int position = mEntityCursor.getPosition(); + mNextEntity = newEntityFromCursorLocked(mEntityCursor); + int newPosition = mEntityCursor.getPosition(); + if (newPosition != position) { + throw new IllegalStateException("the cursor position changed during the call to" + + "newEntityFromCursorLocked, from " + position + " to " + newPosition); + } + } finally { + mDb.endTransaction(); + } + } + + /** + * Checks if there are more Entities accessible via this iterator. This may not be called + * if the iterator is already closed. + * @return true if the call to next() will return an Entity. + */ + public boolean hasNext() { + if (mIsClosed) { + throw new IllegalStateException("calling hasNext() when the iterator is closed"); + } + fillEntityIfAvailable(); + return mNextEntity != null; + } + + /** + * Returns the next Entity that is accessible via this iterator. This may not be called + * if the iterator is already closed. + * @return the next Entity that is accessible via this iterator + */ + public Entity next() { + if (mIsClosed) { + throw new IllegalStateException("calling next() when the iterator is closed"); + } + if (!hasNext()) { + throw new IllegalStateException("you may only call next() if hasNext() is true"); + } + + try { + return mNextEntity; + } finally { + mNextEntity = null; + } + } + + /** + * Closes this iterator making it invalid. If is invalid for the user to call any public + * method on the iterator once it has been closed. + */ + public void close() { + if (mIsClosed) { + throw new IllegalStateException("closing when already closed"); + } + mIsClosed = true; + mEntityCursor.close(); + } + + /** + * Returns a new Entity from the current cursor position. This is called from within a + * database transaction. If a new entity cannot be created from this cursor position (e.g. + * if the row that is referred to no longer exists) then this may return null. The cursor + * is guaranteed to be pointing to a valid row when this call is made. The implementation + * of newEntityFromCursorLocked is not allowed to change the position of the cursor. + * @param cursor from where to read the data for the Entity + * @return an Entity that corresponds to the current cursor position or null + */ + public abstract Entity newEntityFromCursorLocked(Cursor cursor); +} diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 3a080a0..3a8de6e 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -130,6 +130,12 @@ public abstract class ContentProvider implements ComponentCallbacks { selectionArgs, sortOrder); } + public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, + String sortOrder) { + checkReadPermission(uri); + return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder); + } + public String getType(Uri uri) { return ContentProvider.this.getType(uri); } @@ -145,6 +151,11 @@ public abstract class ContentProvider implements ComponentCallbacks { return ContentProvider.this.bulkInsert(uri, initialValues); } + public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) { + checkWritePermission(uri); + return ContentProvider.this.bulkInsertEntities(uri, entities); + } + public int delete(Uri uri, String selection, String[] selectionArgs) { checkWritePermission(uri); return ContentProvider.this.delete(uri, selection, selectionArgs); @@ -156,6 +167,11 @@ public abstract class ContentProvider implements ComponentCallbacks { return ContentProvider.this.update(uri, values, selection, selectionArgs); } + public int[] bulkUpdateEntities(Uri uri, Entity[] entities) { + checkWritePermission(uri); + return ContentProvider.this.bulkUpdateEntities(uri, entities); + } + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { if (mode != null && mode.startsWith("rw")) checkWritePermission(uri); @@ -328,6 +344,11 @@ public abstract class ContentProvider implements ComponentCallbacks { public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder); + public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, + String sortOrder) { + throw new UnsupportedOperationException(); + } + /** * Return the MIME type of the data at the given URI. This should start with * <code>vnd.android.cursor.item</code> for a single record, @@ -378,6 +399,18 @@ public abstract class ContentProvider implements ComponentCallbacks { return numValues; } + public Uri insertEntity(Uri uri, Entity entity) { + throw new UnsupportedOperationException(); + } + + public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) { + Uri[] result = new Uri[entities.length]; + for (int i = 0; i < entities.length; i++) { + result[i] = insertEntity(uri, entities[i]); + } + return result; + } + /** * A request to delete one or more rows. The selection clause is applied when performing * the deletion, allowing the operation to affect multiple rows in a @@ -422,6 +455,18 @@ public abstract class ContentProvider implements ComponentCallbacks { public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs); + public int updateEntity(Uri uri, Entity entity) { + throw new UnsupportedOperationException(); + } + + public int[] bulkUpdateEntities(Uri uri, Entity[] entities) { + int[] result = new int[entities.length]; + for (int i = 0; i < entities.length; i++) { + result[i] = updateEntity(uri, entities[i]); + } + return result; + } + /** * Open a file blob associated with a content URI. * This method can be called from multiple diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 9902807..ed3ed42 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.content; import android.database.Cursor; @@ -26,52 +42,78 @@ public class ContentProviderClient { mContentResolver = contentResolver; } - /** {@see ContentProvider#query} */ + /** see {@link ContentProvider#query} */ public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws RemoteException { return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder); } - /** {@see ContentProvider#getType} */ + /** see {@link ContentProvider#getType} */ public String getType(Uri url) throws RemoteException { return mContentProvider.getType(url); } - /** {@see ContentProvider#insert} */ + /** see {@link ContentProvider#insert} */ public Uri insert(Uri url, ContentValues initialValues) throws RemoteException { return mContentProvider.insert(url, initialValues); } - /** {@see ContentProvider#bulkInsert} */ + /** see {@link ContentProvider#bulkInsert} */ public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException { return mContentProvider.bulkInsert(url, initialValues); } - /** {@see ContentProvider#delete} */ + /** see {@link ContentProvider#delete} */ public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { return mContentProvider.delete(url, selection, selectionArgs); } - /** {@see ContentProvider#update} */ + /** see {@link ContentProvider#update} */ public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) throws RemoteException { return mContentProvider.update(url, values, selection, selectionArgs); } - /** {@see ContentProvider#openFile} */ + /** see {@link ContentProvider#openFile} */ public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return mContentProvider.openFile(url, mode); } - /** {@see ContentProvider#openAssetFile} */ + /** see {@link ContentProvider#openAssetFile} */ public AssetFileDescriptor openAssetFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return mContentProvider.openAssetFile(url, mode); } + /** see {@link ContentProvider#queryEntities} */ + public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, + String sortOrder) throws RemoteException { + return mContentProvider.queryEntities(uri, selection, selectionArgs, sortOrder); + } + + /** see {@link ContentProvider#insertEntity} */ + public Uri insertEntity(Uri uri, Entity entity) throws RemoteException { + return mContentProvider.bulkInsertEntities(uri, new Entity[]{entity})[0]; + } + + /** see {@link ContentProvider#bulkInsertEntities} */ + public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException { + return mContentProvider.bulkInsertEntities(uri, entities); + } + + /** see {@link ContentProvider#updateEntity} */ + public int updateEntity(Uri uri, Entity entity) throws RemoteException { + return mContentProvider.bulkUpdateEntities(uri, new Entity[]{entity})[0]; + } + + /** see {@link ContentProvider#bulkUpdateEntities} */ + public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException { + return mContentProvider.bulkUpdateEntities(uri, entities); + } + /** * Call this to indicate to the system that the associated {@link ContentProvider} is no * longer needed by this {@link ContentProviderClient}. diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index f9282e2..ac67076 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -105,6 +105,20 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } + case QUERY_ENTITIES_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + Uri url = Uri.CREATOR.createFromParcel(data); + String selection = data.readString(); + String[] selectionArgs = data.readStringArray(); + String sortOrder = data.readString(); + EntityIterator entityIterator = queryEntities(url, selection, selectionArgs, + sortOrder); + reply.writeNoException(); + reply.writeStrongBinder(new IEntityIteratorImpl(entityIterator).asBinder()); + return true; + } + case GET_TYPE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); @@ -140,6 +154,40 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } + case BULK_INSERT_ENTITIES_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + Uri uri = Uri.CREATOR.createFromParcel(data); + String className = data.readString(); + Class entityClass = Class.forName(className); + int numEntities = data.readInt(); + Entity[] entities = new Entity[numEntities]; + for (int i = 0; i < numEntities; i++) { + entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader()); + } + Uri[] uris = bulkInsertEntities(uri, entities); + reply.writeNoException(); + reply.writeTypedArray(uris, 0); + return true; + } + + case BULK_UPDATE_ENTITIES_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + Uri uri = Uri.CREATOR.createFromParcel(data); + String className = data.readString(); + Class entityClass = Class.forName(className); + int numEntities = data.readInt(); + Entity[] entities = new Entity[numEntities]; + for (int i = 0; i < numEntities; i++) { + entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader()); + } + int[] counts = bulkUpdateEntities(uri, entities); + reply.writeNoException(); + reply.writeIntArray(counts); + return true; + } + case DELETE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); @@ -215,6 +263,25 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return super.onTransact(code, data, reply, flags); } + private class IEntityIteratorImpl extends IEntityIterator.Stub { + private final EntityIterator mEntityIterator; + + IEntityIteratorImpl(EntityIterator iterator) { + mEntityIterator = iterator; + } + public boolean hasNext() throws RemoteException { + return mEntityIterator.hasNext(); + } + + public Entity next() throws RemoteException { + return mEntityIterator.next(); + } + + public void close() throws RemoteException { + mEntityIterator.close(); + } + } + public IBinder asBinder() { return this; @@ -288,7 +355,7 @@ final class ContentProviderProxy implements IContentProvider BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, adaptor.getObserver(), window); - + if (bulkCursor == null) { return null; } @@ -296,6 +363,54 @@ final class ContentProviderProxy implements IContentProvider return adaptor; } + public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs, + String sortOrder) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + + data.writeInterfaceToken(IContentProvider.descriptor); + + url.writeToParcel(data, 0); + data.writeString(selection); + data.writeStringArray(selectionArgs); + data.writeString(sortOrder); + + mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + + IBinder entityIteratorBinder = reply.readStrongBinder(); + + data.recycle(); + reply.recycle(); + + return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder)); + } + + static class RemoteEntityIterator implements EntityIterator { + private final IEntityIterator mEntityIterator; + RemoteEntityIterator(IEntityIterator entityIterator) { + mEntityIterator = entityIterator; + } + + public boolean hasNext() throws RemoteException { + return mEntityIterator.hasNext(); + } + + public Entity next() throws RemoteException { + return mEntityIterator.next(); + } + + public void close() { + try { + mEntityIterator.close(); + } catch (RemoteException e) { + // doesn't matter + } + } + } + public String getType(Uri url) throws RemoteException { Parcel data = Parcel.obtain(); @@ -357,6 +472,54 @@ final class ContentProviderProxy implements IContentProvider return count; } + public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + + data.writeInterfaceToken(IContentProvider.descriptor); + uri.writeToParcel(data, 0); + data.writeString(entities[0].getClass().getName()); + data.writeInt(entities.length); + for (Entity entity : entities) { + data.writeParcelable(entity, 0); + } + + mRemote.transact(IContentProvider.BULK_INSERT_ENTITIES_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + Uri[] results = new Uri[entities.length]; + reply.readTypedArray(results, Uri.CREATOR); + + data.recycle(); + reply.recycle(); + + return results; + } + + public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + + data.writeInterfaceToken(IContentProvider.descriptor); + uri.writeToParcel(data, 0); + data.writeString(entities[0].getClass().getName()); + data.writeInt(entities.length); + for (Entity entity : entities) { + data.writeParcelable(entity, 0); + } + + mRemote.transact(IContentProvider.BULK_UPDATE_ENTITIES_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + int[] results = new int[entities.length]; + reply.readIntArray(results); + + data.recycle(); + reply.recycle(); + + return results; + } + public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 6f3b1b6..f9bed59 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -166,6 +166,53 @@ public abstract class ContentResolver { } } + class EntityIteratorWrapper implements EntityIterator { + private final EntityIterator mInner; + private final ContentProviderClient mClient; + + EntityIteratorWrapper(EntityIterator inner, ContentProviderClient client) { + mInner = inner; + mClient = client; + } + + public boolean hasNext() throws RemoteException { + return mInner.hasNext(); + } + + public Entity next() throws RemoteException { + return mInner.next(); + } + + public void close() { + mClient.release(); + mInner.close(); + } + + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + } + + public final EntityIterator queryEntity(Uri uri, + String selection, String[] selectionArgs, String sortOrder) throws RemoteException { + ContentProviderClient provider = acquireContentProviderClient(uri); + if (provider == null) { + throw new IllegalArgumentException("Unknown URL " + uri); + } + try { + EntityIterator entityIterator = + provider.queryEntities(uri, selection, selectionArgs, sortOrder); + return new EntityIteratorWrapper(entityIterator, provider); + } catch(RuntimeException e) { + provider.release(); + throw e; + } catch(RemoteException e) { + provider.release(); + throw e; + } + } + /** * Open a stream on to the content associated with a content URI. If there * is no data associated with the URI, FileNotFoundException is thrown. @@ -485,6 +532,56 @@ public abstract class ContentResolver { } } + public final Uri insertEntity(Uri uri, Entity entity) throws RemoteException { + ContentProviderClient provider = acquireContentProviderClient(uri); + if (provider == null) { + throw new IllegalArgumentException("Unknown URL " + uri); + } + try { + return provider.insertEntity(uri, entity); + } finally { + provider.release(); + } + } + + public final int updateEntity(Uri uri, Entity entity) throws RemoteException { + ContentProviderClient provider = acquireContentProviderClient(uri); + if (provider == null) { + throw new IllegalArgumentException("Unknown URL " + uri); + } + try { + return provider.updateEntity(uri, entity); + } finally { + provider.release(); + } + } + + public final Uri[] bulkInsertEntities(Uri uri, Entity[] entities) + throws RemoteException { + ContentProviderClient provider = acquireContentProviderClient(uri); + if (provider == null) { + throw new IllegalArgumentException("Unknown URL " + uri); + } + try { + return provider.bulkInsertEntities(uri, entities); + } finally { + provider.release(); + } + } + + public final int[] bulkUpdateEntities(Uri uri, Entity[] entities) + throws RemoteException { + ContentProviderClient provider = acquireContentProviderClient(uri); + if (provider == null) { + throw new IllegalArgumentException("Unknown URL " + uri); + } + try { + return provider.bulkUpdateEntities(uri, entities); + } finally { + provider.release(); + } + } + /** * Inserts multiple rows into a table at the given URL. * diff --git a/core/java/android/content/Entity.aidl b/core/java/android/content/Entity.aidl new file mode 100644 index 0000000..fb201f3 --- /dev/null +++ b/core/java/android/content/Entity.aidl @@ -0,0 +1,20 @@ +/* //device/java/android/android/content/Entity.aidl +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content; + +parcelable Entity; diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java new file mode 100644 index 0000000..31ea2cd --- /dev/null +++ b/core/java/android/content/Entity.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.os.Parcelable; + +/** + * Objects that pass through the ContentProvider and ContentResolver's methods that deal with + * Entities must implement this abstract base class and thus themselves be Parcelable. + */ +public abstract class Entity implements Parcelable { +} diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java new file mode 100644 index 0000000..61914cf --- /dev/null +++ b/core/java/android/content/EntityIterator.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.os.RemoteException; + +public interface EntityIterator { + /** + * Returns whether there are more elements to iterate, i.e. whether the + * iterator is positioned in front of an element. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + * @see #next + * @since Android 1.0 + */ + public boolean hasNext() throws RemoteException; + + /** + * Returns the next object in the iteration, i.e. returns the element in + * front of the iterator and advances the iterator by one position. + * + * @return the next object. + * @throws java.util.NoSuchElementException + * if there are no more elements. + * @see #hasNext + * @since Android 1.0 + */ + public Entity next() throws RemoteException; + + /** + * Indicates that this iterator is no longer needed and that any associated resources + * may be released (such as a SQLite cursor). + */ + public void close(); +} diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 0b81245..b4d1865 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -43,14 +43,19 @@ public interface IContentProvider extends IInterface { CursorWindow window) throws RemoteException; public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws RemoteException; + public EntityIterator queryEntities(Uri url, String selection, + String[] selectionArgs, String sortOrder) + throws RemoteException; public String getType(Uri url) throws RemoteException; public Uri insert(Uri url, ContentValues initialValues) throws RemoteException; public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException; + public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException; public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException; public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) throws RemoteException; + public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException; public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException; public AssetFileDescriptor openAssetFile(Uri url, String mode) @@ -67,4 +72,7 @@ public interface IContentProvider extends IInterface { static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12; static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13; static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14; + static final int BULK_INSERT_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 16; + static final int BULK_UPDATE_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 17; + static final int QUERY_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 18; } diff --git a/core/java/android/content/IEntityIterator.java b/core/java/android/content/IEntityIterator.java new file mode 100644 index 0000000..eb800f7 --- /dev/null +++ b/core/java/android/content/IEntityIterator.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; +import android.util.Log; + +/** + * ICPC interface methods for an iterator over Entity objects. + */ +public interface IEntityIterator extends IInterface { + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends Binder implements IEntityIterator { + private static final String TAG = "IEntityIterator"; + private static final java.lang.String DESCRIPTOR = "android.content.IEntityIterator"; + + /** Construct the stub at attach it to the interface. */ + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + /** + * Cast an IBinder object into an IEntityIterator interface, + * generating a proxy if needed. + */ + public static IEntityIterator asInterface(IBinder obj) { + if ((obj==null)) { + return null; + } + IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin!=null)&&(iin instanceof IEntityIterator))) { + return ((IEntityIterator)iin); + } + return new IEntityIterator.Stub.Proxy(obj); + } + + public IBinder asBinder() { + return this; + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: + { + reply.writeString(DESCRIPTOR); + return true; + } + + case TRANSACTION_hasNext: + { + data.enforceInterface(DESCRIPTOR); + boolean _result; + try { + _result = this.hasNext(); + } catch (Exception e) { + Log.e(TAG, "caught exception in hasNext()", e); + reply.writeException(e); + return true; + } + reply.writeNoException(); + reply.writeInt(((_result)?(1):(0))); + return true; + } + + case TRANSACTION_next: + { + data.enforceInterface(DESCRIPTOR); + Entity entity; + try { + entity = this.next(); + } catch (RemoteException e) { + Log.e(TAG, "caught exception in next()", e); + reply.writeException(e); + return true; + } + reply.writeNoException(); + reply.writeString(entity.getClass().getName()); + reply.writeParcelable(entity, 0); + return true; + } + + case TRANSACTION_close: + { + data.enforceInterface(DESCRIPTOR); + try { + this.close(); + } catch (RemoteException e) { + Log.e(TAG, "caught exception in close()", e); + reply.writeException(e); + return true; + } + reply.writeNoException(); + return true; + } + } + return super.onTransact(code, data, reply, flags); + } + + private static class Proxy implements IEntityIterator { + private IBinder mRemote; + Proxy(IBinder remote) { + mRemote = remote; + } + public IBinder asBinder() { + return mRemote; + } + public java.lang.String getInterfaceDescriptor() { + return DESCRIPTOR; + } + public boolean hasNext() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + boolean _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_hasNext, _data, _reply, 0); + _reply.readException(); + _result = (0!=_reply.readInt()); + } + finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + + public Entity next() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + Entity _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0); + _reply.readException(); + final String className = _reply.readString(); + final Class entityClass = Class.forName(className); + ClassLoader classLoader = entityClass.getClassLoader(); + _result = (Entity) _reply.readParcelable(classLoader); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + + public void close() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_close, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + } + static final int TRANSACTION_hasNext = (IBinder.FIRST_CALL_TRANSACTION + 0); + static final int TRANSACTION_next = (IBinder.FIRST_CALL_TRANSACTION + 1); + static final int TRANSACTION_close = (IBinder.FIRST_CALL_TRANSACTION + 2); + } + public boolean hasNext() throws RemoteException; + public Entity next() throws RemoteException; + public void close() throws RemoteException; +} |