Merge change 2723
* changes: - create a new generic ISyncAdapter implementation, SyncAdapterNew - change the applyBatch to take an ArrayList rather than an [] - change Entity to be a final flass that contains ContentValues - remove the ability to update/insert Entities by a ContentProviderOperation
This commit is contained in:
300
api/current.xml
300
api/current.xml
@@ -1145,6 +1145,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="WRITE_EXTERNAL_STORAGE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.permission.WRITE_EXTERNAL_STORAGE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="WRITE_GSERVICES"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -1167,17 +1178,6 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="WRITE_EXTERNAL_STORAGE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.permission.WRITE_EXTERNAL_STORAGE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="WRITE_SECURE_SETTINGS"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -28029,7 +28029,7 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="operations" type="android.content.ContentProviderOperation[]">
|
||||
<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
|
||||
</parameter>
|
||||
<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
|
||||
</exception>
|
||||
@@ -28373,7 +28373,7 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="operations" type="android.content.ContentProviderOperation[]">
|
||||
<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
|
||||
</parameter>
|
||||
<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
|
||||
</exception>
|
||||
@@ -28808,19 +28808,6 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="withEntity"
|
||||
return="android.content.ContentProviderOperation.Builder"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="entity" type="android.content.Entity">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="withExpectedCount"
|
||||
return="android.content.ContentProviderOperation.Builder"
|
||||
abstract="false"
|
||||
@@ -28849,7 +28836,7 @@
|
||||
<parameter name="selectionArgs" type="java.lang.String[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="withSelectionBackReferences"
|
||||
<method name="withSelectionBackReference"
|
||||
return="android.content.ContentProviderOperation.Builder"
|
||||
abstract="false"
|
||||
native="false"
|
||||
@@ -28859,7 +28846,24 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="backReferences" type="java.util.Map<java.lang.Integer, java.lang.Integer>">
|
||||
<parameter name="selectionArgIndex" type="int">
|
||||
</parameter>
|
||||
<parameter name="previousResult" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="withValueBackReference"
|
||||
return="android.content.ContentProviderOperation.Builder"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="key" type="java.lang.String">
|
||||
</parameter>
|
||||
<parameter name="previousResult" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="withValueBackReferences"
|
||||
@@ -29126,7 +29130,7 @@
|
||||
>
|
||||
<parameter name="authority" type="java.lang.String">
|
||||
</parameter>
|
||||
<parameter name="operations" type="android.content.ContentProviderOperation[]">
|
||||
<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
|
||||
</parameter>
|
||||
<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
|
||||
</exception>
|
||||
@@ -29206,23 +29210,6 @@
|
||||
<parameter name="values" type="android.content.ContentValues">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="insertEntity"
|
||||
return="android.net.Uri"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="uri" type="android.net.Uri">
|
||||
</parameter>
|
||||
<parameter name="entity" type="android.content.Entity">
|
||||
</parameter>
|
||||
<exception name="RemoteException" type="android.os.RemoteException">
|
||||
</exception>
|
||||
</method>
|
||||
<method name="notifyChange"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -29442,23 +29429,6 @@
|
||||
<parameter name="selectionArgs" type="java.lang.String[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="updateEntity"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="uri" type="android.net.Uri">
|
||||
</parameter>
|
||||
<parameter name="entity" type="android.content.Entity">
|
||||
</parameter>
|
||||
<exception name="RemoteException" type="android.os.RemoteException">
|
||||
</exception>
|
||||
</method>
|
||||
<method name="validateSyncExtrasBundle"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -32623,9 +32593,9 @@
|
||||
</interface>
|
||||
<class name="Entity"
|
||||
extends="java.lang.Object"
|
||||
abstract="true"
|
||||
abstract="false"
|
||||
static="false"
|
||||
final="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
@@ -32638,7 +32608,123 @@
|
||||
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="describeContents"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</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>
|
||||
<method name="writeToParcel"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="dest" type="android.os.Parcel">
|
||||
</parameter>
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<field name="CREATOR"
|
||||
type="android.os.Parcelable.Creator"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</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"
|
||||
@@ -44377,6 +44463,32 @@
|
||||
<parameter name="columnIndex" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isFloat"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="columnIndex" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isLong"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="columnIndex" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isNull"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -44390,6 +44502,19 @@
|
||||
<parameter name="columnIndex" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isString"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="columnIndex" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setWindow"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -45470,6 +45595,36 @@
|
||||
<parameter name="col" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isFloat"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="row" type="int">
|
||||
</parameter>
|
||||
<parameter name="col" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isLong"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="row" type="int">
|
||||
</parameter>
|
||||
<parameter name="col" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isNull"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -45485,6 +45640,21 @@
|
||||
<parameter name="col" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isString"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="row" type="int">
|
||||
</parameter>
|
||||
<parameter name="col" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="newFromParcel"
|
||||
return="android.database.CursorWindow"
|
||||
abstract="false"
|
||||
|
||||
@@ -406,7 +406,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @hide This method should be used only when {@link #applyBatch} is not enough and must be
|
||||
* @hide This method should be used only when {@link ContentProvider#applyBatch} is not enough and must be
|
||||
* used with {@link #endBatch}.
|
||||
* e.g. If returned value has to be used during one transaction, this method might be useful.
|
||||
*/
|
||||
@@ -461,7 +461,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
|
||||
}
|
||||
}
|
||||
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws OperationApplicationException {
|
||||
boolean successful = false;
|
||||
beginBatch();
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Content providers are one of the primary building blocks of Android applications, providing
|
||||
@@ -156,7 +157,7 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
return ContentProvider.this.insertEntity(uri, entities);
|
||||
}
|
||||
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws OperationApplicationException {
|
||||
for (ContentProviderOperation operation : operations) {
|
||||
if (operation.isReadOperation()) {
|
||||
@@ -641,11 +642,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
* @throws OperationApplicationException thrown if an application fails.
|
||||
* See {@link ContentProviderOperation#apply} for more information.
|
||||
*/
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws OperationApplicationException {
|
||||
ContentProviderResult[] results = new ContentProviderResult[operations.length];
|
||||
for (int i = 0; i < operations.length; i++) {
|
||||
results[i] = operations[i].apply(this, results, i);
|
||||
final int numOperations = operations.size();
|
||||
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
|
||||
for (int i = 0; i < numOperations; i++) {
|
||||
results[i] = operations.get(i).apply(this, results, i);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The public interface object used to interact with a {@link ContentProvider}. This is obtained by
|
||||
@@ -105,7 +106,7 @@ public class ContentProviderClient {
|
||||
}
|
||||
|
||||
/** see {@link ContentProvider#applyBatch} */
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws RemoteException, OperationApplicationException {
|
||||
return mContentProvider.applyBatch(operations);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@@ -179,8 +180,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
|
||||
case APPLY_BATCH_TRANSACTION:
|
||||
{
|
||||
data.enforceInterface(IContentProvider.descriptor);
|
||||
final ContentProviderOperation[] operations =
|
||||
data.createTypedArray(ContentProviderOperation.CREATOR);
|
||||
final int numOperations = data.readInt();
|
||||
final ArrayList<ContentProviderOperation> operations =
|
||||
new ArrayList<ContentProviderOperation>(numOperations);
|
||||
for (int i = 0; i < numOperations; i++) {
|
||||
operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
|
||||
}
|
||||
final ContentProviderResult[] results = applyBatch(operations);
|
||||
reply.writeNoException();
|
||||
reply.writeTypedArray(results, 0);
|
||||
@@ -471,13 +476,16 @@ final class ContentProviderProxy implements IContentProvider
|
||||
return count;
|
||||
}
|
||||
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws RemoteException, OperationApplicationException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
|
||||
data.writeInterfaceToken(IContentProvider.descriptor);
|
||||
data.writeTypedArray(operations, 0);
|
||||
data.writeInt(operations.size());
|
||||
for (ContentProviderOperation operation : operations) {
|
||||
operation.writeToParcel(data, 0);
|
||||
}
|
||||
mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
|
||||
|
||||
DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
|
||||
|
||||
@@ -24,8 +24,6 @@ import android.os.Parcel;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
import dalvik.system.VMStack;
|
||||
|
||||
public class ContentProviderOperation implements Parcelable {
|
||||
private final static int TYPE_INSERT = 1;
|
||||
private final static int TYPE_UPDATE = 2;
|
||||
@@ -37,7 +35,6 @@ public class ContentProviderOperation implements Parcelable {
|
||||
private final String mSelection;
|
||||
private final String[] mSelectionArgs;
|
||||
private final ContentValues mValues;
|
||||
private final Entity mEntity;
|
||||
private final Integer mExpectedCount;
|
||||
private final ContentValues mValuesBackReferences;
|
||||
private final Map<Integer, Integer> mSelectionArgsBackReferences;
|
||||
@@ -52,7 +49,6 @@ public class ContentProviderOperation implements Parcelable {
|
||||
mType = builder.mType;
|
||||
mUri = builder.mUri;
|
||||
mValues = builder.mValues;
|
||||
mEntity = builder.mEntity;
|
||||
mSelection = builder.mSelection;
|
||||
mSelectionArgs = builder.mSelectionArgs;
|
||||
mExpectedCount = builder.mExpectedCount;
|
||||
@@ -60,11 +56,10 @@ public class ContentProviderOperation implements Parcelable {
|
||||
mValuesBackReferences = builder.mValuesBackReferences;
|
||||
}
|
||||
|
||||
private ContentProviderOperation(Parcel source, ClassLoader classLoader) {
|
||||
private ContentProviderOperation(Parcel source) {
|
||||
mType = source.readInt();
|
||||
mUri = Uri.CREATOR.createFromParcel(source);
|
||||
mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
|
||||
mEntity = (Entity) source.readParcelable(classLoader);
|
||||
mSelection = source.readInt() != 0 ? source.readString() : null;
|
||||
mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
|
||||
mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
|
||||
@@ -92,7 +87,6 @@ public class ContentProviderOperation implements Parcelable {
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
dest.writeParcelable(mEntity, 0);
|
||||
if (mSelection != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeString(mSelection);
|
||||
@@ -184,7 +178,7 @@ public class ContentProviderOperation implements Parcelable {
|
||||
* Applies this operation using the given provider. The backRefs array is used to resolve any
|
||||
* back references that were requested using
|
||||
* {@link Builder#withValueBackReferences(ContentValues)} and
|
||||
* {@link Builder#withSelectionBackReferences(java.util.Map)}.
|
||||
* {@link Builder#withSelectionBackReference}.
|
||||
* @param provider the {@link ContentProvider} on which this batch is applied
|
||||
* @param backRefs a {@link ContentProviderResult} array that will be consulted
|
||||
* to resolve any requested back references.
|
||||
@@ -201,12 +195,7 @@ public class ContentProviderOperation implements Parcelable {
|
||||
resolveSelectionArgsBackReferences(backRefs, numBackRefs);
|
||||
|
||||
if (mType == TYPE_INSERT) {
|
||||
Uri newUri;
|
||||
if (mEntity != null) {
|
||||
newUri = provider.insertEntity(mUri, mEntity);
|
||||
} else {
|
||||
newUri = provider.insert(mUri, values);
|
||||
}
|
||||
Uri newUri = provider.insert(mUri, values);
|
||||
if (newUri == null) {
|
||||
throw new OperationApplicationException("insert failed");
|
||||
}
|
||||
@@ -217,11 +206,7 @@ public class ContentProviderOperation implements Parcelable {
|
||||
if (mType == TYPE_DELETE) {
|
||||
numRows = provider.delete(mUri, mSelection, selectionArgs);
|
||||
} else if (mType == TYPE_UPDATE) {
|
||||
if (mEntity != null) {
|
||||
numRows = provider.updateEntity(mUri, mEntity);
|
||||
} else {
|
||||
numRows = provider.update(mUri, values, mSelection, selectionArgs);
|
||||
}
|
||||
numRows = provider.update(mUri, values, mSelection, selectionArgs);
|
||||
} else if (mType == TYPE_COUNT) {
|
||||
Cursor cursor = provider.query(mUri, COUNT_COLUMNS, mSelection, selectionArgs, null);
|
||||
try {
|
||||
@@ -322,7 +307,7 @@ public class ContentProviderOperation implements Parcelable {
|
||||
*/
|
||||
private static String backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
|
||||
Integer backRefIndex) {
|
||||
if (backRefIndex > numBackRefs) {
|
||||
if (backRefIndex >= numBackRefs) {
|
||||
throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
|
||||
+ " but there are only " + numBackRefs + " back refs");
|
||||
}
|
||||
@@ -343,7 +328,7 @@ public class ContentProviderOperation implements Parcelable {
|
||||
public static final Creator<ContentProviderOperation> CREATOR =
|
||||
new Creator<ContentProviderOperation>() {
|
||||
public ContentProviderOperation createFromParcel(Parcel source) {
|
||||
return new ContentProviderOperation(source, VMStack.getCallingClassLoader2());
|
||||
return new ContentProviderOperation(source);
|
||||
}
|
||||
|
||||
public ContentProviderOperation[] newArray(int size) {
|
||||
@@ -368,7 +353,6 @@ public class ContentProviderOperation implements Parcelable {
|
||||
private String mSelection;
|
||||
private String[] mSelectionArgs;
|
||||
private ContentValues mValues;
|
||||
private Entity mEntity;
|
||||
private Integer mExpectedCount;
|
||||
private ContentValues mValuesBackReferences;
|
||||
private Map<Integer, Integer> mSelectionArgsBackReferences;
|
||||
@@ -384,14 +368,6 @@ public class ContentProviderOperation implements Parcelable {
|
||||
|
||||
/** Create a ContentProviderOperation from this {@link Builder}. */
|
||||
public ContentProviderOperation build() {
|
||||
if (mValues != null && mEntity != null) {
|
||||
throw new IllegalArgumentException("you are not allowed to specify both an entity "
|
||||
+ "and a values");
|
||||
}
|
||||
if (mEntity != null && mValuesBackReferences != null) {
|
||||
throw new IllegalArgumentException("you are not allowed to specify both an entity "
|
||||
+ "and a values backreference");
|
||||
}
|
||||
return new ContentProviderOperation(this);
|
||||
}
|
||||
|
||||
@@ -414,19 +390,39 @@ public class ContentProviderOperation implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link Map} of back references. The integer key is the index of the selection arg
|
||||
* to set and the integer value is the index of the previous result whose
|
||||
* value should be used for the arg. If any value at that index of the selection arg
|
||||
* Add a ContentValues back reference.
|
||||
* A column value from the back references takes precedence over a value specified in
|
||||
* {@link #withValues}.
|
||||
* This can only be used with builders of type insert or update.
|
||||
* @return this builder, to allow for chaining.
|
||||
*/
|
||||
public Builder withValueBackReference(String key, int previousResult) {
|
||||
if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
|
||||
throw new IllegalArgumentException(
|
||||
"only inserts and updates can have value back-references");
|
||||
}
|
||||
if (mValuesBackReferences == null) {
|
||||
mValuesBackReferences = new ContentValues();
|
||||
}
|
||||
mValuesBackReferences.put(key, previousResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a back references as a selection arg. Any value at that index of the selection arg
|
||||
* that was specified by {@link #withSelection} will be overwritten.
|
||||
* This can only be used with builders of type update, delete, or count query.
|
||||
* @return this builder, to allow for chaining.
|
||||
*/
|
||||
public Builder withSelectionBackReferences(Map<Integer, Integer> backReferences) {
|
||||
public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
|
||||
if (mType != TYPE_COUNT && mType != TYPE_UPDATE && mType != TYPE_DELETE) {
|
||||
throw new IllegalArgumentException(
|
||||
"only deletes, updates and counts can have selection back-references");
|
||||
}
|
||||
mSelectionArgsBackReferences = backReferences;
|
||||
if (mSelectionArgsBackReferences == null) {
|
||||
mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
|
||||
}
|
||||
mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -444,25 +440,11 @@ public class ContentProviderOperation implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ContentValues to use. This may be null. These values may be overwritten by
|
||||
* the corresponding value specified by {@link #withValueBackReferences(ContentValues)}.
|
||||
* This can only be used with builders of type insert or update.
|
||||
* @return this builder, to allow for chaining.
|
||||
*/
|
||||
public Builder withEntity(Entity entity) {
|
||||
if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
|
||||
throw new IllegalArgumentException("only inserts and updates can have an entity");
|
||||
}
|
||||
mEntity = entity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The selection and arguments to use. An occurrence of '?' in the selection will be
|
||||
* replaced with the corresponding occurence of the selection argument. Any of the
|
||||
* selection arguments may be overwritten by a selection argument back reference as
|
||||
* specified by {@link #withSelectionBackReferences}.
|
||||
* specified by {@link #withSelectionBackReference}.
|
||||
* This can only be used with builders of type update, delete, or count query.
|
||||
* @return this builder, to allow for chaining.
|
||||
*/
|
||||
|
||||
@@ -74,4 +74,11 @@ public class ContentProviderResult implements Parcelable {
|
||||
return new ContentProviderResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
public String toString() {
|
||||
if (uri != null) {
|
||||
return "ContentProviderResult(uri=" + uri.toString() + ")";
|
||||
}
|
||||
return "ContentProviderResult(count=" + count + ")";
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
@@ -566,50 +567,6 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an Entity at the given URL.
|
||||
*
|
||||
* @param uri The URL of the table to insert into.
|
||||
* @param entity an Entity to insert at uri. This must be the same Entity subtype that the
|
||||
* matching content provider expects at that uri.
|
||||
* @return the URL of the newly created row.
|
||||
* @throws RemoteException thrown if a RemoteException is encountered while attempting
|
||||
* to communicate with a remote provider.
|
||||
*/
|
||||
public final Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
|
||||
ContentProviderClient provider = acquireContentProviderClient(uri);
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Unknown URL " + uri);
|
||||
}
|
||||
try {
|
||||
return provider.insertEntity(uri, entity);
|
||||
} finally {
|
||||
provider.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the Entity at the given URL with the provided entity.
|
||||
*
|
||||
* @param uri The URL of the entity to update.
|
||||
* @param entity the new version of the entity
|
||||
* @return the number of rows that are updated. Will be 0 if an entity no longer exists
|
||||
* at uri otherwise it will be 1.
|
||||
* @throws RemoteException thrown if a RemoteException is encountered while attempting
|
||||
* to communicate with a remote provider.
|
||||
*/
|
||||
public final int updateEntity(Uri uri, Entity entity) throws RemoteException {
|
||||
ContentProviderClient provider = acquireContentProviderClient(uri);
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Unknown URL " + uri);
|
||||
}
|
||||
try {
|
||||
return provider.updateEntity(uri, entity);
|
||||
} finally {
|
||||
provider.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies each of the {@link ContentProviderOperation} objects and returns an array
|
||||
* of their results. Passes through OperationApplicationException, which may be thrown
|
||||
@@ -627,7 +584,7 @@ public abstract class ContentResolver {
|
||||
* to communicate with a remote provider.
|
||||
*/
|
||||
public ContentProviderResult[] applyBatch(String authority,
|
||||
ContentProviderOperation[] operations)
|
||||
ArrayList<ContentProviderOperation> operations)
|
||||
throws RemoteException, OperationApplicationException {
|
||||
ContentProviderClient provider = acquireContentProviderClient(authority);
|
||||
if (provider == null) {
|
||||
|
||||
@@ -17,10 +17,88 @@
|
||||
package android.content;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.net.Uri;
|
||||
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.
|
||||
*/
|
||||
public abstract class Entity implements Parcelable {
|
||||
public final class Entity implements Parcelable {
|
||||
final private ContentValues mValues;
|
||||
final private ArrayList<NamedContentValues> mSubValues;
|
||||
|
||||
public Entity(ContentValues values) {
|
||||
mValues = values;
|
||||
mSubValues = new ArrayList<NamedContentValues>();
|
||||
}
|
||||
|
||||
public ContentValues getEntityValues() {
|
||||
return mValues;
|
||||
}
|
||||
|
||||
public ArrayList<NamedContentValues> getSubValues() {
|
||||
return mSubValues;
|
||||
}
|
||||
|
||||
public void addSubValue(Uri uri, ContentValues values) {
|
||||
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;
|
||||
|
||||
public NamedContentValues(Uri uri, ContentValues values) {
|
||||
this.uri = uri;
|
||||
this.values = values;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Entity: ").append(getEntityValues());
|
||||
for (Entity.NamedContentValues namedValue : getSubValues()) {
|
||||
sb.append("\n ").append(namedValue.uri);
|
||||
sb.append("\n -> ").append(namedValue.values);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package android.content;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
public interface EntityIterator {
|
||||
public interface EntityIterator {
|
||||
/**
|
||||
* Returns whether there are more elements to iterate, i.e. whether the
|
||||
* iterator is positioned in front of an element.
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.os.IInterface;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The ipc interface to talk to a content provider.
|
||||
@@ -60,7 +61,7 @@ public interface IContentProvider extends IInterface {
|
||||
throws RemoteException, FileNotFoundException;
|
||||
public AssetFileDescriptor openAssetFile(Uri url, String mode)
|
||||
throws RemoteException, FileNotFoundException;
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations)
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws RemoteException, OperationApplicationException;
|
||||
|
||||
/* IPC constants */
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -93,7 +94,7 @@ public interface IEntityIterator extends IInterface {
|
||||
return true;
|
||||
}
|
||||
reply.writeNoException();
|
||||
reply.writeParcelable(entity, 0);
|
||||
entity.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -149,7 +150,7 @@ public interface IEntityIterator extends IInterface {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
return (Entity) _reply.readParcelable(null /* classLoader */);
|
||||
return Entity.CREATOR.createFromParcel(_reply);
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
|
||||
135
core/java/android/content/SyncAdapterNew.java
Normal file
135
core/java/android/content/SyncAdapterNew.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.*;
|
||||
import android.os.Process;
|
||||
import android.accounts.Account;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class SyncAdapterNew {
|
||||
private static final String TAG = "SyncAdapter";
|
||||
private final Context mContext;
|
||||
private final String mAuthority;
|
||||
|
||||
/** Kernel event log tag. Also listed in data/etc/event-log-tags. */
|
||||
public static final int LOG_SYNC_DETAILS = 2743;
|
||||
|
||||
public SyncAdapterNew(Context context, String authority) {
|
||||
mContext = context;
|
||||
mAuthority = authority;
|
||||
}
|
||||
|
||||
class Transport extends ISyncAdapter.Stub {
|
||||
private final AtomicInteger mNumSyncStarts = new AtomicInteger(0);
|
||||
private volatile Thread mSyncThread;
|
||||
|
||||
public void startSync(ISyncContext syncContext, Account account, Bundle extras) {
|
||||
boolean alreadyInProgress;
|
||||
synchronized (this) {
|
||||
if (mSyncThread == null) {
|
||||
mSyncThread = new Thread(
|
||||
new SyncRunnable(new SyncContext(syncContext), account, extras),
|
||||
"SyncAdapterThread-" + mNumSyncStarts.incrementAndGet());
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
mSyncThread.start();
|
||||
alreadyInProgress = false;
|
||||
} else {
|
||||
alreadyInProgress = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyInProgress) {
|
||||
try {
|
||||
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
|
||||
} catch (RemoteException e) {
|
||||
// don't care if the caller is no longer around
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelSync() {
|
||||
synchronized (this) {
|
||||
if (mSyncThread != null) {
|
||||
mSyncThread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncRunnable implements Runnable {
|
||||
private final SyncContext mSyncContext;
|
||||
private final Account mAccount;
|
||||
private final Bundle mExtras;
|
||||
|
||||
private SyncRunnable(SyncContext syncContext, Account account, Bundle extras) {
|
||||
mSyncContext = syncContext;
|
||||
mAccount = account;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SyncResult syncResult = new SyncResult();
|
||||
ContentProviderClient provider = mAuthority != null
|
||||
? mContext.getContentResolver().acquireContentProviderClient(mAuthority)
|
||||
: null;
|
||||
try {
|
||||
SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult);
|
||||
} finally {
|
||||
if (provider != null) {
|
||||
provider.release();
|
||||
}
|
||||
if (!isCanceled()) {
|
||||
mSyncContext.onFinished(syncResult);
|
||||
}
|
||||
mSyncThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCanceled() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Transport mTransport = new Transport();
|
||||
|
||||
/**
|
||||
* Get the Transport object.
|
||||
*/
|
||||
public final ISyncAdapter getISyncAdapter() {
|
||||
return mTransport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a sync for this account. SyncAdapter-specific parameters may
|
||||
* be specified in extras, which is guaranteed to not be null. Invocations
|
||||
* of this method are guaranteed to be serialized.
|
||||
*
|
||||
* @param account the account that should be synced
|
||||
* @param extras SyncAdapter-specific parameters
|
||||
*/
|
||||
public abstract void performSync(Account account, Bundle extras,
|
||||
ContentProviderClient provider, SyncResult syncResult);
|
||||
}
|
||||
@@ -166,6 +166,48 @@ public abstract class AbstractWindowedCursor extends AbstractCursor
|
||||
return mWindow.isBlob(mPos, columnIndex);
|
||||
}
|
||||
|
||||
public boolean isString(int columnIndex)
|
||||
{
|
||||
checkPosition();
|
||||
|
||||
synchronized(mUpdatedRows) {
|
||||
if (isFieldUpdated(columnIndex)) {
|
||||
Object object = getUpdatedField(columnIndex);
|
||||
return object == null || object instanceof String;
|
||||
}
|
||||
}
|
||||
|
||||
return mWindow.isString(mPos, columnIndex);
|
||||
}
|
||||
|
||||
public boolean isLong(int columnIndex)
|
||||
{
|
||||
checkPosition();
|
||||
|
||||
synchronized(mUpdatedRows) {
|
||||
if (isFieldUpdated(columnIndex)) {
|
||||
Object object = getUpdatedField(columnIndex);
|
||||
return object != null && (object instanceof Integer || object instanceof Long);
|
||||
}
|
||||
}
|
||||
|
||||
return mWindow.isLong(mPos, columnIndex);
|
||||
}
|
||||
|
||||
public boolean isFloat(int columnIndex)
|
||||
{
|
||||
checkPosition();
|
||||
|
||||
synchronized(mUpdatedRows) {
|
||||
if (isFieldUpdated(columnIndex)) {
|
||||
Object object = getUpdatedField(columnIndex);
|
||||
return object != null && (object instanceof Float || object instanceof Double);
|
||||
}
|
||||
}
|
||||
|
||||
return mWindow.isFloat(mPos, columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkPosition()
|
||||
{
|
||||
|
||||
@@ -263,7 +263,58 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a field contains a long
|
||||
*
|
||||
* @param row the row to read from, row - getStartPosition() being the actual row in the window
|
||||
* @param col the column to read from
|
||||
* @return {@code true} if given field is a long
|
||||
*/
|
||||
public boolean isLong(int row, int col) {
|
||||
acquireReference();
|
||||
try {
|
||||
return isInteger_native(row - mStartPos, col);
|
||||
} finally {
|
||||
releaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a field contains a float.
|
||||
*
|
||||
* @param row the row to read from, row - getStartPosition() being the actual row in the window
|
||||
* @param col the column to read from
|
||||
* @return {@code true} if given field is a float
|
||||
*/
|
||||
public boolean isFloat(int row, int col) {
|
||||
acquireReference();
|
||||
try {
|
||||
return isFloat_native(row - mStartPos, col);
|
||||
} finally {
|
||||
releaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a field contains either a String or is null.
|
||||
*
|
||||
* @param row the row to read from, row - getStartPosition() being the actual row in the window
|
||||
* @param col the column to read from
|
||||
* @return {@code true} if given field is {@code NULL} or a String
|
||||
*/
|
||||
public boolean isString(int row, int col) {
|
||||
acquireReference();
|
||||
try {
|
||||
return isString_native(row - mStartPos, col);
|
||||
} finally {
|
||||
releaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
private native boolean isBlob_native(int row, int col);
|
||||
private native boolean isString_native(int row, int col);
|
||||
private native boolean isInteger_native(int row, int col);
|
||||
private native boolean isFloat_native(int row, int col);
|
||||
|
||||
/**
|
||||
* Returns a String for the given field.
|
||||
|
||||
@@ -31,6 +31,75 @@ public final class ContactsContract {
|
||||
/** A content:// style uri to the authority for the contacts provider */
|
||||
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
|
||||
|
||||
public interface AccountsColumns {
|
||||
/**
|
||||
* The name of this account data
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String NAME = "name";
|
||||
/**
|
||||
* The name of this account data
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String TYPE = "type";
|
||||
/**
|
||||
* The name of this account data
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String DATA1 = "data1";
|
||||
|
||||
/**
|
||||
* The value for this account data
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String DATA2 = "data2";
|
||||
|
||||
/**
|
||||
* The value for this account data
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String DATA3 = "data3";
|
||||
|
||||
/**
|
||||
* The value for this account data
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String DATA4 = "data4";
|
||||
|
||||
/**
|
||||
* The value for this account data
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String DATA5 = "data5";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants for the aggregates table, which contains a record per group
|
||||
* of contact representing the same person.
|
||||
*/
|
||||
public static final class Accounts implements BaseColumns, AccountsColumns {
|
||||
/**
|
||||
* This utility class cannot be instantiated
|
||||
*/
|
||||
private Accounts() {}
|
||||
|
||||
/**
|
||||
* The content:// style URI for this table
|
||||
*/
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "accounts");
|
||||
|
||||
/**
|
||||
* The MIME type of {@link #CONTENT_URI} providing a directory of
|
||||
* account data.
|
||||
*/
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contacts_account";
|
||||
|
||||
/**
|
||||
* The MIME type of a {@link #CONTENT_URI} subdirectory of a account
|
||||
*/
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contacts_account";
|
||||
}
|
||||
|
||||
public interface AggregatesColumns {
|
||||
/**
|
||||
* The display name for the contact.
|
||||
@@ -135,6 +204,11 @@ public final class ContactsContract {
|
||||
*/
|
||||
private Contacts() {}
|
||||
|
||||
/**
|
||||
* A reference to the {@link Accounts#_ID} that this data belongs to.
|
||||
*/
|
||||
public static final String ACCOUNTS_ID = "accounts_id";
|
||||
|
||||
/**
|
||||
* A reference to the {@link Aggregates#_ID} that this data belongs to.
|
||||
*/
|
||||
@@ -166,6 +240,22 @@ public final class ContactsContract {
|
||||
*/
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
|
||||
|
||||
/**
|
||||
* A string that uniquely identifies this contact to its source, which is referred to
|
||||
* by the {@link #ACCOUNTS_ID}
|
||||
*/
|
||||
public static final String SOURCE_ID = "sourceid";
|
||||
|
||||
/**
|
||||
* An integer that is updated whenever this contact or its data changes.
|
||||
*/
|
||||
public static final String VERSION = "version";
|
||||
|
||||
/**
|
||||
* Set to 1 whenever the version changes
|
||||
*/
|
||||
public static final String DIRTY = "dirty";
|
||||
|
||||
/**
|
||||
* A sub-directory of a single contact that contains all of their {@link Data} rows.
|
||||
* To access this directory append
|
||||
|
||||
@@ -229,7 +229,7 @@ static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column
|
||||
{
|
||||
int32_t err;
|
||||
CursorWindow * window = GET_WINDOW(env, object);
|
||||
LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window);
|
||||
LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window);
|
||||
|
||||
field_slot_t field;
|
||||
err = window->read_field_slot(row, column, &field);
|
||||
@@ -241,6 +241,54 @@ LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window
|
||||
return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL;
|
||||
}
|
||||
|
||||
static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column)
|
||||
{
|
||||
int32_t err;
|
||||
CursorWindow * window = GET_WINDOW(env, object);
|
||||
LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window);
|
||||
|
||||
field_slot_t field;
|
||||
err = window->read_field_slot(row, column, &field);
|
||||
if (err != 0) {
|
||||
throwExceptionWithRowCol(env, row, column);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL;
|
||||
}
|
||||
|
||||
static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column)
|
||||
{
|
||||
int32_t err;
|
||||
CursorWindow * window = GET_WINDOW(env, object);
|
||||
LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window);
|
||||
|
||||
field_slot_t field;
|
||||
err = window->read_field_slot(row, column, &field);
|
||||
if (err != 0) {
|
||||
throwExceptionWithRowCol(env, row, column);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return field.type == FIELD_TYPE_INTEGER;
|
||||
}
|
||||
|
||||
static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
|
||||
{
|
||||
int32_t err;
|
||||
CursorWindow * window = GET_WINDOW(env, object);
|
||||
LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window);
|
||||
|
||||
field_slot_t field;
|
||||
err = window->read_field_slot(row, column, &field);
|
||||
if (err != 0) {
|
||||
throwExceptionWithRowCol(env, row, column);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return field.type == FIELD_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
|
||||
{
|
||||
int32_t err;
|
||||
@@ -326,11 +374,11 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
|
||||
jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField);
|
||||
if (buffer == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null");
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
jchar* dst = env->GetCharArrayElements(buffer, NULL);
|
||||
uint8_t type = field.type;
|
||||
@@ -338,7 +386,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
|
||||
jcharArray newArray = NULL;
|
||||
if (type == FIELD_TYPE_STRING) {
|
||||
uint32_t size = field.data.buffer.size;
|
||||
if (size > 0) {
|
||||
if (size > 0) {
|
||||
#if WINDOW_STORAGE_UTF8
|
||||
// Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
|
||||
String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
|
||||
@@ -346,7 +394,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
|
||||
if (strSize > bufferSize || dst == NULL) {
|
||||
newArray = env->NewCharArray(strSize);
|
||||
env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string());
|
||||
} else {
|
||||
} else {
|
||||
memcpy(dst, (jchar const *)utf16.string(), strSize * 2);
|
||||
}
|
||||
sizeCopied = strSize;
|
||||
@@ -359,7 +407,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
|
||||
memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (type == FIELD_TYPE_INTEGER) {
|
||||
int64_t value;
|
||||
if (window->getLong(row, column, &value)) {
|
||||
@@ -628,6 +676,9 @@ static JNINativeMethod sMethods[] =
|
||||
{"putDouble_native", "(DII)Z", (void *)putDouble_native},
|
||||
{"freeLastRow_native", "()V", (void *)freeLastRow},
|
||||
{"putNull_native", "(II)Z", (void *)putNull_native},
|
||||
{"isString_native", "(II)Z", (void *)isString_native},
|
||||
{"isFloat_native", "(II)Z", (void *)isFloat_native},
|
||||
{"isInteger_native", "(II)Z", (void *)isInteger_native},
|
||||
};
|
||||
|
||||
int register_android_database_CursorWindow(JNIEnv * env)
|
||||
@@ -646,7 +697,7 @@ int register_android_database_CursorWindow(JNIEnv * env)
|
||||
LOGE("Error locating fields");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
clazz = env->FindClass("android/database/CharArrayBuffer");
|
||||
if (clazz == NULL) {
|
||||
LOGE("Can't find android/database/CharArrayBuffer");
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Mock implementation of IContentProvider that does nothing. All methods are non-functional and
|
||||
@@ -91,7 +92,8 @@ public class MockContentProvider implements IContentProvider {
|
||||
throw new UnsupportedOperationException("unimplemented mock method");
|
||||
}
|
||||
|
||||
public ContentProviderResult[] applyBatch(ContentProviderOperation[] operations) throws RemoteException, OperationApplicationException {
|
||||
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
|
||||
throws RemoteException, OperationApplicationException {
|
||||
throw new UnsupportedOperationException("unimplemented mock method");
|
||||
}
|
||||
|
||||
|
||||
@@ -92,10 +92,6 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testInsertWithBackRefs() throws OperationApplicationException {
|
||||
ContentValues valuesBackRefs = new ContentValues();
|
||||
valuesBackRefs.put("a1", 3);
|
||||
valuesBackRefs.put("a2", 1);
|
||||
|
||||
ContentProviderResult[] previousResults = new ContentProviderResult[4];
|
||||
previousResults[0] = new ContentProviderResult(100);
|
||||
previousResults[1] = new ContentProviderResult(101);
|
||||
@@ -103,7 +99,8 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
previousResults[3] = new ContentProviderResult(103);
|
||||
ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
|
||||
.withValues(sTestValues1)
|
||||
.withValueBackReferences(valuesBackRefs)
|
||||
.withValueBackReference("a1", 3)
|
||||
.withValueBackReference("a2", 1)
|
||||
.build();
|
||||
ContentProviderResult result = op1.apply(new TestContentProvider() {
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
@@ -146,11 +143,6 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
previousResults[2] = new ContentProviderResult(102);
|
||||
previousResults[3] = new ContentProviderResult(103);
|
||||
|
||||
ContentValues valuesBackRefs = new ContentValues();
|
||||
valuesBackRefs.put("a1", 3); // a1 -> 103
|
||||
valuesBackRefs.put("a2", 1); // a2 -> 101
|
||||
valuesBackRefs.put("a3", 2); // a3 -> 102
|
||||
|
||||
ContentValues expectedValues = new ContentValues(values);
|
||||
expectedValues.put("a1", "103");
|
||||
expectedValues.put("a2", "101");
|
||||
@@ -158,18 +150,15 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
|
||||
ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
|
||||
.withValues(values)
|
||||
.withValueBackReferences(valuesBackRefs)
|
||||
.withValueBackReference("a1", 3)
|
||||
.withValueBackReference("a2", 1)
|
||||
.withValueBackReference("a3", 2)
|
||||
.build();
|
||||
ContentValues v2 = op1.resolveValueBackReferences(previousResults, previousResults.length);
|
||||
assertEquals(expectedValues, v2);
|
||||
}
|
||||
|
||||
public void testSelectionBackRefs() {
|
||||
Map<Integer, Integer> selectionBackRefs = new Hashtable<Integer, Integer>();
|
||||
selectionBackRefs.put(1, 3);
|
||||
selectionBackRefs.put(2, 1);
|
||||
selectionBackRefs.put(4, 2);
|
||||
|
||||
ContentProviderResult[] previousResults = new ContentProviderResult[4];
|
||||
previousResults[0] = new ContentProviderResult(100);
|
||||
previousResults[1] = new ContentProviderResult(101);
|
||||
@@ -179,7 +168,9 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
String[] selectionArgs = new String[]{"a", null, null, "b", null};
|
||||
|
||||
ContentProviderOperation op1 = ContentProviderOperation.newUpdate(sTestUri1)
|
||||
.withSelectionBackReferences(selectionBackRefs)
|
||||
.withSelectionBackReference(1, 3)
|
||||
.withSelectionBackReference(2, 1)
|
||||
.withSelectionBackReference(4, 2)
|
||||
.withSelection("unused", selectionArgs)
|
||||
.build();
|
||||
String[] s2 = op1.resolveSelectionArgsBackReferences(
|
||||
@@ -209,7 +200,6 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(
|
||||
Uri.parse("content://goo/bar"));
|
||||
|
||||
builderSetEntity(builder, new TestEntity("blah"));
|
||||
builderSetExpectedCount(builder, 42);
|
||||
builderSetSelection(builder, "selection");
|
||||
builderSetSelectionArgs(builder, new String[]{"a", "b"});
|
||||
@@ -224,7 +214,6 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
|
||||
assertEquals(1 /* ContentProviderOperation.TYPE_INSERT */, operationGetType(op2));
|
||||
assertEquals("content://goo/bar", operationGetUri(op2).toString());
|
||||
assertEquals("blah", ((TestEntity) operationGetEntity(op2)).mValue);
|
||||
assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
|
||||
assertEquals("selection", operationGetSelection(op2));
|
||||
assertEquals(2, operationGetSelectionArgs(op2).length);
|
||||
@@ -422,35 +411,6 @@ public class ContentProviderOperationTest extends TestCase {
|
||||
return (Map<Integer, Integer>) field.get(operation);
|
||||
}
|
||||
|
||||
public static class TestEntity extends Entity {
|
||||
public final String mValue;
|
||||
public TestEntity(String value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public TestEntity(Parcel source) {
|
||||
mValue = source.readString();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mValue);
|
||||
}
|
||||
|
||||
public static final Creator<TestEntity> CREATOR = new Creator<TestEntity>() {
|
||||
public TestEntity createFromParcel(Parcel source) {
|
||||
return new TestEntity(source);
|
||||
}
|
||||
|
||||
public TestEntity[] newArray(int size) {
|
||||
return new TestEntity[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testParcelingResult() {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
ContentProviderResult result1;
|
||||
|
||||
Reference in New Issue
Block a user