1078f588cef389358adabc579de00747878f3c108Dave Santoro/* 2078f588cef389358adabc579de00747878f3c108Dave Santoro * Copyright (C) 2011 The Android Open Source Project 3078f588cef389358adabc579de00747878f3c108Dave Santoro * 4078f588cef389358adabc579de00747878f3c108Dave Santoro * Licensed under the Apache License, Version 2.0 (the "License"); 5078f588cef389358adabc579de00747878f3c108Dave Santoro * you may not use this file except in compliance with the License. 6078f588cef389358adabc579de00747878f3c108Dave Santoro * You may obtain a copy of the License at 7078f588cef389358adabc579de00747878f3c108Dave Santoro * 8078f588cef389358adabc579de00747878f3c108Dave Santoro * http://www.apache.org/licenses/LICENSE-2.0 9078f588cef389358adabc579de00747878f3c108Dave Santoro * 10078f588cef389358adabc579de00747878f3c108Dave Santoro * Unless required by applicable law or agreed to in writing, software 11078f588cef389358adabc579de00747878f3c108Dave Santoro * distributed under the License is distributed on an "AS IS" BASIS, 12078f588cef389358adabc579de00747878f3c108Dave Santoro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13078f588cef389358adabc579de00747878f3c108Dave Santoro * See the License for the specific language governing permissions and 14078f588cef389358adabc579de00747878f3c108Dave Santoro * limitations under the License 15078f588cef389358adabc579de00747878f3c108Dave Santoro */ 16078f588cef389358adabc579de00747878f3c108Dave Santoro 17078f588cef389358adabc579de00747878f3c108Dave Santoropackage com.android.providers.contacts; 18078f588cef389358adabc579de00747878f3c108Dave Santoro 19078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.ContentProvider; 20078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.ContentProviderOperation; 21078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.ContentProviderResult; 22078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.ContentValues; 23078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.Context; 24078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.content.OperationApplicationException; 25078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.database.sqlite.SQLiteOpenHelper; 26078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.database.sqlite.SQLiteTransactionListener; 27078f588cef389358adabc579de00747878f3c108Dave Santoroimport android.net.Uri; 2874e8f30b3a67af4defd8f73c503e794785671feeMakoto Onukiimport android.util.Log; 29078f588cef389358adabc579de00747878f3c108Dave Santoro 30078f588cef389358adabc579de00747878f3c108Dave Santoroimport java.util.ArrayList; 31078f588cef389358adabc579de00747878f3c108Dave Santoro 32078f588cef389358adabc579de00747878f3c108Dave Santoro/** 33078f588cef389358adabc579de00747878f3c108Dave Santoro * A common base class for the contacts and profile providers. This handles much of the same 34078f588cef389358adabc579de00747878f3c108Dave Santoro * logic that SQLiteContentProvider does (i.e. starting transactions on the appropriate database), 35078f588cef389358adabc579de00747878f3c108Dave Santoro * but exposes awareness of batch operations to the subclass so that cross-database operations 36078f588cef389358adabc579de00747878f3c108Dave Santoro * can be supported. 37078f588cef389358adabc579de00747878f3c108Dave Santoro */ 38078f588cef389358adabc579de00747878f3c108Dave Santoropublic abstract class AbstractContactsProvider extends ContentProvider 39078f588cef389358adabc579de00747878f3c108Dave Santoro implements SQLiteTransactionListener { 40078f588cef389358adabc579de00747878f3c108Dave Santoro 41ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public static final String TAG = "ContactsProvider"; 4274e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki 43ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 44ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 45ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki /** Set true to enable detailed transaction logging. */ 46ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public static final boolean ENABLE_TRANSACTION_LOG = false; // Don't submit with true. 4774e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki 48078f588cef389358adabc579de00747878f3c108Dave Santoro /** 49078f588cef389358adabc579de00747878f3c108Dave Santoro * Duration in ms to sleep after successfully yielding the lock during a batch operation. 50078f588cef389358adabc579de00747878f3c108Dave Santoro */ 51078f588cef389358adabc579de00747878f3c108Dave Santoro protected static final int SLEEP_AFTER_YIELD_DELAY = 4000; 52078f588cef389358adabc579de00747878f3c108Dave Santoro 53078f588cef389358adabc579de00747878f3c108Dave Santoro /** 54078f588cef389358adabc579de00747878f3c108Dave Santoro * Maximum number of operations allowed in a batch between yield points. 55078f588cef389358adabc579de00747878f3c108Dave Santoro */ 56078f588cef389358adabc579de00747878f3c108Dave Santoro private static final int MAX_OPERATIONS_PER_YIELD_POINT = 500; 57078f588cef389358adabc579de00747878f3c108Dave Santoro 58078f588cef389358adabc579de00747878f3c108Dave Santoro /** 59376917cea44aec4dfd68dec23522353b142535fdDave Santoro * Number of inserts performed in bulk to allow before yielding the transaction. 60376917cea44aec4dfd68dec23522353b142535fdDave Santoro */ 61376917cea44aec4dfd68dec23522353b142535fdDave Santoro private static final int BULK_INSERTS_PER_YIELD_POINT = 50; 62376917cea44aec4dfd68dec23522353b142535fdDave Santoro 63376917cea44aec4dfd68dec23522353b142535fdDave Santoro /** 64078f588cef389358adabc579de00747878f3c108Dave Santoro * The contacts transaction that is active in this thread. 65078f588cef389358adabc579de00747878f3c108Dave Santoro */ 666efb7db26598b105342d02207e0ca1c8725c10daDave Santoro private ThreadLocal<ContactsTransaction> mTransactionHolder; 67078f588cef389358adabc579de00747878f3c108Dave Santoro 68078f588cef389358adabc579de00747878f3c108Dave Santoro /** 69078f588cef389358adabc579de00747878f3c108Dave Santoro * The DB helper to use for this content provider. 70078f588cef389358adabc579de00747878f3c108Dave Santoro */ 71078f588cef389358adabc579de00747878f3c108Dave Santoro private SQLiteOpenHelper mDbHelper; 72078f588cef389358adabc579de00747878f3c108Dave Santoro 73078f588cef389358adabc579de00747878f3c108Dave Santoro /** 74078f588cef389358adabc579de00747878f3c108Dave Santoro * The database helper to serialize all transactions on. If non-null, any new transaction 75078f588cef389358adabc579de00747878f3c108Dave Santoro * created by this provider will automatically retrieve a writable database from this helper 76078f588cef389358adabc579de00747878f3c108Dave Santoro * and initiate a transaction on that database. This should be used to ensure that operations 77078f588cef389358adabc579de00747878f3c108Dave Santoro * across multiple databases are all blocked on a single DB lock (to prevent deadlock cases). 78ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 79ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * Hint: It's always {@link ContactsDatabaseHelper}. 80ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 81ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * TODO Change the structure to make it obvious that it's actually always set, and is the 82ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * {@link ContactsDatabaseHelper}. 83078f588cef389358adabc579de00747878f3c108Dave Santoro */ 84078f588cef389358adabc579de00747878f3c108Dave Santoro private SQLiteOpenHelper mSerializeOnDbHelper; 85078f588cef389358adabc579de00747878f3c108Dave Santoro 86078f588cef389358adabc579de00747878f3c108Dave Santoro /** 87078f588cef389358adabc579de00747878f3c108Dave Santoro * The tag corresponding to the database used for serializing transactions. 88ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 89ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * Hint: It's always the contacts db helper tag. 90ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 91ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * See also the TODO on {@link #mSerializeOnDbHelper}. 92078f588cef389358adabc579de00747878f3c108Dave Santoro */ 93078f588cef389358adabc579de00747878f3c108Dave Santoro private String mSerializeDbTag; 94078f588cef389358adabc579de00747878f3c108Dave Santoro 95ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki /** 96ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * The transaction listener used with {@link #mSerializeOnDbHelper}. 97ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 98ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * Hint: It's always {@link ContactsProvider2}. 99ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 100ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * See also the TODO on {@link #mSerializeOnDbHelper}. 101ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki */ 102ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private SQLiteTransactionListener mSerializedDbTransactionListener; 103ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 104078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 105078f588cef389358adabc579de00747878f3c108Dave Santoro public boolean onCreate() { 106078f588cef389358adabc579de00747878f3c108Dave Santoro Context context = getContext(); 107078f588cef389358adabc579de00747878f3c108Dave Santoro mDbHelper = getDatabaseHelper(context); 1086efb7db26598b105342d02207e0ca1c8725c10daDave Santoro mTransactionHolder = getTransactionHolder(); 109078f588cef389358adabc579de00747878f3c108Dave Santoro return true; 110078f588cef389358adabc579de00747878f3c108Dave Santoro } 111078f588cef389358adabc579de00747878f3c108Dave Santoro 112078f588cef389358adabc579de00747878f3c108Dave Santoro public SQLiteOpenHelper getDatabaseHelper() { 113078f588cef389358adabc579de00747878f3c108Dave Santoro return mDbHelper; 114078f588cef389358adabc579de00747878f3c108Dave Santoro } 115078f588cef389358adabc579de00747878f3c108Dave Santoro 116078f588cef389358adabc579de00747878f3c108Dave Santoro /** 117078f588cef389358adabc579de00747878f3c108Dave Santoro * Specifies a database helper (and corresponding tag) to serialize all transactions on. 118ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * 119ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki * See also the TODO on {@link #mSerializeOnDbHelper}. 120078f588cef389358adabc579de00747878f3c108Dave Santoro */ 121ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public void setDbHelperToSerializeOn(SQLiteOpenHelper serializeOnDbHelper, String tag, 122ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki SQLiteTransactionListener listener) { 123078f588cef389358adabc579de00747878f3c108Dave Santoro mSerializeOnDbHelper = serializeOnDbHelper; 124078f588cef389358adabc579de00747878f3c108Dave Santoro mSerializeDbTag = tag; 125ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mSerializedDbTransactionListener = listener; 126078f588cef389358adabc579de00747878f3c108Dave Santoro } 127078f588cef389358adabc579de00747878f3c108Dave Santoro 128078f588cef389358adabc579de00747878f3c108Dave Santoro public ContactsTransaction getCurrentTransaction() { 1296efb7db26598b105342d02207e0ca1c8725c10daDave Santoro return mTransactionHolder.get(); 130078f588cef389358adabc579de00747878f3c108Dave Santoro } 131078f588cef389358adabc579de00747878f3c108Dave Santoro 132078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 133078f588cef389358adabc579de00747878f3c108Dave Santoro public Uri insert(Uri uri, ContentValues values) { 134078f588cef389358adabc579de00747878f3c108Dave Santoro ContactsTransaction transaction = startTransaction(false); 135078f588cef389358adabc579de00747878f3c108Dave Santoro try { 136078f588cef389358adabc579de00747878f3c108Dave Santoro Uri result = insertInTransaction(uri, values); 137078f588cef389358adabc579de00747878f3c108Dave Santoro if (result != null) { 138078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markDirty(); 139078f588cef389358adabc579de00747878f3c108Dave Santoro } 140078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markSuccessful(false); 141078f588cef389358adabc579de00747878f3c108Dave Santoro return result; 142078f588cef389358adabc579de00747878f3c108Dave Santoro } finally { 143078f588cef389358adabc579de00747878f3c108Dave Santoro endTransaction(false); 144078f588cef389358adabc579de00747878f3c108Dave Santoro } 145078f588cef389358adabc579de00747878f3c108Dave Santoro } 146078f588cef389358adabc579de00747878f3c108Dave Santoro 147078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 148078f588cef389358adabc579de00747878f3c108Dave Santoro public int delete(Uri uri, String selection, String[] selectionArgs) { 149078f588cef389358adabc579de00747878f3c108Dave Santoro ContactsTransaction transaction = startTransaction(false); 150078f588cef389358adabc579de00747878f3c108Dave Santoro try { 151078f588cef389358adabc579de00747878f3c108Dave Santoro int deleted = deleteInTransaction(uri, selection, selectionArgs); 152078f588cef389358adabc579de00747878f3c108Dave Santoro if (deleted > 0) { 153078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markDirty(); 154078f588cef389358adabc579de00747878f3c108Dave Santoro } 155078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markSuccessful(false); 156078f588cef389358adabc579de00747878f3c108Dave Santoro return deleted; 157078f588cef389358adabc579de00747878f3c108Dave Santoro } finally { 158078f588cef389358adabc579de00747878f3c108Dave Santoro endTransaction(false); 159078f588cef389358adabc579de00747878f3c108Dave Santoro } 160078f588cef389358adabc579de00747878f3c108Dave Santoro } 161078f588cef389358adabc579de00747878f3c108Dave Santoro 162078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 163078f588cef389358adabc579de00747878f3c108Dave Santoro public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 164078f588cef389358adabc579de00747878f3c108Dave Santoro ContactsTransaction transaction = startTransaction(false); 165078f588cef389358adabc579de00747878f3c108Dave Santoro try { 166078f588cef389358adabc579de00747878f3c108Dave Santoro int updated = updateInTransaction(uri, values, selection, selectionArgs); 167078f588cef389358adabc579de00747878f3c108Dave Santoro if (updated > 0) { 168078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markDirty(); 169078f588cef389358adabc579de00747878f3c108Dave Santoro } 170078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markSuccessful(false); 171078f588cef389358adabc579de00747878f3c108Dave Santoro return updated; 172078f588cef389358adabc579de00747878f3c108Dave Santoro } finally { 173078f588cef389358adabc579de00747878f3c108Dave Santoro endTransaction(false); 174078f588cef389358adabc579de00747878f3c108Dave Santoro } 175078f588cef389358adabc579de00747878f3c108Dave Santoro } 176078f588cef389358adabc579de00747878f3c108Dave Santoro 177078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 178078f588cef389358adabc579de00747878f3c108Dave Santoro public int bulkInsert(Uri uri, ContentValues[] values) { 179078f588cef389358adabc579de00747878f3c108Dave Santoro ContactsTransaction transaction = startTransaction(true); 180078f588cef389358adabc579de00747878f3c108Dave Santoro int numValues = values.length; 181376917cea44aec4dfd68dec23522353b142535fdDave Santoro int opCount = 0; 182078f588cef389358adabc579de00747878f3c108Dave Santoro try { 183078f588cef389358adabc579de00747878f3c108Dave Santoro for (int i = 0; i < numValues; i++) { 184078f588cef389358adabc579de00747878f3c108Dave Santoro insert(uri, values[i]); 185376917cea44aec4dfd68dec23522353b142535fdDave Santoro if (++opCount >= BULK_INSERTS_PER_YIELD_POINT) { 186376917cea44aec4dfd68dec23522353b142535fdDave Santoro opCount = 0; 187b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro try { 188b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro yield(transaction); 189b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } catch (RuntimeException re) { 190b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro transaction.markYieldFailed(); 191b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro throw re; 192b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } 193376917cea44aec4dfd68dec23522353b142535fdDave Santoro } 194078f588cef389358adabc579de00747878f3c108Dave Santoro } 195078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markSuccessful(true); 196078f588cef389358adabc579de00747878f3c108Dave Santoro } finally { 197078f588cef389358adabc579de00747878f3c108Dave Santoro endTransaction(true); 198078f588cef389358adabc579de00747878f3c108Dave Santoro } 199078f588cef389358adabc579de00747878f3c108Dave Santoro return numValues; 200078f588cef389358adabc579de00747878f3c108Dave Santoro } 201078f588cef389358adabc579de00747878f3c108Dave Santoro 202078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 203078f588cef389358adabc579de00747878f3c108Dave Santoro public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 204078f588cef389358adabc579de00747878f3c108Dave Santoro throws OperationApplicationException { 20574e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki if (VERBOSE_LOGGING) { 20674e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki Log.v(TAG, "applyBatch: " + operations.size() + " ops"); 20774e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki } 208078f588cef389358adabc579de00747878f3c108Dave Santoro int ypCount = 0; 209078f588cef389358adabc579de00747878f3c108Dave Santoro int opCount = 0; 210078f588cef389358adabc579de00747878f3c108Dave Santoro ContactsTransaction transaction = startTransaction(true); 211078f588cef389358adabc579de00747878f3c108Dave Santoro try { 212078f588cef389358adabc579de00747878f3c108Dave Santoro final int numOperations = operations.size(); 213078f588cef389358adabc579de00747878f3c108Dave Santoro final ContentProviderResult[] results = new ContentProviderResult[numOperations]; 214078f588cef389358adabc579de00747878f3c108Dave Santoro for (int i = 0; i < numOperations; i++) { 215078f588cef389358adabc579de00747878f3c108Dave Santoro if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) { 216078f588cef389358adabc579de00747878f3c108Dave Santoro throw new OperationApplicationException( 217078f588cef389358adabc579de00747878f3c108Dave Santoro "Too many content provider operations between yield points. " 218078f588cef389358adabc579de00747878f3c108Dave Santoro + "The maximum number of operations per yield point is " 219078f588cef389358adabc579de00747878f3c108Dave Santoro + MAX_OPERATIONS_PER_YIELD_POINT, ypCount); 220078f588cef389358adabc579de00747878f3c108Dave Santoro } 221078f588cef389358adabc579de00747878f3c108Dave Santoro final ContentProviderOperation operation = operations.get(i); 222078f588cef389358adabc579de00747878f3c108Dave Santoro if (i > 0 && operation.isYieldAllowed()) { 22374e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki if (VERBOSE_LOGGING) { 22474e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki Log.v(TAG, "applyBatch: " + opCount + " ops finished; about to yield..."); 22574e8f30b3a67af4defd8f73c503e794785671feeMakoto Onuki } 226078f588cef389358adabc579de00747878f3c108Dave Santoro opCount = 0; 227b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro try { 228b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro if (yield(transaction)) { 229b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro ypCount++; 230b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } 231b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } catch (RuntimeException re) { 232b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro transaction.markYieldFailed(); 233b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro throw re; 234078f588cef389358adabc579de00747878f3c108Dave Santoro } 235078f588cef389358adabc579de00747878f3c108Dave Santoro } 236078f588cef389358adabc579de00747878f3c108Dave Santoro 237078f588cef389358adabc579de00747878f3c108Dave Santoro results[i] = operation.apply(this, results, i); 238078f588cef389358adabc579de00747878f3c108Dave Santoro } 239078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.markSuccessful(true); 240078f588cef389358adabc579de00747878f3c108Dave Santoro return results; 241078f588cef389358adabc579de00747878f3c108Dave Santoro } finally { 242078f588cef389358adabc579de00747878f3c108Dave Santoro endTransaction(true); 243078f588cef389358adabc579de00747878f3c108Dave Santoro } 244078f588cef389358adabc579de00747878f3c108Dave Santoro } 245078f588cef389358adabc579de00747878f3c108Dave Santoro 246078f588cef389358adabc579de00747878f3c108Dave Santoro /** 247078f588cef389358adabc579de00747878f3c108Dave Santoro * If we are not yet already in a transaction, this starts one (on the DB to serialize on, if 248078f588cef389358adabc579de00747878f3c108Dave Santoro * present) and sets the thread-local transaction variable for tracking. If we are already in 249078f588cef389358adabc579de00747878f3c108Dave Santoro * a transaction, this returns that transaction, and the batch parameter is ignored. 250078f588cef389358adabc579de00747878f3c108Dave Santoro * @param callerIsBatch Whether the caller is operating in batch mode. 251078f588cef389358adabc579de00747878f3c108Dave Santoro */ 252078f588cef389358adabc579de00747878f3c108Dave Santoro private ContactsTransaction startTransaction(boolean callerIsBatch) { 253ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 254ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "startTransaction " + getClass().getSimpleName() + 255ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki " callerIsBatch=" + callerIsBatch, new RuntimeException("startTransaction")); 256ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2576efb7db26598b105342d02207e0ca1c8725c10daDave Santoro ContactsTransaction transaction = mTransactionHolder.get(); 258078f588cef389358adabc579de00747878f3c108Dave Santoro if (transaction == null) { 259078f588cef389358adabc579de00747878f3c108Dave Santoro transaction = new ContactsTransaction(callerIsBatch); 260078f588cef389358adabc579de00747878f3c108Dave Santoro if (mSerializeOnDbHelper != null) { 261078f588cef389358adabc579de00747878f3c108Dave Santoro transaction.startTransactionForDb(mSerializeOnDbHelper.getWritableDatabase(), 262ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mSerializeDbTag, mSerializedDbTransactionListener); 263078f588cef389358adabc579de00747878f3c108Dave Santoro } 2646efb7db26598b105342d02207e0ca1c8725c10daDave Santoro mTransactionHolder.set(transaction); 265078f588cef389358adabc579de00747878f3c108Dave Santoro } 266078f588cef389358adabc579de00747878f3c108Dave Santoro return transaction; 267078f588cef389358adabc579de00747878f3c108Dave Santoro } 268078f588cef389358adabc579de00747878f3c108Dave Santoro 269078f588cef389358adabc579de00747878f3c108Dave Santoro /** 270078f588cef389358adabc579de00747878f3c108Dave Santoro * Ends the current transaction and clears out the member variable. This does not set the 271078f588cef389358adabc579de00747878f3c108Dave Santoro * transaction as being successful. 272078f588cef389358adabc579de00747878f3c108Dave Santoro * @param callerIsBatch Whether the caller is operating in batch mode. 273078f588cef389358adabc579de00747878f3c108Dave Santoro */ 274078f588cef389358adabc579de00747878f3c108Dave Santoro private void endTransaction(boolean callerIsBatch) { 275ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 276ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "endTransaction " + getClass().getSimpleName() + 277ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki " callerIsBatch=" + callerIsBatch, new RuntimeException("endTransaction")); 278ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2796efb7db26598b105342d02207e0ca1c8725c10daDave Santoro ContactsTransaction transaction = mTransactionHolder.get(); 280078f588cef389358adabc579de00747878f3c108Dave Santoro if (transaction != null && (!transaction.isBatch() || callerIsBatch)) { 281b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro try { 282b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro if (transaction.isDirty()) { 283b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro notifyChange(); 284b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } 285b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro transaction.finish(callerIsBatch); 286b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro } finally { 287b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro // No matter what, make sure we clear out the thread-local transaction reference. 288b91899a113c499ef96fe5719398558b4cfd128c2Dave Santoro mTransactionHolder.set(null); 289078f588cef389358adabc579de00747878f3c108Dave Santoro } 290078f588cef389358adabc579de00747878f3c108Dave Santoro } 291078f588cef389358adabc579de00747878f3c108Dave Santoro } 292078f588cef389358adabc579de00747878f3c108Dave Santoro 2936efb7db26598b105342d02207e0ca1c8725c10daDave Santoro /** 2946efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * Gets the database helper for this contacts provider. This is called once, during onCreate(). 2956efb7db26598b105342d02207e0ca1c8725c10daDave Santoro */ 2966efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected abstract SQLiteOpenHelper getDatabaseHelper(Context context); 2976efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 2986efb7db26598b105342d02207e0ca1c8725c10daDave Santoro /** 2996efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * Gets the thread-local transaction holder to use for keeping track of the transaction. This 3006efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * is called once, in onCreate(). If multiple classes are inheriting from this class that need 3016efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * to be kept in sync on the same transaction, they must all return the same thread-local. 3026efb7db26598b105342d02207e0ca1c8725c10daDave Santoro */ 3036efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected abstract ThreadLocal<ContactsTransaction> getTransactionHolder(); 3046efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 305078f588cef389358adabc579de00747878f3c108Dave Santoro protected abstract Uri insertInTransaction(Uri uri, ContentValues values); 306078f588cef389358adabc579de00747878f3c108Dave Santoro 307078f588cef389358adabc579de00747878f3c108Dave Santoro protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs); 308078f588cef389358adabc579de00747878f3c108Dave Santoro 309078f588cef389358adabc579de00747878f3c108Dave Santoro protected abstract int updateInTransaction(Uri uri, ContentValues values, String selection, 310078f588cef389358adabc579de00747878f3c108Dave Santoro String[] selectionArgs); 311078f588cef389358adabc579de00747878f3c108Dave Santoro 312078f588cef389358adabc579de00747878f3c108Dave Santoro protected abstract boolean yield(ContactsTransaction transaction); 313078f588cef389358adabc579de00747878f3c108Dave Santoro 314078f588cef389358adabc579de00747878f3c108Dave Santoro protected abstract void notifyChange(); 315078f588cef389358adabc579de00747878f3c108Dave Santoro} 316