- 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:
283
api/current.xml
283
api/current.xml
@@ -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<android.content.Entity.NamedContentValues>"
|
||||
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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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>.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
88
core/java/android/content/CursorEntityIterator.java
Normal file
88
core/java/android/content/CursorEntityIterator.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user