diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index a41b5d3fb7818..a646e49f4f61e 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -17,7 +17,6 @@ package android.content; import android.annotation.UnsupportedAppUsage; -import android.content.ContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; @@ -59,6 +58,7 @@ public class ContentProviderOperation implements Parcelable { private final ContentValues mValuesBackReferences; private final Map mSelectionArgsBackReferences; private final boolean mYieldAllowed; + private final boolean mFailureAllowed; private final static String TAG = "ContentProviderOperation"; @@ -76,6 +76,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences; mValuesBackReferences = builder.mValuesBackReferences; mYieldAllowed = builder.mYieldAllowed; + mFailureAllowed = builder.mFailureAllowed; } private ContentProviderOperation(Parcel source) { @@ -98,6 +99,7 @@ public class ContentProviderOperation implements Parcelable { } } mYieldAllowed = source.readInt() != 0; + mFailureAllowed = source.readInt() != 0; } /** @hide */ @@ -111,6 +113,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences; mValuesBackReferences = cpo.mValuesBackReferences; mYieldAllowed = cpo.mYieldAllowed; + mFailureAllowed = cpo.mFailureAllowed; } public void writeToParcel(Parcel dest, int flags) { @@ -157,6 +160,7 @@ public class ContentProviderOperation implements Parcelable { dest.writeInt(0); } dest.writeInt(mYieldAllowed ? 1 : 0); + dest.writeInt(mFailureAllowed ? 1 : 0); } /** @@ -212,6 +216,11 @@ public class ContentProviderOperation implements Parcelable { return mYieldAllowed; } + /** {@hide} */ + public boolean isFailureAllowed() { + return mFailureAllowed; + } + /** @hide exposed for unit tests */ @UnsupportedAppUsage public int getType() { @@ -274,6 +283,14 @@ public class ContentProviderOperation implements Parcelable { return mType == TYPE_ASSERT; } + private ContentProviderResult fail(String msg) throws OperationApplicationException { + if (mFailureAllowed) { + return new ContentProviderResult(msg); + } else { + throw new OperationApplicationException(msg); + } + } + /** * Applies this operation using the given provider. The backRefs array is used to resolve any * back references that were requested using @@ -297,7 +314,8 @@ public class ContentProviderOperation implements Parcelable { if (mType == TYPE_INSERT) { Uri newUri = provider.insert(mUri, values); if (newUri == null) { - throw new OperationApplicationException("insert failed"); + Log.e(TAG, this.toString()); + return fail("Insert into " + mUri + " returned no result"); } return new ContentProviderResult(newUri); } @@ -329,7 +347,7 @@ public class ContentProviderOperation implements Parcelable { if (!TextUtils.equals(cursorValue, expectedValue)) { // Throw exception when expected values don't match Log.e(TAG, this.toString()); - throw new OperationApplicationException("Found value " + cursorValue + return fail("Found value " + cursorValue + " when expected " + expectedValue + " for column " + projection[i]); } @@ -346,7 +364,7 @@ public class ContentProviderOperation implements Parcelable { if (mExpectedCount != null && mExpectedCount != numRows) { Log.e(TAG, this.toString()); - throw new OperationApplicationException("wrong number of rows: " + numRows); + return fail("Expected " + mExpectedCount + " rows but actual " + numRows); } return new ContentProviderResult(numRows); @@ -491,6 +509,7 @@ public class ContentProviderOperation implements Parcelable { private ContentValues mValuesBackReferences; private Map mSelectionArgsBackReferences; private boolean mYieldAllowed; + private boolean mFailureAllowed; /** Create a {@link Builder} of a given type. The uri must not be null. */ private Builder(int type, Uri uri) { @@ -683,5 +702,11 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = yieldAllowed; return this; } + + /** {@hide} */ + public Builder withFailureAllowed(boolean failureAllowed) { + mFailureAllowed = failureAllowed; + return this; + } } } diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index d90173ceb3cd6..b3010116a115c 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -16,10 +16,11 @@ package android.content; -import android.content.ContentProvider; import android.net.Uri; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; /** * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed @@ -28,26 +29,44 @@ import android.os.Parcel; public class ContentProviderResult implements Parcelable { public final Uri uri; public final Integer count; + /** {@hide} */ + public final String failure; public ContentProviderResult(Uri uri) { - if (uri == null) throw new IllegalArgumentException("uri must not be null"); - this.uri = uri; - this.count = null; + this(Preconditions.checkNotNull(uri), null, null); } public ContentProviderResult(int count) { + this(null, count, null); + } + + /** {@hide} */ + public ContentProviderResult(String failure) { + this(null, null, failure); + } + + /** {@hide} */ + public ContentProviderResult(Uri uri, Integer count, String failure) { + this.uri = uri; this.count = count; - this.uri = null; + this.failure = failure; } public ContentProviderResult(Parcel source) { - int type = source.readInt(); - if (type == 1) { - count = source.readInt(); + if (source.readInt() != 0) { + uri = Uri.CREATOR.createFromParcel(source); + } else { uri = null; + } + if (source.readInt() != 0) { + count = source.readInt(); } else { count = null; - uri = Uri.CREATOR.createFromParcel(source); + } + if (source.readInt() != 0) { + failure = source.readString(); + } else { + failure = null; } } @@ -55,37 +74,63 @@ public class ContentProviderResult implements Parcelable { public ContentProviderResult(ContentProviderResult cpr, int userId) { uri = ContentProvider.maybeAddUserId(cpr.uri, userId); count = cpr.count; + failure = cpr.failure; } + @Override public void writeToParcel(Parcel dest, int flags) { - if (uri == null) { + if (uri != null) { + dest.writeInt(1); + uri.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } + if (count != null) { dest.writeInt(1); dest.writeInt(count); } else { - dest.writeInt(2); - uri.writeToParcel(dest, 0); + dest.writeInt(0); + } + if (failure != null) { + dest.writeInt(1); + dest.writeString(failure); + } else { + dest.writeInt(0); } } + @Override public int describeContents() { return 0; } public static final @android.annotation.NonNull Creator CREATOR = new Creator() { + @Override public ContentProviderResult createFromParcel(Parcel source) { return new ContentProviderResult(source); } + @Override public ContentProviderResult[] newArray(int size) { return new ContentProviderResult[size]; } }; + @Override public String toString() { + final StringBuilder sb = new StringBuilder("ContentProviderResult("); if (uri != null) { - return "ContentProviderResult(uri=" + uri.toString() + ")"; + sb.append("uri=" + uri + " "); } - return "ContentProviderResult(count=" + count + ")"; + if (count != null) { + sb.append("count=" + count + " "); + } + if (uri != null) { + sb.append("failure=" + failure + " "); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(")"); + return sb.toString(); } }