18402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton/*
28402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * Copyright (C) 2009 The Android Open Source Project
38402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton *
48402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
58402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * you may not use this file except in compliance with the License.
68402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * You may obtain a copy of the License at
78402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton *
88402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
98402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton *
108402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * Unless required by applicable law or agreed to in writing, software
118402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
128402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * See the License for the specific language governing permissions and
148402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * limitations under the License
158402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton */
168402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
178402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonpackage com.android.browser.provider;
188402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
198402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.ContentProvider;
208402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.ContentProviderOperation;
218402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.ContentProviderResult;
22fca41d76f4839d6707aa9680d47a93646cd01df4John Reckimport android.content.ContentResolver;
238402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.ContentValues;
248402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.Context;
258402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.content.OperationApplicationException;
268402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
278402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.database.sqlite.SQLiteOpenHelper;
288402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.net.Uri;
298402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
308402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport java.util.ArrayList;
31fca41d76f4839d6707aa9680d47a93646cd01df4John Reckimport java.util.HashSet;
32fca41d76f4839d6707aa9680d47a93646cd01df4John Reckimport java.util.Set;
338402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
348402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton/**
358402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton * General purpose {@link ContentProvider} base class that uses SQLiteDatabase for storage.
368402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton */
37fca41d76f4839d6707aa9680d47a93646cd01df4John Reckpublic abstract class SQLiteContentProvider extends ContentProvider {
388402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
398402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private static final String TAG = "SQLiteContentProvider";
408402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
418402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private SQLiteOpenHelper mOpenHelper;
42fca41d76f4839d6707aa9680d47a93646cd01df4John Reck    private Set<Uri> mChangedUris;
438402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    protected SQLiteDatabase mDb;
448402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
458402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private final ThreadLocal<Boolean> mApplyingBatch = new ThreadLocal<Boolean>();
468402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private static final int SLEEP_AFTER_YIELD_DELAY = 4000;
478402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
488402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
498402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * Maximum number of operations allowed in a batch between yield points.
508402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
518402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private static final int MAX_OPERATIONS_PER_YIELD_POINT = 500;
528402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
538402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
548402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public boolean onCreate() {
558402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        Context context = getContext();
568402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        mOpenHelper = getDatabaseHelper(context);
57fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        mChangedUris = new HashSet<Uri>();
588402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return true;
598402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
608402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
618402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
628402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * Returns a {@link SQLiteOpenHelper} that can open the database.
638402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
648402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public abstract SQLiteOpenHelper getDatabaseHelper(Context context);
658402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
668402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
678402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * The equivalent of the {@link #insert} method, but invoked within a transaction.
688402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
698402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public abstract Uri insertInTransaction(Uri uri, ContentValues values,
708402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            boolean callerIsSyncAdapter);
718402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
728402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
738402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * The equivalent of the {@link #update} method, but invoked within a transaction.
748402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
758402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public abstract int updateInTransaction(Uri uri, ContentValues values, String selection,
768402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            String[] selectionArgs, boolean callerIsSyncAdapter);
778402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
788402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
798402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * The equivalent of the {@link #delete} method, but invoked within a transaction.
808402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
818402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs,
828402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            boolean callerIsSyncAdapter);
838402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
848402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
85fca41d76f4839d6707aa9680d47a93646cd01df4John Reck     * Call this to add a URI to the list of URIs to be notified when the transaction
86fca41d76f4839d6707aa9680d47a93646cd01df4John Reck     * is committed.
878402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
88fca41d76f4839d6707aa9680d47a93646cd01df4John Reck    protected void postNotifyUri(Uri uri) {
89fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        synchronized (mChangedUris) {
90fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            mChangedUris.add(uri);
91fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        }
92fca41d76f4839d6707aa9680d47a93646cd01df4John Reck    }
938402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
948402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public boolean isCallerSyncAdapter(Uri uri) {
958402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return false;
968402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
978402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
988402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public SQLiteOpenHelper getDatabaseHelper() {
998402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return mOpenHelper;
1008402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1018402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1028402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    private boolean applyingBatch() {
1038402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return mApplyingBatch.get() != null && mApplyingBatch.get();
1048402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1058402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1068402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
1078402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public Uri insert(Uri uri, ContentValues values) {
1088402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        Uri result = null;
1098402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
1108402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean applyingBatch = applyingBatch();
1118402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (!applyingBatch) {
1128402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb = mOpenHelper.getWritableDatabase();
113fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            mDb.beginTransaction();
1148402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            try {
1158402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                result = insertInTransaction(uri, values, callerIsSyncAdapter);
1168402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.setTransactionSuccessful();
1178402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            } finally {
1188402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.endTransaction();
1198402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
1208402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1218402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            onEndTransaction(callerIsSyncAdapter);
1228402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        } else {
1238402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            result = insertInTransaction(uri, values, callerIsSyncAdapter);
1248402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1258402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return result;
1268402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1278402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1288402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
1298402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public int bulkInsert(Uri uri, ContentValues[] values) {
1308402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int numValues = values.length;
1318402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
1328402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        mDb = mOpenHelper.getWritableDatabase();
133fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        mDb.beginTransaction();
1348402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        try {
1358402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            for (int i = 0; i < numValues; i++) {
1368402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                Uri result = insertInTransaction(uri, values[i], callerIsSyncAdapter);
1378402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.yieldIfContendedSafely();
1388402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
1398402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb.setTransactionSuccessful();
1408402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        } finally {
1418402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb.endTransaction();
1428402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1438402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1448402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        onEndTransaction(callerIsSyncAdapter);
1458402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return numValues;
1468402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1478402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1488402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
1498402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1508402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int count = 0;
1518402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
1528402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean applyingBatch = applyingBatch();
1538402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (!applyingBatch) {
1548402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb = mOpenHelper.getWritableDatabase();
155fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            mDb.beginTransaction();
1568402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            try {
1578402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                count = updateInTransaction(uri, values, selection, selectionArgs,
1588402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                        callerIsSyncAdapter);
1598402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.setTransactionSuccessful();
1608402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            } finally {
1618402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.endTransaction();
1628402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
1638402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1648402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            onEndTransaction(callerIsSyncAdapter);
1658402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        } else {
1668402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            count = updateInTransaction(uri, values, selection, selectionArgs, callerIsSyncAdapter);
1678402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1688402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1698402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return count;
1708402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1718402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1728402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
1738402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public int delete(Uri uri, String selection, String[] selectionArgs) {
1748402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int count = 0;
1758402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
1768402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean applyingBatch = applyingBatch();
1778402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (!applyingBatch) {
1788402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb = mOpenHelper.getWritableDatabase();
179fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            mDb.beginTransaction();
1808402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            try {
1818402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                count = deleteInTransaction(uri, selection, selectionArgs, callerIsSyncAdapter);
1828402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.setTransactionSuccessful();
1838402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            } finally {
1848402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                mDb.endTransaction();
1858402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
1868402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1878402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            onEndTransaction(callerIsSyncAdapter);
1888402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        } else {
1898402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            count = deleteInTransaction(uri, selection, selectionArgs, callerIsSyncAdapter);
1908402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1918402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return count;
1928402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1938402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1948402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    @Override
1958402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
1968402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            throws OperationApplicationException {
1978402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int ypCount = 0;
1988402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int opCount = 0;
1998402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        boolean callerIsSyncAdapter = false;
2008402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        mDb = mOpenHelper.getWritableDatabase();
201fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        mDb.beginTransaction();
2028402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        try {
2038402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mApplyingBatch.set(true);
2048402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            final int numOperations = operations.size();
2058402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            final ContentProviderResult[] results = new ContentProviderResult[numOperations];
2068402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            for (int i = 0; i < numOperations; i++) {
2078402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {
2088402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    throw new OperationApplicationException(
2098402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                            "Too many content provider operations between yield points. "
2108402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                                    + "The maximum number of operations per yield point is "
2118402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                                    + MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
2128402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                }
2138402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                final ContentProviderOperation operation = operations.get(i);
2148402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                if (!callerIsSyncAdapter && isCallerSyncAdapter(operation.getUri())) {
2158402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    callerIsSyncAdapter = true;
2168402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                }
2178402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                if (i > 0 && operation.isYieldAllowed()) {
2188402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    opCount = 0;
2198402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    if (mDb.yieldIfContendedSafely(SLEEP_AFTER_YIELD_DELAY)) {
2208402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                        ypCount++;
2218402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    }
2228402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                }
2238402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                results[i] = operation.apply(this, results, i);
2248402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
2258402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb.setTransactionSuccessful();
2268402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            return results;
2278402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        } finally {
2288402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mApplyingBatch.set(false);
2298402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            mDb.endTransaction();
2308402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            onEndTransaction(callerIsSyncAdapter);
2318402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
2328402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
2338402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
2348402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    protected void onEndTransaction(boolean callerIsSyncAdapter) {
235fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        Set<Uri> changed;
236fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        synchronized (mChangedUris) {
237fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            changed = new HashSet<Uri>(mChangedUris);
238fca41d76f4839d6707aa9680d47a93646cd01df4John Reck            mChangedUris.clear();
239fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        }
240fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        ContentResolver resolver = getContext().getContentResolver();
241fca41d76f4839d6707aa9680d47a93646cd01df4John Reck        for (Uri uri : changed) {
2423f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck            boolean syncToNetwork = !callerIsSyncAdapter && syncToNetwork(uri);
2433f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck            resolver.notifyChange(uri, null, syncToNetwork);
2448402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
2458402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
2463f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck
2473f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck    protected boolean syncToNetwork(Uri uri) {
2483f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck        return false;
2493f3da5238625bd2d73fdce7667fd61fe0f2548c5John Reck    }
2508402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton}
251