1ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana/*
2ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * Copyright (C) 2009 The Android Open Source Project
3ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana *
4ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * you may not use this file except in compliance with the License.
6ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * You may obtain a copy of the License at
7ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana *
8ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana *
10ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * Unless required by applicable law or agreed to in writing, software
11ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * See the License for the specific language governing permissions and
14ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana * limitations under the License.
15ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana */
16ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
17ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintanapackage android.content;
18ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
19ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintanaimport android.database.Cursor;
2008b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkeyimport android.net.Uri;
218943737692169f564cd34a9c8d471f3a5d438712Fred Quintanaimport android.os.Parcel;
2208b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkeyimport android.os.Parcelable;
2308b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkeyimport android.text.TextUtils;
2435abad216da8a49128c3899a206c15d44c471617Ken Shirriffimport android.util.Log;
25ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
2608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkeyimport java.util.ArrayList;
278943737692169f564cd34a9c8d471f3a5d438712Fred Quintanaimport java.util.HashMap;
2808b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkeyimport java.util.Map;
29ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
308943737692169f564cd34a9c8d471f3a5d438712Fred Quintanapublic class ContentProviderOperation implements Parcelable {
31bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    /** @hide exposed for unit tests */
32bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    public final static int TYPE_INSERT = 1;
33bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    /** @hide exposed for unit tests */
34bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    public final static int TYPE_UPDATE = 2;
35bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    /** @hide exposed for unit tests */
36bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    public final static int TYPE_DELETE = 3;
37bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    /** @hide exposed for unit tests */
3808b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey    public final static int TYPE_ASSERT = 4;
39ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
40ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final int mType;
41ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final Uri mUri;
42ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final String mSelection;
43ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final String[] mSelectionArgs;
44ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final ContentValues mValues;
45ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final Integer mExpectedCount;
46ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final ContentValues mValuesBackReferences;
47ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private final Map<Integer, Integer> mSelectionArgsBackReferences;
4856f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana    private final boolean mYieldAllowed;
49ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
5035abad216da8a49128c3899a206c15d44c471617Ken Shirriff    private final static String TAG = "ContentProviderOperation";
5135abad216da8a49128c3899a206c15d44c471617Ken Shirriff
52ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
53ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Creates a {@link ContentProviderOperation} by copying the contents of a
54ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * {@link Builder}.
55ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
56ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    private ContentProviderOperation(Builder builder) {
57ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mType = builder.mType;
58ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mUri = builder.mUri;
59ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mValues = builder.mValues;
60ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mSelection = builder.mSelection;
61ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mSelectionArgs = builder.mSelectionArgs;
62ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mExpectedCount = builder.mExpectedCount;
63ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
64ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        mValuesBackReferences = builder.mValuesBackReferences;
6556f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        mYieldAllowed = builder.mYieldAllowed;
66ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
67ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
6803d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana    private ContentProviderOperation(Parcel source) {
698943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mType = source.readInt();
708943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mUri = Uri.CREATOR.createFromParcel(source);
718943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
728943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mSelection = source.readInt() != 0 ? source.readString() : null;
738943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
748943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
758943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mValuesBackReferences = source.readInt() != 0
768943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                ? ContentValues.CREATOR.createFromParcel(source)
778943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                : null;
788943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        mSelectionArgsBackReferences = source.readInt() != 0
798943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                ? new HashMap<Integer, Integer>()
808943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                : null;
818943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mSelectionArgsBackReferences != null) {
828943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            final int count = source.readInt();
838943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            for (int i = 0; i < count; i++) {
848943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
858943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            }
868943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
8756f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        mYieldAllowed = source.readInt() != 0;
888943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
898943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
908943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public void writeToParcel(Parcel dest, int flags) {
918943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        dest.writeInt(mType);
928943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        Uri.writeToParcel(dest, mUri);
938943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mValues != null) {
948943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
958943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            mValues.writeToParcel(dest, 0);
968943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
978943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
988943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
998943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mSelection != null) {
1008943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
1018943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeString(mSelection);
1028943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
1038943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
1048943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
1058943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mSelectionArgs != null) {
1068943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
1078943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeStringArray(mSelectionArgs);
1088943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
1098943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
1108943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
1118943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mExpectedCount != null) {
1128943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
1138943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(mExpectedCount);
1148943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
1158943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
1168943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
1178943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mValuesBackReferences != null) {
1188943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
1198943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            mValuesBackReferences.writeToParcel(dest, 0);
1208943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
1218943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
1228943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
1238943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        if (mSelectionArgsBackReferences != null) {
1248943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(1);
1258943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(mSelectionArgsBackReferences.size());
1268943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            for (Map.Entry<Integer, Integer> entry : mSelectionArgsBackReferences.entrySet()) {
1278943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                dest.writeInt(entry.getKey());
1288943737692169f564cd34a9c8d471f3a5d438712Fred Quintana                dest.writeInt(entry.getValue());
1298943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            }
1308943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        } else {
1318943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            dest.writeInt(0);
1328943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
13356f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        dest.writeInt(mYieldAllowed ? 1 : 0);
1348943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
1358943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
136ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
137ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Create a {@link Builder} suitable for building an insert {@link ContentProviderOperation}.
138ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param uri The {@link Uri} that is the target of the insert.
139ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return a {@link Builder}
140ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
141ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public static Builder newInsert(Uri uri) {
142ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return new Builder(TYPE_INSERT, uri);
143ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
144ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
145ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
146ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Create a {@link Builder} suitable for building an update {@link ContentProviderOperation}.
147ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param uri The {@link Uri} that is the target of the update.
148ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return a {@link Builder}
149ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
150ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public static Builder newUpdate(Uri uri) {
151ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return new Builder(TYPE_UPDATE, uri);
152ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
153ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
154ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
155ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Create a {@link Builder} suitable for building a delete {@link ContentProviderOperation}.
156ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param uri The {@link Uri} that is the target of the delete.
157ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return a {@link Builder}
158ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
159ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public static Builder newDelete(Uri uri) {
160ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return new Builder(TYPE_DELETE, uri);
161ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
162ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
163ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
16408b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey     * Create a {@link Builder} suitable for building a
16508b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey     * {@link ContentProviderOperation} to assert a set of values as provided
16608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey     * through {@link Builder#withValues(ContentValues)}.
167ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
16808b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey    public static Builder newAssertQuery(Uri uri) {
16908b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey        return new Builder(TYPE_ASSERT, uri);
170ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
171ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
1728943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public Uri getUri() {
1738943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        return mUri;
1748943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
1758943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
17656f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana    public boolean isYieldAllowed() {
17756f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        return mYieldAllowed;
17856f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana    }
17956f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana
180bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    /** @hide exposed for unit tests */
181bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    public int getType() {
182bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey        return mType;
183bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey    }
184bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey
1858943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public boolean isWriteOperation() {
1868943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
1878943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
1888943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
1898943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public boolean isReadOperation() {
19008b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey        return mType == TYPE_ASSERT;
1918943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
1928943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
193ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
194ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Applies this operation using the given provider. The backRefs array is used to resolve any
195ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * back references that were requested using
196ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * {@link Builder#withValueBackReferences(ContentValues)} and
19703d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana     * {@link Builder#withSelectionBackReference}.
198ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param provider the {@link ContentProvider} on which this batch is applied
199ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param backRefs a {@link ContentProviderResult} array that will be consulted
200ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * to resolve any requested back references.
201ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param numBackRefs the number of valid results on the backRefs array.
202ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return a {@link ContentProviderResult} that contains either the {@link Uri} of the inserted
203ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * row if this was an insert otherwise the number of rows affected.
204ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @throws OperationApplicationException thrown if either the insert fails or
205ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * if the number of rows affected didn't match the expected count
206ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
207ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
208ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            int numBackRefs) throws OperationApplicationException {
209ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
210ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        String[] selectionArgs =
211ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                resolveSelectionArgsBackReferences(backRefs, numBackRefs);
212ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
213ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mType == TYPE_INSERT) {
21403d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            Uri newUri = provider.insert(mUri, values);
215ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            if (newUri == null) {
216ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new OperationApplicationException("insert failed");
217ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
218ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return new ContentProviderResult(newUri);
219ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
220ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
221ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        int numRows;
222ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mType == TYPE_DELETE) {
223ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            numRows = provider.delete(mUri, mSelection, selectionArgs);
224ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        } else if (mType == TYPE_UPDATE) {
22503d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            numRows = provider.update(mUri, values, mSelection, selectionArgs);
22608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey        } else if (mType == TYPE_ASSERT) {
22708b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            // Assert that all rows match expected values
2285ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            String[] projection =  null;
2295ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            if (values != null) {
2305ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                // Build projection map from expected values
2315ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                final ArrayList<String> projectionList = new ArrayList<String>();
2325ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                for (Map.Entry<String, Object> entry : values.valueSet()) {
2335ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                    projectionList.add(entry.getKey());
2345ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                }
2355ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                projection = projectionList.toArray(new String[projectionList.size()]);
2365ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            }
23708b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
238ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            try {
2395ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                numRows = cursor.getCount();
2405ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                if (projection != null) {
2415ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                    while (cursor.moveToNext()) {
2425ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                        for (int i = 0; i < projection.length; i++) {
2435ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                            final String cursorValue = cursor.getString(i);
2445ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                            final String expectedValue = values.getAsString(projection[i]);
2455ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                            if (!TextUtils.equals(cursorValue, expectedValue)) {
2465ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                                // Throw exception when expected values don't match
24735abad216da8a49128c3899a206c15d44c471617Ken Shirriff                                Log.e(TAG, this.toString());
2485ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                                throw new OperationApplicationException("Found value " + cursorValue
2495ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                                        + " when expected " + expectedValue + " for column "
2505ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                                        + projection[i]);
2515ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                            }
25208b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        }
25308b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                    }
254ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                }
255ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            } finally {
256ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                cursor.close();
257ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
258ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        } else {
25935abad216da8a49128c3899a206c15d44c471617Ken Shirriff            Log.e(TAG, this.toString());
260ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            throw new IllegalStateException("bad type, " + mType);
261ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
262ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
263ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mExpectedCount != null && mExpectedCount != numRows) {
26435abad216da8a49128c3899a206c15d44c471617Ken Shirriff            Log.e(TAG, this.toString());
265ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            throw new OperationApplicationException("wrong number of rows: " + numRows);
266ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
267ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
268ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return new ContentProviderResult(numRows);
269ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
270ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
271ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
272ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * The ContentValues back references are represented as a ContentValues object where the
273ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * key refers to a column and the value is an index of the back reference whose
274ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * valued should be associated with the column.
275d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * <p>
276d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * This is intended to be a private method but it is exposed for
277d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * unit testing purposes
278ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param backRefs an array of previous results
279ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param numBackRefs the number of valid previous results in backRefs
280ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return the ContentValues that should be used in this operation application after
281ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * expansion of back references. This can be called if either mValues or mValuesBackReferences
282ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * is null
283ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
284ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public ContentValues resolveValueBackReferences(
285ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            ContentProviderResult[] backRefs, int numBackRefs) {
286ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mValuesBackReferences == null) {
287ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return mValues;
288ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
289ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        final ContentValues values;
290ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mValues == null) {
291ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            values = new ContentValues();
292ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        } else {
293ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            values = new ContentValues(mValues);
294ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
295ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        for (Map.Entry<String, Object> entry : mValuesBackReferences.valueSet()) {
296ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            String key = entry.getKey();
297ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
298ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            if (backRefIndex == null) {
29935abad216da8a49128c3899a206c15d44c471617Ken Shirriff                Log.e(TAG, this.toString());
300ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException("values backref " + key + " is not an integer");
301ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
302ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
303ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
304ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return values;
305ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
306ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
307ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
308ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * The Selection Arguments back references are represented as a Map of Integer->Integer where
309ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * the key is an index into the selection argument array (see {@link Builder#withSelection})
310ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * and the value is the index of the previous result that should be used for that selection
311ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * argument array slot.
312d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * <p>
313d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * This is intended to be a private method but it is exposed for
314d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato     * unit testing purposes
315ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param backRefs an array of previous results
316ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param numBackRefs the number of valid previous results in backRefs
317ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return the ContentValues that should be used in this operation application after
318ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * expansion of back references. This can be called if either mValues or mValuesBackReferences
319ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * is null
320ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
321ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public String[] resolveSelectionArgsBackReferences(
322ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            ContentProviderResult[] backRefs, int numBackRefs) {
323ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (mSelectionArgsBackReferences == null) {
324ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return mSelectionArgs;
325ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
326ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        String[] newArgs = new String[mSelectionArgs.length];
327ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        System.arraycopy(mSelectionArgs, 0, newArgs, 0, mSelectionArgs.length);
328ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        for (Map.Entry<Integer, Integer> selectionArgBackRef
329ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                : mSelectionArgsBackReferences.entrySet()) {
330ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            final Integer selectionArgIndex = selectionArgBackRef.getKey();
331ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            final int backRefIndex = selectionArgBackRef.getValue();
3328851e163fc5bc17d139bf29cd2ec2f3926d342bcFred Quintana            newArgs[selectionArgIndex] =
3338851e163fc5bc17d139bf29cd2ec2f3926d342bcFred Quintana                    String.valueOf(backRefToValue(backRefs, numBackRefs, backRefIndex));
334ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
335ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return newArgs;
336ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
337ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
33835abad216da8a49128c3899a206c15d44c471617Ken Shirriff    @Override
33935abad216da8a49128c3899a206c15d44c471617Ken Shirriff    public String toString() {
34035abad216da8a49128c3899a206c15d44c471617Ken Shirriff        return "mType: " + mType + ", mUri: " + mUri +
34135abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mSelection: " + mSelection +
34235abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mExpectedCount: " + mExpectedCount +
34335abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mYieldAllowed: " + mYieldAllowed +
34435abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mValues: " + mValues +
34535abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mValuesBackReferences: " + mValuesBackReferences +
34635abad216da8a49128c3899a206c15d44c471617Ken Shirriff                ", mSelectionArgsBackReferences: " + mSelectionArgsBackReferences;
34735abad216da8a49128c3899a206c15d44c471617Ken Shirriff    }
34835abad216da8a49128c3899a206c15d44c471617Ken Shirriff
349ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
350ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Return the string representation of the requested back reference.
351ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param backRefs an array of results
352ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param numBackRefs the number of items in the backRefs array that are valid
353ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @param backRefIndex which backRef to be used
354ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @throws ArrayIndexOutOfBoundsException thrown if the backRefIndex is larger than
355ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * the numBackRefs
356ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * @return the string representation of the requested back reference.
357ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
35835abad216da8a49128c3899a206c15d44c471617Ken Shirriff    private long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
359ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            Integer backRefIndex) {
36003d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana        if (backRefIndex >= numBackRefs) {
36135abad216da8a49128c3899a206c15d44c471617Ken Shirriff            Log.e(TAG, this.toString());
362ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
363ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                    + " but there are only " + numBackRefs + " back refs");
364ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
365ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        ContentProviderResult backRef = backRefs[backRefIndex];
3668851e163fc5bc17d139bf29cd2ec2f3926d342bcFred Quintana        long backRefValue;
367ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        if (backRef.uri != null) {
3688851e163fc5bc17d139bf29cd2ec2f3926d342bcFred Quintana            backRefValue = ContentUris.parseId(backRef.uri);
369ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        } else {
3708851e163fc5bc17d139bf29cd2ec2f3926d342bcFred Quintana            backRefValue = backRef.count;
371ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
372ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        return backRefValue;
373ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
374ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
3758943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public int describeContents() {
3768943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        return 0;
3778943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    }
3788943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
3798943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    public static final Creator<ContentProviderOperation> CREATOR =
3808943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            new Creator<ContentProviderOperation>() {
3818943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        public ContentProviderOperation createFromParcel(Parcel source) {
38203d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            return new ContentProviderOperation(source);
3838943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
3848943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
3858943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        public ContentProviderOperation[] newArray(int size) {
3868943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            return new ContentProviderOperation[size];
3878943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
3888943737692169f564cd34a9c8d471f3a5d438712Fred Quintana    };
3898943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
3908943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
391ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    /**
392ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
393ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
394ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * {@link ContentProviderOperation#newUpdate(android.net.Uri)},
395ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * {@link ContentProviderOperation#newDelete(android.net.Uri)} or
39608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey     * {@link ContentProviderOperation#newAssertQuery(Uri)}. The withXXX methods
397ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * can then be used to add parameters to the builder. See the specific methods to find for
398ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * which {@link Builder} type each is allowed. Call {@link #build} to create the
399ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     * {@link ContentProviderOperation} once all the parameters have been supplied.
400ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana     */
401ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    public static class Builder {
402ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private final int mType;
403ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private final Uri mUri;
404ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private String mSelection;
405ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private String[] mSelectionArgs;
406ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private ContentValues mValues;
407ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private Integer mExpectedCount;
408ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private ContentValues mValuesBackReferences;
409ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private Map<Integer, Integer> mSelectionArgsBackReferences;
41056f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        private boolean mYieldAllowed;
411ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
412ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /** Create a {@link Builder} of a given type. The uri must not be null. */
413ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        private Builder(int type, Uri uri) {
414ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            if (uri == null) {
415ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException("uri must not be null");
416ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
417ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            mType = type;
418ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            mUri = uri;
419ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
420ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
4218943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        /** Create a ContentProviderOperation from this {@link Builder}. */
422ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        public ContentProviderOperation build() {
4235ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            if (mType == TYPE_UPDATE) {
424c933fb663e4748c4fa3f92fc63649e5199519a86Fred Quintana                if ((mValues == null || mValues.size() == 0)
425c933fb663e4748c4fa3f92fc63649e5199519a86Fred Quintana                        && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
426c933fb663e4748c4fa3f92fc63649e5199519a86Fred Quintana                    throw new IllegalArgumentException("Empty values");
427c933fb663e4748c4fa3f92fc63649e5199519a86Fred Quintana                }
428c933fb663e4748c4fa3f92fc63649e5199519a86Fred Quintana            }
4295ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            if (mType == TYPE_ASSERT) {
4305ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                if ((mValues == null || mValues.size() == 0)
4315ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                        && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)
4325ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                        && (mExpectedCount == null)) {
4335ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                    throw new IllegalArgumentException("Empty values");
4345ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana                }
4355ab78057a35dc71b2847920031cd707a7e2c6c64Fred Quintana            }
436ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return new ContentProviderOperation(this);
437ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
438ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
439ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /**
440ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * Add a {@link ContentValues} of back references. The key is the name of the column
441ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * and the value is an integer that is the index of the previous result whose
442ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * value should be used for the column. The value is added as a {@link String}.
443ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * A column value from the back references takes precedence over a value specified in
444ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * {@link #withValues}.
44508b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type insert, update, or assert.
446ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * @return this builder, to allow for chaining.
447ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         */
448ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        public Builder withValueBackReferences(ContentValues backReferences) {
44908b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
450ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException(
45108b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        "only inserts, updates, and asserts can have value back-references");
452ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
453ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            mValuesBackReferences = backReferences;
454ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return this;
455ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
456ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
457ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /**
45803d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * Add a ContentValues back reference.
45903d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * A column value from the back references takes precedence over a value specified in
46003d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * {@link #withValues}.
46108b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type insert, update, or assert.
462ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * @return this builder, to allow for chaining.
463ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         */
46403d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana        public Builder withValueBackReference(String key, int previousResult) {
46508b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
466ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException(
46708b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        "only inserts, updates, and asserts can have value back-references");
468ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
46903d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            if (mValuesBackReferences == null) {
47003d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana                mValuesBackReferences = new ContentValues();
47103d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            }
47203d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            mValuesBackReferences.put(key, previousResult);
473ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return this;
474ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
475ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
476ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /**
47703d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * Add a back references as a selection arg. Any value at that index of the selection arg
47803d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * that was specified by {@link #withSelection} will be overwritten.
47908b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type update, delete, or assert.
480ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * @return this builder, to allow for chaining.
481ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         */
48203d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana        public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
48308b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
48408b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                throw new IllegalArgumentException("only updates, deletes, and asserts "
48508b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        + "can have selection back-references");
486ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
48703d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            if (mSelectionArgsBackReferences == null) {
48803d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana                mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
48903d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            }
49003d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana            mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
491ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return this;
492ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
493ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
494ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /**
4958943737692169f564cd34a9c8d471f3a5d438712Fred Quintana         * The ContentValues to use. This may be null. These values may be overwritten by
496d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * the corresponding value specified by {@link #withValueBackReference} or by
497d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * future calls to {@link #withValues} or {@link #withValue}.
49808b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type insert, update, or assert.
4998943737692169f564cd34a9c8d471f3a5d438712Fred Quintana         * @return this builder, to allow for chaining.
5008943737692169f564cd34a9c8d471f3a5d438712Fred Quintana         */
50103d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana        public Builder withValues(ContentValues values) {
50208b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
50308b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                throw new IllegalArgumentException(
50408b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        "only inserts, updates, and asserts can have values");
5058943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            }
506d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            if (mValues == null) {
507d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues = new ContentValues();
508d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            }
509d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            mValues.putAll(values);
5108943737692169f564cd34a9c8d471f3a5d438712Fred Quintana            return this;
5118943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        }
5128943737692169f564cd34a9c8d471f3a5d438712Fred Quintana
5138943737692169f564cd34a9c8d471f3a5d438712Fred Quintana        /**
514d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * A value to insert or update. This value may be overwritten by
515d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * the corresponding value specified by {@link #withValueBackReference}.
51608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type insert, update, or assert.
517d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * @param key the name of this value
518d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * @param value the value itself. the type must be acceptable for insertion by
519d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * {@link ContentValues#put}
520d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         * @return this builder, to allow for chaining.
521d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana         */
522d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana        public Builder withValue(String key, Object value) {
52308b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
524d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                throw new IllegalArgumentException("only inserts and updates can have values");
525d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            }
526d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            if (mValues == null) {
527d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues = new ContentValues();
528d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            }
529d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            if (value == null) {
530d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.putNull(key);
531d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof String) {
532d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (String) value);
533d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Byte) {
534d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Byte) value);
535d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Short) {
536d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Short) value);
537d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Integer) {
538d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Integer) value);
539d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Long) {
540d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Long) value);
541d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Float) {
542d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Float) value);
543d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Double) {
544d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Double) value);
545d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof Boolean) {
546d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (Boolean) value);
547d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else if (value instanceof byte[]) {
548d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                mValues.put(key, (byte[]) value);
549d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            } else {
550d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana                throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
551d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            }
552d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana            return this;
553d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana        }
554bc25407b9299ae433023ddf147fe633f3b3b640cJeff Sharkey
555d8dfeb5ee82d679f491cd20e776907a69fb4f27cFred Quintana        /**
556ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * The selection and arguments to use. An occurrence of '?' in the selection will be
557ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * replaced with the corresponding occurence of the selection argument. Any of the
558ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * selection arguments may be overwritten by a selection argument back reference as
55903d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana         * specified by {@link #withSelectionBackReference}.
56008b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type update, delete, or assert.
561ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * @return this builder, to allow for chaining.
562ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         */
563ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        public Builder withSelection(String selection, String[] selectionArgs) {
56408b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
565ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException(
56608b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        "only updates, deletes, and asserts can have selections");
567ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
568ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            mSelection = selection;
569824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey            if (selectionArgs == null) {
570824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey                mSelectionArgs = null;
571824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey            } else {
572824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey                mSelectionArgs = new String[selectionArgs.length];
573824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey                System.arraycopy(selectionArgs, 0, mSelectionArgs, 0, selectionArgs.length);
574824838d74eb0316f6987a1d98d2d9e9fa8d4e15bJeff Sharkey            }
575ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return this;
576ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
577ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana
578ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        /**
579ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * If set then if the number of rows affected by this operation do not match
580ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * this count {@link OperationApplicationException} will be throw.
58108b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey         * This can only be used with builders of type update, delete, or assert.
582ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         * @return this builder, to allow for chaining.
583ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana         */
584ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        public Builder withExpectedCount(int count) {
58508b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
586ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana                throw new IllegalArgumentException(
58708b75b1ffb856ab97e1577eb7d20c69a18fcaccaJeff Sharkey                        "only updates, deletes, and asserts can have expected counts");
588ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            }
589ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            mExpectedCount = count;
590ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana            return this;
591ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana        }
59256f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana
59356f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        public Builder withYieldAllowed(boolean yieldAllowed) {
59456f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana            mYieldAllowed = yieldAllowed;
59556f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana            return this;
59656f67d21459ad3f136c73c8932904d4a495989c0Fred Quintana        }
597ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana    }
598ce31b2361db630cf1347fa42dd77e610a4eeb96dFred Quintana}
599