- removed the concept of Entity from the ContentProvider APIs

- removed the parcelling ability from Entity and EntityIterator and made them public
- added an EntityIterator abstract implementation that allow easy wrapping of a Cursor
- changed the VCard code to use the new APIs
This commit is contained in:
Fred Quintana
2009-12-07 14:52:28 -08:00
parent a50d450863
commit 328c0e7986
20 changed files with 854 additions and 725 deletions

View File

@@ -33868,6 +33868,161 @@
</parameter>
</method>
</interface>
<class name="Entity"
extends="java.lang.Object"
abstract="false"
static="false"
final="true"
deprecated="not deprecated"
visibility="public"
>
<constructor name="Entity"
type="android.content.Entity"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="values" type="android.content.ContentValues">
</parameter>
</constructor>
<method name="addSubValue"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
<method name="getEntityValues"
return="android.content.ContentValues"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="getSubValues"
return="java.util.ArrayList&lt;android.content.Entity.NamedContentValues&gt;"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
</class>
<class name="Entity.NamedContentValues"
extends="java.lang.Object"
abstract="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="Entity.NamedContentValues"
type="android.content.Entity.NamedContentValues"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
</constructor>
<field name="uri"
type="android.net.Uri"
transient="false"
volatile="false"
static="false"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="values"
type="android.content.ContentValues"
transient="false"
volatile="false"
static="false"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class>
<interface name="EntityIterator"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="close"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="hasNext"
return="boolean"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
<method name="next"
return="android.content.Entity"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
<method name="reset"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -49340,6 +49495,23 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
<method name="cursorDoubleToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorDoubleToCursorValues"
return="void"
abstract="false"
@@ -49357,6 +49529,23 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
<method name="cursorFloatToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorIntToContentValues"
return="void"
abstract="false"
@@ -49393,6 +49582,23 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
<method name="cursorIntToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorLongToContentValues"
return="void"
abstract="false"
@@ -49429,6 +49635,23 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
<method name="cursorLongToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorRowToContentValues"
return="void"
abstract="false"
@@ -49444,6 +49667,23 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
<method name="cursorShortToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorStringToContentValues"
return="void"
abstract="false"
@@ -49480,6 +49720,23 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
<method name="cursorStringToContentValuesIfPresent"
return="void"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
<parameter name="values" type="android.content.ContentValues">
</parameter>
<parameter name="column" type="java.lang.String">
</parameter>
</method>
<method name="cursorStringToInsertHelper"
return="void"
abstract="false"
@@ -123844,6 +124101,19 @@
</implements>
<implements name="android.provider.ContactsContract.SyncColumns">
</implements>
<method name="newEntityIterator"
return="android.content.EntityIterator"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
</method>
<field name="CONTENT_ITEM_TYPE"
type="java.lang.String"
transient="false"
@@ -124662,6 +124932,19 @@
<parameter name="rawContactUri" type="android.net.Uri">
</parameter>
</method>
<method name="newEntityIterator"
return="android.content.EntityIterator"
abstract="false"
native="false"
synchronized="false"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="cursor" type="android.database.Cursor">
</parameter>
</method>
<field name="AGGREGATION_MODE_DEFAULT"
type="int"
transient="false"

View File

@@ -1,121 +0,0 @@
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.
* @hide
*/
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;
}
}
public void reset() throws RemoteException {
if (mIsClosed) {
throw new IllegalStateException("calling reset() when the iterator is closed");
}
mEntityCursor.moveToPosition(-1);
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);
}

View File

@@ -38,7 +38,6 @@ public abstract class AsyncQueryHandler extends Handler {
private static final int EVENT_ARG_INSERT = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
private static final int EVENT_ARG_QUERY_ENTITIES = 5;
/* package */ final WeakReference<ContentResolver> mResolver;
@@ -93,18 +92,6 @@ public abstract class AsyncQueryHandler extends Handler {
args.result = cursor;
break;
case EVENT_ARG_QUERY_ENTITIES:
EntityIterator iterator = null;
try {
iterator = resolver.queryEntities(args.uri, args.selection,
args.selectionArgs, args.orderBy);
} catch (Exception e) {
Log.w(TAG, e.toString());
}
args.result = iterator;
break;
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
@@ -194,45 +181,6 @@ public abstract class AsyncQueryHandler extends Handler {
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous query for an {@link EntityIterator}.
* When the query is done {@link #onQueryEntitiesComplete} is called.
*
* @param token A token passed into {@link #onQueryComplete} to identify the
* query.
* @param cookie An object that gets passed into {@link #onQueryComplete}
* @param uri The URI, using the content:// scheme, for the content to
* retrieve.
* @param selection A filter declaring which rows to return, formatted as an
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given URI.
* @param selectionArgs You may include ?s in selection, which will be
* replaced by the values from selectionArgs, in the order that
* they appear in the selection. The values will be bound as
* Strings.
* @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
* (excluding the ORDER BY itself). Passing null will use the
* default sort order, which may be unordered.
* @hide
*/
public void startQueryEntities(int token, Object cookie, Uri uri, String selection,
String[] selectionArgs, String orderBy) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY_ENTITIES;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.selection = selection;
args.selectionArgs = selectionArgs;
args.orderBy = orderBy;
args.cookie = cookie;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* Attempts to cancel operation that has not already started. Note that
* there is no guarantee that the operation will be canceled. They still may
@@ -339,18 +287,6 @@ public abstract class AsyncQueryHandler extends Handler {
// Empty
}
/**
* Called when an asynchronous query is completed.
*
* @param token The token to identify the query.
* @param cookie The cookie object.
* @param iterator The iterator holding the query results.
* @hide
*/
protected void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
// Empty
}
/**
* Called when an asynchronous insert is completed.
*
@@ -408,10 +344,6 @@ public abstract class AsyncQueryHandler extends Handler {
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
case EVENT_ARG_QUERY_ENTITIES:
onQueryEntitiesComplete(token, args.cookie, (EntityIterator)args.result);
break;
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;

View File

@@ -163,15 +163,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
selectionArgs, sortOrder);
}
/**
* @hide
*/
public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
String sortOrder) {
enforceReadPermission(uri);
return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder);
}
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
@@ -476,14 +467,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
/**
* @hide
*/
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,
@@ -581,7 +564,7 @@ public abstract class ContentProvider implements ComponentCallbacks {
/**
* Open a file blob associated with a content URI.
* This method can be called from multiple
* threads, as described inentity
* threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*

View File

@@ -89,16 +89,7 @@ public class ContentProviderClient {
return mContentProvider.openAssetFile(url, mode);
}
/**
* see {@link ContentProvider#queryEntities}
* @hide
*/
public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
String sortOrder) throws RemoteException {
return mContentProvider.queryEntities(uri, selection, selectionArgs, sortOrder);
}
/** see {@link ContentProvider#applyBatch} */
/** see {@link ContentProvider#applyBatch} */
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
return mContentProvider.applyBatch(operations);

View File

@@ -106,20 +106,6 @@ 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);
@@ -245,32 +231,6 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return super.onTransact(code, data, reply, flags);
}
/**
* @hide
*/
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 reset() throws RemoteException {
mEntityIterator.reset();
}
public void close() throws RemoteException {
mEntityIterator.close();
}
}
public IBinder asBinder()
{
return this;
@@ -352,64 +312,6 @@ final class ContentProviderProxy implements IContentProvider
return adaptor;
}
/**
* @hide
*/
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));
}
/**
* @hide
*/
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 reset() throws RemoteException {
mEntityIterator.reset();
}
public void close() {
try {
mEntityIterator.close();
} catch (RemoteException e) {
// doesn't matter
}
}
}
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();

View File

@@ -215,96 +215,6 @@ public abstract class ContentResolver {
}
}
/**
* EntityIterator wrapper that releases the associated ContentProviderClient when the
* iterator is closed.
* @hide
*/
private class EntityIteratorWrapper implements EntityIterator {
private final EntityIterator mInner;
private final ContentProviderClient mClient;
private volatile boolean mClientReleased;
EntityIteratorWrapper(EntityIterator inner, ContentProviderClient client) {
mInner = inner;
mClient = client;
mClientReleased = false;
}
public boolean hasNext() throws RemoteException {
if (mClientReleased) {
throw new IllegalStateException("this iterator is already closed");
}
return mInner.hasNext();
}
public Entity next() throws RemoteException {
if (mClientReleased) {
throw new IllegalStateException("this iterator is already closed");
}
return mInner.next();
}
public void reset() throws RemoteException {
if (mClientReleased) {
throw new IllegalStateException("this iterator is already closed");
}
mInner.reset();
}
public void close() {
mClient.release();
mInner.close();
mClientReleased = true;
}
protected void finalize() throws Throwable {
if (!mClientReleased) {
mClient.release();
}
super.finalize();
}
}
/**
* Query the given URI, returning an {@link EntityIterator} over the result set.
*
* @param uri The URI, using the content:// scheme, for the content to
* retrieve.
* @param selection A filter declaring which rows to return, formatted as an
* SQL WHERE clause (excluding the WHERE itself). Passing null will
* return all rows for the given URI.
* @param selectionArgs You may include ?s in selection, which will be
* replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
* @param sortOrder How to order the rows, formatted as an SQL ORDER BY
* clause (excluding the ORDER BY itself). Passing null will use the
* default sort order, which may be unordered.
* @return An EntityIterator object
* @throws RemoteException thrown if a RemoteException is encountered while attempting
* to communicate with a remote provider.
* @throws IllegalArgumentException thrown if there is no provider that matches the uri
* @hide
*/
public final EntityIterator queryEntities(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.

View File

@@ -0,0 +1,88 @@
package android.content;
import android.database.Cursor;
import android.os.RemoteException;
/**
* Abstract implementation of EntityIterator that makes it easy to wrap a cursor
* that can contain several consecutive rows for an entity.
* @hide
*/
public abstract class CursorEntityIterator implements EntityIterator {
private final Cursor mCursor;
private boolean mIsClosed;
/**
* Constructor that makes initializes the cursor such that the iterator points to the
* first Entity, if there are any.
* @param cursor the cursor that contains the rows that make up the entities
*/
public CursorEntityIterator(Cursor cursor) {
mIsClosed = false;
mCursor = cursor;
mCursor.moveToFirst();
}
/**
* Returns the entity that the cursor is currently pointing to. This must take care to advance
* the cursor past this entity. This will never be called if the cursor is at the end.
* @param cursor the cursor that contains the entity rows
* @return the entity that the cursor is currently pointing to
* @throws RemoteException if a RemoteException is caught while attempting to build the Entity
*/
public abstract Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException;
/**
* 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
*/
public final boolean hasNext() throws RemoteException {
if (mIsClosed) {
throw new IllegalStateException("calling hasNext() when the iterator is closed");
}
return !mCursor.isAfterLast();
}
/**
* 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
*/
public Entity next() throws RemoteException {
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");
}
return getEntityAndIncrementCursor(mCursor);
}
public final void reset() throws RemoteException {
if (mIsClosed) {
throw new IllegalStateException("calling reset() when the iterator is closed");
}
mCursor.moveToFirst();
}
/**
* Indicates that this iterator is no longer needed and that any associated resources
* may be released (such as a SQLite cursor).
*/
public final void close() {
if (mIsClosed) {
throw new IllegalStateException("closing when already closed");
}
mIsClosed = true;
mCursor.close();
}
}

View File

@@ -1,20 +0,0 @@
/* //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;

View File

@@ -24,11 +24,13 @@ import android.util.Log;
import java.util.ArrayList;
/**
* 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.
* @hide
* A representation of a item using ContentValues. It contains one top level ContentValue
* plus a collection of Uri, ContentValues tuples as subvalues. One example of its use
* is in Contacts, where the top level ContentValue contains the columns from the RawContacts
* table and the subvalues contain a ContentValues object for each row from the Data table that
* corresponds to that RawContact. The uri refers to the Data table uri for each row.
*/
public final class Entity implements Parcelable {
public final class Entity {
final private ContentValues mValues;
final private ArrayList<NamedContentValues> mSubValues;
@@ -49,40 +51,6 @@ public final class Entity implements Parcelable {
mSubValues.add(new Entity.NamedContentValues(uri, values));
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
mValues.writeToParcel(dest, 0);
dest.writeInt(mSubValues.size());
for (NamedContentValues value : mSubValues) {
value.uri.writeToParcel(dest, 0);
value.values.writeToParcel(dest, 0);
}
}
private Entity(Parcel source) {
mValues = ContentValues.CREATOR.createFromParcel(source);
final int numValues = source.readInt();
mSubValues = new ArrayList<NamedContentValues>(numValues);
for (int i = 0; i < numValues; i++) {
final Uri uri = Uri.CREATOR.createFromParcel(source);
final ContentValues values = ContentValues.CREATOR.createFromParcel(source);
mSubValues.add(new NamedContentValues(uri, values));
}
}
public static final Creator<Entity> CREATOR = new Creator<Entity>() {
public Entity createFromParcel(Parcel source) {
return new Entity(source);
}
public Entity[] newArray(int size) {
return new Entity[size];
}
};
public static class NamedContentValues {
public final Uri uri;
public final ContentValues values;

View File

@@ -18,9 +18,6 @@ package android.content;
import android.os.RemoteException;
/**
* @hide
*/
public interface EntityIterator {
/**
* Returns whether there are more elements to iterate, i.e. whether the

View File

@@ -44,12 +44,6 @@ public interface IContentProvider extends IInterface {
CursorWindow window) throws RemoteException;
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException;
/**
* @hide
*/
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;
@@ -76,9 +70,5 @@ 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;
/**
* @hide
*/
static final int QUERY_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 18;
static final int APPLY_BATCH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 19;
}

View File

@@ -1,210 +0,0 @@
/*
* 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.os.Parcelable;
import android.util.Log;
/**
* ICPC interface methods for an iterator over Entity objects.
* @hide
*/
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();
entity.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
return true;
}
case TRANSACTION_reset:
{
data.enforceInterface(DESCRIPTOR);
try {
this.reset();
} catch (RemoteException e) {
Log.e(TAG, "caught exception in next()", e);
reply.writeException(e);
return true;
}
reply.writeNoException();
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();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0);
_reply.readException();
return Entity.CREATOR.createFromParcel(_reply);
} finally {
_reply.recycle();
_data.recycle();
}
}
public void reset() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
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);
static final int TRANSACTION_reset = (IBinder.FIRST_CALL_TRANSACTION + 3);
}
public boolean hasNext() throws RemoteException;
public Entity next() throws RemoteException;
public void reset() throws RemoteException;
public void close() throws RemoteException;
}

View File

@@ -670,6 +670,102 @@ public class DatabaseUtils {
return value;
}
/**
* Reads a String out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorStringToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getString(index));
}
}
/**
* Reads a Long out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorLongToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getLong(index));
}
}
/**
* Reads a Short out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorShortToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getShort(index));
}
}
/**
* Reads a Integer out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorIntToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getInt(index));
}
}
/**
* Reads a Float out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorFloatToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getFloat(index));
}
}
/**
* Reads a Double out of a column in a Cursor and writes it to a ContentValues.
* Adds nothing to the ContentValues if the column isn't present or if its value is null.
*
* @param cursor The cursor to read from
* @param column The column to read
* @param values The {@link ContentValues} to put the value into
*/
public static void cursorDoubleToContentValuesIfPresent(Cursor cursor, ContentValues values,
String column) {
final int index = cursor.getColumnIndexOrThrow(column);
if (!cursor.isNull(index)) {
values.put(column, cursor.getDouble(index));
}
}
/**
* This class allows users to do multiple inserts into a table but
* compile the SQL insert statement only once, which may increase

View File

@@ -139,13 +139,9 @@ public class VCardComposer {
public static final Uri CONTACTS_TEST_CONTENT_URI =
Uri.withAppendedPath(VCARD_TEST_AUTHORITY_URI, "contacts");
private static final Uri sDataRequestUri;
private static final Map<Integer, String> sImMap;
static {
Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon();
builder.appendQueryParameter(Data.FOR_EXPORT_ONLY, "1");
sDataRequestUri = builder.build();
sImMap = new HashMap<Integer, String>();
sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
@@ -482,16 +478,19 @@ public class VCardComposer {
private String createOneEntryInternal(final String contactId) {
final Map<String, List<ContentValues>> contentValuesListMap =
new HashMap<String, List<ContentValues>>();
final String selection = Data.CONTACT_ID + "=?";
final String[] selectionArgs = new String[] {contactId};
// The resolver may return the entity iterator with no data. It is possiible.
// e.g. If all the data in the contact of the given contact id are not exportable ones,
// they are hidden from the view of this method, though contact id itself exists.
boolean dataExists = false;
EntityIterator entityIterator = null;
try {
entityIterator = mContentResolver.queryEntities(
sDataRequestUri, selection, selectionArgs, null);
final Uri uri = RawContacts.CONTENT_URI.buildUpon()
.appendEncodedPath(contactId)
.appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
.appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
.build();
entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
uri, null, null, null, null));
dataExists = entityIterator.hasNext();
while (entityIterator.hasNext()) {
Entity entity = entityIterator.next();

View File

@@ -23,7 +23,12 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.EntityIterator;
import android.content.CursorEntityIterator;
import android.content.Entity;
import android.content.ContentProviderClient;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.pim.ICalendar;
import android.pim.RecurrenceSet;
@@ -33,6 +38,7 @@ import android.text.format.Time;
import android.util.Config;
import android.util.Log;
import android.accounts.Account;
import android.os.RemoteException;
/**
* The Calendar provider contains all calendar events.
@@ -135,12 +141,60 @@ public final class Calendar {
* <p>Type: String (blob)</p>
*/
public static final String SYNC_STATE = "sync_state";
/**
* The account that was used to sync the entry to the device.
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
* The type of the account that was used to sync the entry to the device.
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
/**
* The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ID = "_sync_id";
/**
* The last time, from the sync source's point of view, that this row has been synchronized.
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_TIME = "_sync_time";
/**
* The version of the row, as assigned by the server.
* <P>Type: TEXT</P>
*/
public static final String _SYNC_VERSION = "_sync_version";
/**
* Used in temporary provider while syncing, always NULL for rows in persistent providers.
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_LOCAL_ID = "_sync_local_id";
/**
* Used only in persistent providers, and only during merging.
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_MARK = "_sync_mark";
/**
* Used to indicate that local, unsynced, changes are present.
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_DIRTY = "_sync_dirty";
}
/**
* Contains a list of available calendars.
*/
public static class Calendars implements BaseColumns, SyncConstValue, CalendarsColumns
public static class Calendars implements BaseColumns, CalendarsColumns
{
public static final Cursor query(ContentResolver cr, String[] projection,
String where, String orderBy)
@@ -523,8 +577,182 @@ public final class Calendar {
/**
* Contains one entry per calendar event. Recurring events show up as a single entry.
*/
public static final class Events implements BaseColumns, SyncConstValue,
EventsColumns, CalendarsColumns {
public static final class EventsEntity implements BaseColumns, EventsColumns, CalendarsColumns {
/**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://calendar/event_entities");
public static EntityIterator newEntityIterator(Cursor cursor, ContentResolver resolver) {
return new EntityIteratorImpl(cursor, resolver);
}
public static EntityIterator newEntityIterator(Cursor cursor,
ContentProviderClient provider) {
return new EntityIteratorImpl(cursor, provider);
}
private static class EntityIteratorImpl extends CursorEntityIterator {
private final ContentResolver mResolver;
private final ContentProviderClient mProvider;
private static final String[] REMINDERS_PROJECTION = new String[] {
Reminders.MINUTES,
Reminders.METHOD,
};
private static final int COLUMN_MINUTES = 0;
private static final int COLUMN_METHOD = 1;
private static final String[] ATTENDEES_PROJECTION = new String[] {
Attendees.ATTENDEE_NAME,
Attendees.ATTENDEE_EMAIL,
Attendees.ATTENDEE_RELATIONSHIP,
Attendees.ATTENDEE_TYPE,
Attendees.ATTENDEE_STATUS,
};
private static final int COLUMN_ATTENDEE_NAME = 0;
private static final int COLUMN_ATTENDEE_EMAIL = 1;
private static final int COLUMN_ATTENDEE_RELATIONSHIP = 2;
private static final int COLUMN_ATTENDEE_TYPE = 3;
private static final int COLUMN_ATTENDEE_STATUS = 4;
private static final String[] EXTENDED_PROJECTION = new String[] {
ExtendedProperties.NAME,
ExtendedProperties.VALUE,
};
private static final int COLUMN_NAME = 0;
private static final int COLUMN_VALUE = 1;
public EntityIteratorImpl(Cursor cursor, ContentResolver resolver) {
super(cursor);
mResolver = resolver;
mProvider = null;
}
public EntityIteratorImpl(Cursor cursor, ContentProviderClient provider) {
super(cursor);
mResolver = null;
mProvider = provider;
}
public Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException {
// we expect the cursor is already at the row we need to read from
final long eventId = cursor.getLong(cursor.getColumnIndexOrThrow(Events._ID));
ContentValues cv = new ContentValues();
cv.put(Events._ID, eventId);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, CALENDAR_ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, HTML_URI);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, TITLE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DESCRIPTION);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, EVENT_LOCATION);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, STATUS);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, SELF_ATTENDEE_STATUS);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, COMMENTS_URI);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DTSTART);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DTEND);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DURATION);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, EVENT_TIMEZONE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ALL_DAY);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, VISIBILITY);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, TRANSPARENCY);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, HAS_ALARM);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
HAS_EXTENDED_PROPERTIES);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, RRULE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, RDATE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, EXRULE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, EXDATE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORIGINAL_EVENT);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv,
ORIGINAL_INSTANCE_TIME);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, ORIGINAL_ALL_DAY);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, LAST_DATE);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, HAS_ATTENDEE_DATA);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv,
GUESTS_CAN_INVITE_OTHERS);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, GUESTS_CAN_MODIFY);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, GUESTS_CAN_SEE_GUESTS);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORGANIZER);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, _SYNC_DIRTY);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.URL);
Entity entity = new Entity(cv);
Cursor subCursor;
if (mResolver != null) {
subCursor = mResolver.query(Reminders.CONTENT_URI, REMINDERS_PROJECTION,
"event_id=" + eventId, null, null);
} else {
subCursor = mProvider.query(Reminders.CONTENT_URI, REMINDERS_PROJECTION,
"event_id=" + eventId, null, null);
}
try {
while (subCursor.moveToNext()) {
ContentValues reminderValues = new ContentValues();
reminderValues.put(Reminders.MINUTES, subCursor.getInt(COLUMN_MINUTES));
reminderValues.put(Reminders.METHOD, subCursor.getInt(COLUMN_METHOD));
entity.addSubValue(Reminders.CONTENT_URI, reminderValues);
}
} finally {
subCursor.close();
}
if (mResolver != null) {
subCursor = mResolver.query(Attendees.CONTENT_URI, ATTENDEES_PROJECTION,
"event_id=" + eventId, null /* selectionArgs */, null /* sortOrder */);
} else {
subCursor = mProvider.query(Attendees.CONTENT_URI, ATTENDEES_PROJECTION,
"event_id=" + eventId, null /* selectionArgs */, null /* sortOrder */);
}
try {
while (subCursor.moveToNext()) {
ContentValues attendeeValues = new ContentValues();
attendeeValues.put(Attendees.ATTENDEE_NAME,
subCursor.getString(COLUMN_ATTENDEE_NAME));
attendeeValues.put(Attendees.ATTENDEE_EMAIL,
subCursor.getString(COLUMN_ATTENDEE_EMAIL));
attendeeValues.put(Attendees.ATTENDEE_RELATIONSHIP,
subCursor.getInt(COLUMN_ATTENDEE_RELATIONSHIP));
attendeeValues.put(Attendees.ATTENDEE_TYPE,
subCursor.getInt(COLUMN_ATTENDEE_TYPE));
attendeeValues.put(Attendees.ATTENDEE_STATUS,
subCursor.getInt(COLUMN_ATTENDEE_STATUS));
entity.addSubValue(Attendees.CONTENT_URI, attendeeValues);
}
} finally {
subCursor.close();
}
if (mResolver != null) {
subCursor = mResolver.query(ExtendedProperties.CONTENT_URI, EXTENDED_PROJECTION,
"event_id=" + eventId, null /* selectionArgs */, null /* sortOrder */);
} else {
subCursor = mProvider.query(ExtendedProperties.CONTENT_URI, EXTENDED_PROJECTION,
"event_id=" + eventId, null /* selectionArgs */, null /* sortOrder */);
}
try {
while (subCursor.moveToNext()) {
ContentValues extendedValues = new ContentValues();
extendedValues.put(ExtendedProperties.NAME, cursor.getString(COLUMN_NAME));
extendedValues.put(ExtendedProperties.VALUE,
cursor.getString(COLUMN_VALUE));
entity.addSubValue(ExtendedProperties.CONTENT_URI, extendedValues);
}
} finally {
subCursor.close();
}
cursor.moveToNext();
return entity;
}
}
}
/**
* Contains one entry per calendar event. Recurring events show up as a single entry.
*/
public static final class Events implements BaseColumns, EventsColumns, CalendarsColumns {
private static final String[] FETCH_ENTRY_COLUMNS =
new String[] { Events._SYNC_ACCOUNT, Events._SYNC_ID };

View File

@@ -24,12 +24,15 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.CursorEntityIterator;
import android.content.EntityIterator;
import android.content.Entity;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Rect;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;
@@ -984,7 +987,7 @@ public final class ContactsContract {
* removes the raw contact from its aggregate contact.
* The sync adapter then deletes the raw contact from the server and
* finalizes phone-side deletion by calling {@code resolver.delete(...)}
* again and passing the {@link #CALLER_IS_SYNCADAPTER} query parameter.<p>
* again and passing the {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter.<p>
* <p>Some sync adapters are read-only, meaning that they only sync server-side
* changes to the phone, but not the reverse. If one of those raw contacts
* is marked for deletion, it will remain on the phone. However it will be
@@ -1366,6 +1369,107 @@ public final class ContactsContract {
*/
public static final String DATA_ID = "data_id";
}
public static EntityIterator newEntityIterator(Cursor cursor) {
return new EntityIteratorImpl(cursor);
}
private static class EntityIteratorImpl extends CursorEntityIterator {
private static final String[] DATA_KEYS = new String[]{
Data.DATA1,
Data.DATA2,
Data.DATA3,
Data.DATA4,
Data.DATA5,
Data.DATA6,
Data.DATA7,
Data.DATA8,
Data.DATA9,
Data.DATA10,
Data.DATA11,
Data.DATA12,
Data.DATA13,
Data.DATA14,
Data.DATA15,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
Data.SYNC4};
public EntityIteratorImpl(Cursor cursor) {
super(cursor);
}
public android.content.Entity getEntityAndIncrementCursor(Cursor cursor)
throws RemoteException {
final int columnRawContactId = cursor.getColumnIndexOrThrow(RawContacts._ID);
final long rawContactId = cursor.getLong(columnRawContactId);
// we expect the cursor is already at the row we need to read from
ContentValues cv = new ContentValues();
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_NAME);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_TYPE);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, _ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, VERSION);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SOURCE_ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC1);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC2);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC3);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC4);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, IS_RESTRICTED);
android.content.Entity contact = new android.content.Entity(cv);
// read data rows until the contact id changes
do {
if (rawContactId != cursor.getLong(columnRawContactId)) {
break;
}
// add the data to to the contact
cv = new ContentValues();
cv.put(Data._ID, cursor.getLong(cursor.getColumnIndexOrThrow(Entity.DATA_ID)));
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
Data.RES_PACKAGE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Data.MIMETYPE);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.IS_PRIMARY);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv,
Data.IS_SUPER_PRIMARY);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.DATA_VERSION);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
CommonDataKinds.GroupMembership.GROUP_SOURCE_ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
Data.DATA_VERSION);
for (String key : DATA_KEYS) {
final int columnIndex = cursor.getColumnIndexOrThrow(key);
if (cursor.isNull(columnIndex)) {
// don't put anything
} else {
cv.put(key, cursor.getString(columnIndex));
}
// TODO: go back to this version of the code when bug
// http://b/issue?id=2306370 is fixed.
// if (cursor.isNull(columnIndex)) {
// // don't put anything
// } else if (cursor.isLong(columnIndex)) {
// values.put(key, cursor.getLong(columnIndex));
// } else if (cursor.isFloat(columnIndex)) {
// values.put(key, cursor.getFloat(columnIndex));
// } else if (cursor.isString(columnIndex)) {
// values.put(key, cursor.getString(columnIndex));
// } else if (cursor.isBlob(columnIndex)) {
// values.put(key, cursor.getBlob(columnIndex));
// }
}
contact.addSubValue(ContactsContract.Data.CONTENT_URI, cv);
} while (cursor.moveToNext());
return contact;
}
}
}
/**
@@ -4326,6 +4430,41 @@ public final class ContactsContract {
* The MIME type of a single group.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
public static EntityIterator newEntityIterator(Cursor cursor) {
return new EntityIteratorImpl(cursor);
}
private static class EntityIteratorImpl extends CursorEntityIterator {
public EntityIteratorImpl(Cursor cursor) {
super(cursor);
}
public Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException {
// we expect the cursor is already at the row we need to read from
final ContentValues values = new ContentValues();
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, _ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_NAME);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_TYPE);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DIRTY);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, VERSION);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SOURCE_ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, RES_PACKAGE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE_RES);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, GROUP_VISIBLE);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC1);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC2);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC3);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC4);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYSTEM_ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, NOTES);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SHOULD_SYNC);
cursor.moveToNext();
return new Entity(values);
}
}
}
/**

View File

@@ -136,7 +136,6 @@ android.content.ContentProvider
android.content.ContentProvider$Transport
android.content.ContentProviderClient
android.content.ContentProviderNative
android.content.ContentProviderNative$IEntityIteratorImpl
android.content.ContentProviderOperation
android.content.ContentProviderProxy
android.content.ContentProviderResult
@@ -151,7 +150,6 @@ android.content.Entity
android.content.IContentProvider
android.content.IContentService$Stub
android.content.IContentService$Stub$Proxy
android.content.IEntityIterator$Stub
android.content.IIntentReceiver$Stub
android.content.IIntentSender$Stub
android.content.ISyncAdapter$Stub

View File

@@ -110,21 +110,6 @@ import java.util.List;
return contactEntry;
}
@Override
public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
String sortOrder) {
mTestCase.assertTrue(uri != null);
mTestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
final String authority = uri.getAuthority();
mTestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
mTestCase.assertTrue((Data.CONTACT_ID + "=?").equals(selection));
mTestCase.assertEquals(1, selectionArgs.length);
int id = Integer.parseInt(selectionArgs[0]);
mTestCase.assertTrue(id >= 0 && id < mContactEntryList.size());
return new MockEntityIterator(mContactEntryList.get(id).getList());
}
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {

View File

@@ -96,15 +96,6 @@ class MockContentProvider extends ContentProvider {
throw new UnsupportedOperationException("unimplemented mock method");
}
/**
* @hide
*/
@Override
public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
String sortOrder) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("unimplemented mock method");