diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java index 700f1d88241c1..55885134de84c 100644 --- a/core/java/android/content/AbstractTableMerger.java +++ b/core/java/android/content/AbstractTableMerger.java @@ -164,304 +164,301 @@ public abstract class AbstractTableMerger mDb.update(mDeletedTable, mSyncMarkValues, null, null); } - // load the local database entries, so we can merge them with the server - final String[] accountSelectionArgs = new String[]{account}; - Cursor localCursor = mDb.query(mTable, syncDirtyProjection, - SELECT_MARKED, accountSelectionArgs, null, null, - mTable + "." + _SYNC_ID); - Cursor deletedCursor; - if (mDeletedTable != null) { - deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection, + Cursor localCursor = null; + Cursor deletedCursor = null; + Cursor diffsCursor = null; + try { + // load the local database entries, so we can merge them with the server + final String[] accountSelectionArgs = new String[]{account}; + localCursor = mDb.query(mTable, syncDirtyProjection, SELECT_MARKED, accountSelectionArgs, null, null, - mDeletedTable + "." + _SYNC_ID); - } else { - deletedCursor = - mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null); - } - - // Apply updates and insertions from the server - Cursor diffsCursor = serverDiffs.query(mTableURL, - null, null, null, mTable + "." + _SYNC_ID); - int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID); - int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION); - int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID); - int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION); - int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID); - - String lastSyncId = null; - int diffsCount = 0; - int localCount = 0; - localCursor.moveToFirst(); - deletedCursor.moveToFirst(); - while (diffsCursor.moveToNext()) { - if (mIsMergeCancelled) { - localCursor.close(); - deletedCursor.close(); - diffsCursor.close(); - return; - } - mDb.yieldIfContended(); - String serverSyncId = diffsCursor.getString(serverSyncIDColumn); - String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn); - long localRowId = 0; - String localSyncVersion = null; - - diffsCount++; - context.setStatusText("Processing " + diffsCount + "/" - + diffsCursor.getCount()); - if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " + - diffsCount + ", " + serverSyncId); - - if (TRACE) { - if (diffsCount == 10) { - Debug.startMethodTracing("atmtrace"); - } - if (diffsCount == 20) { - Debug.stopMethodTracing(); - } + mTable + "." + _SYNC_ID); + if (mDeletedTable != null) { + deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection, + SELECT_MARKED, accountSelectionArgs, null, null, + mDeletedTable + "." + _SYNC_ID); + } else { + deletedCursor = + mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null); } - boolean conflict = false; - boolean update = false; - boolean insert = false; + // Apply updates and insertions from the server + diffsCursor = serverDiffs.query(mTableURL, + null, null, null, mTable + "." + _SYNC_ID); + int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID); + int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION); + int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID); + int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION); + int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID); + + String lastSyncId = null; + int diffsCount = 0; + int localCount = 0; + localCursor.moveToFirst(); + deletedCursor.moveToFirst(); + while (diffsCursor.moveToNext()) { + if (mIsMergeCancelled) { + return; + } + mDb.yieldIfContended(); + String serverSyncId = diffsCursor.getString(serverSyncIDColumn); + String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn); + long localRowId = 0; + String localSyncVersion = null; + + diffsCount++; + context.setStatusText("Processing " + diffsCount + "/" + + diffsCursor.getCount()); + if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " + + diffsCount + ", " + serverSyncId); + + if (TRACE) { + if (diffsCount == 10) { + Debug.startMethodTracing("atmtrace"); + } + if (diffsCount == 20) { + Debug.stopMethodTracing(); + } + } + + boolean conflict = false; + boolean update = false; + boolean insert = false; + + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "found event with serverSyncID " + serverSyncId); + } + if (TextUtils.isEmpty(serverSyncId)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.e(TAG, "server entry doesn't have a serverSyncID"); + } + continue; + } + + // It is possible that the sync adapter wrote the same record multiple times, + // e.g. if the same record came via multiple feeds. If this happens just ignore + // the duplicate records. + if (serverSyncId.equals(lastSyncId)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId); + } + continue; + } + lastSyncId = serverSyncId; + + String localSyncID = null; + boolean localSyncDirty = false; + + while (!localCursor.isAfterLast()) { + if (mIsMergeCancelled) { + return; + } + localCount++; + localSyncID = localCursor.getString(2); + + // If the local record doesn't have a _sync_id then + // it is new. Ignore it for now, we will send an insert + // the the server later. + if (TextUtils.isEmpty(localSyncID)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "local record " + + localCursor.getLong(1) + + " has no _sync_id, ignoring"); + } + localCursor.moveToNext(); + localSyncID = null; + continue; + } + + int comp = serverSyncId.compareTo(localSyncID); + + // the local DB has a record that the server doesn't have + if (comp > 0) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "local record " + + localCursor.getLong(1) + + " has _sync_id " + localSyncID + + " that is < server _sync_id " + serverSyncId); + } + if (diffsArePartial) { + localCursor.moveToNext(); + } else { + deleteRow(localCursor); + if (mDeletedTable != null) { + mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID}); + } + syncResult.stats.numDeletes++; + mDb.yieldIfContended(); + } + localSyncID = null; + continue; + } + + // the server has a record that the local DB doesn't have + if (comp < 0) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "local record " + + localCursor.getLong(1) + + " has _sync_id " + localSyncID + + " that is > server _sync_id " + serverSyncId); + } + localSyncID = null; + } + + // the server and the local DB both have this record + if (comp == 0) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "local record " + + localCursor.getLong(1) + + " has _sync_id " + localSyncID + + " that matches the server _sync_id"); + } + localSyncDirty = localCursor.getInt(0) != 0; + localRowId = localCursor.getLong(1); + localSyncVersion = localCursor.getString(3); + localCursor.moveToNext(); + } + + break; + } + + // If this record is in the deleted table then update the server version + // in the deleted table, if necessary, and then ignore it here. + // We will send a deletion indication to the server down a + // little further. + if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table"); + } + final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn); + if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "setting version of deleted record " + serverSyncId + " to " + + serverSyncVersion); + } + ContentValues values = new ContentValues(); + values.put(_SYNC_VERSION, serverSyncVersion); + mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId}); + } + continue; + } + + // If the _sync_local_id is present in the diffsCursor + // then this record corresponds to a local record that was just + // inserted into the server and the _sync_local_id is the row id + // of the local record. Set these fields so that the next check + // treats this record as an update, which will allow the + // merger to update the record with the server's sync id + if (!diffsCursor.isNull(serverSyncLocalIdColumn)) { + localRowId = diffsCursor.getLong(serverSyncLocalIdColumn); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "the remote record with sync id " + serverSyncId + + " has a local sync id, " + localRowId); + } + localSyncID = serverSyncId; + localSyncDirty = false; + localSyncVersion = null; + } + + if (!TextUtils.isEmpty(localSyncID)) { + // An existing server item has changed + boolean recordChanged = (localSyncVersion == null) || + !serverSyncVersion.equals(localSyncVersion); + if (recordChanged) { + if (localSyncDirty) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "remote record " + serverSyncId + + " conflicts with local _sync_id " + localSyncID + + ", local _id " + localRowId); + } + conflict = true; + } else { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, + "remote record " + + serverSyncId + + " updates local _sync_id " + + localSyncID + ", local _id " + + localRowId); + } + update = true; + } + } + } else { + // the local db doesn't know about this record so add it + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "remote record " + serverSyncId + " is new, inserting"); + } + insert = true; + } + + if (update) { + updateRow(localRowId, serverDiffs, diffsCursor); + syncResult.stats.numUpdates++; + } else if (conflict) { + resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor); + syncResult.stats.numUpdates++; + } else if (insert) { + insertRow(serverDiffs, diffsCursor); + syncResult.stats.numInserts++; + } + } if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "found event with serverSyncID " + serverSyncId); - } - if (TextUtils.isEmpty(serverSyncId)) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.e(TAG, "server entry doesn't have a serverSyncID"); - } - continue; + Log.v(TAG, "processed " + diffsCount + " server entries"); } - // It is possible that the sync adapter wrote the same record multiple times, - // e.g. if the same record came via multiple feeds. If this happens just ignore - // the duplicate records. - if (serverSyncId.equals(lastSyncId)) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId); - } - continue; - } - lastSyncId = serverSyncId; - - String localSyncID = null; - boolean localSyncDirty = false; - - while (!localCursor.isAfterLast()) { - if (mIsMergeCancelled) { - localCursor.deactivate(); - deletedCursor.deactivate(); - diffsCursor.deactivate(); - return; - } - localCount++; - localSyncID = localCursor.getString(2); - - // If the local record doesn't have a _sync_id then - // it is new. Ignore it for now, we will send an insert - // the the server later. - if (TextUtils.isEmpty(localSyncID)) { + // If tombstones aren't in use delete any remaining local rows that + // don't have corresponding server rows. Keep the rows that don't + // have a sync id since those were created locally and haven't been + // synced to the server yet. + if (!diffsArePartial) { + while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) { + if (mIsMergeCancelled) { + return; + } + localCount++; + final String localSyncId = localCursor.getString(2); if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "local record " + - localCursor.getLong(1) + - " has no _sync_id, ignoring"); + Log.v(TAG, + "deleting local record " + + localCursor.getLong(1) + + " _sync_id " + localSyncId); } - localCursor.moveToNext(); - localSyncID = null; - continue; + deleteRow(localCursor); + if (mDeletedTable != null) { + mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId}); + } + syncResult.stats.numDeletes++; + mDb.yieldIfContended(); } - - int comp = serverSyncId.compareTo(localSyncID); - - // the local DB has a record that the server doesn't have - if (comp > 0) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "local record " + - localCursor.getLong(1) + - " has _sync_id " + localSyncID + - " that is < server _sync_id " + serverSyncId); - } - if (diffsArePartial) { - localCursor.moveToNext(); - } else { - deleteRow(localCursor); - if (mDeletedTable != null) { - mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID}); - } - syncResult.stats.numDeletes++; - mDb.yieldIfContended(); - } - localSyncID = null; - continue; - } - - // the server has a record that the local DB doesn't have - if (comp < 0) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "local record " + - localCursor.getLong(1) + - " has _sync_id " + localSyncID + - " that is > server _sync_id " + serverSyncId); - } - localSyncID = null; - } - - // the server and the local DB both have this record - if (comp == 0) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "local record " + - localCursor.getLong(1) + - " has _sync_id " + localSyncID + - " that matches the server _sync_id"); - } - localSyncDirty = localCursor.getInt(0) != 0; - localRowId = localCursor.getLong(1); - localSyncVersion = localCursor.getString(3); - localCursor.moveToNext(); - } - - break; - } - - // If this record is in the deleted table then update the server version - // in the deleted table, if necessary, and then ignore it here. - // We will send a deletion indication to the server down a - // little further. - if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table"); - } - final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn); - if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "setting version of deleted record " + serverSyncId + " to " - + serverSyncVersion); - } - ContentValues values = new ContentValues(); - values.put(_SYNC_VERSION, serverSyncVersion); - mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId}); - } - continue; - } - - // If the _sync_local_id is present in the diffsCursor - // then this record corresponds to a local record that was just - // inserted into the server and the _sync_local_id is the row id - // of the local record. Set these fields so that the next check - // treats this record as an update, which will allow the - // merger to update the record with the server's sync id - if (!diffsCursor.isNull(serverSyncLocalIdColumn)) { - localRowId = diffsCursor.getLong(serverSyncLocalIdColumn); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "the remote record with sync id " + serverSyncId - + " has a local sync id, " + localRowId); - } - localSyncID = serverSyncId; - localSyncDirty = false; - localSyncVersion = null; - } - - if (!TextUtils.isEmpty(localSyncID)) { - // An existing server item has changed - boolean recordChanged = (localSyncVersion == null) || - !serverSyncVersion.equals(localSyncVersion); - if (recordChanged) { - if (localSyncDirty) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "remote record " + serverSyncId - + " conflicts with local _sync_id " + localSyncID - + ", local _id " + localRowId); - } - conflict = true; - } else { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, - "remote record " + - serverSyncId + - " updates local _sync_id " + - localSyncID + ", local _id " + - localRowId); - } - update = true; - } - } - } else { - // the local db doesn't know about this record so add it - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "remote record " + serverSyncId + " is new, inserting"); - } - insert = true; - } - - if (update) { - updateRow(localRowId, serverDiffs, diffsCursor); - syncResult.stats.numUpdates++; - } else if (conflict) { - resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor); - syncResult.stats.numUpdates++; - } else if (insert) { - insertRow(serverDiffs, diffsCursor); - syncResult.stats.numInserts++; } + if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount + + " local entries"); + } finally { + if (diffsCursor != null) diffsCursor.close(); + if (localCursor != null) localCursor.close(); + if (deletedCursor != null) deletedCursor.close(); } - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "processed " + diffsCount + " server entries"); - } - - // If tombstones aren't in use delete any remaining local rows that - // don't have corresponding server rows. Keep the rows that don't - // have a sync id since those were created locally and haven't been - // synced to the server yet. - if (!diffsArePartial) { - while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) { - if (mIsMergeCancelled) { - localCursor.deactivate(); - deletedCursor.deactivate(); - diffsCursor.deactivate(); - return; - } - localCount++; - final String localSyncId = localCursor.getString(2); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, - "deleting local record " + - localCursor.getLong(1) + - " _sync_id " + localSyncId); - } - deleteRow(localCursor); - if (mDeletedTable != null) { - mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId}); - } - syncResult.stats.numDeletes++; - mDb.yieldIfContended(); - } - } - - if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount + - " local entries"); - diffsCursor.deactivate(); - localCursor.deactivate(); - deletedCursor.deactivate(); if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "applying deletions from the server"); // Apply deletions from the server if (mDeletedTableURL != null) { diffsCursor = serverDiffs.query(mDeletedTableURL, null, null, null, null); - - while (diffsCursor.moveToNext()) { - if (mIsMergeCancelled) { - diffsCursor.deactivate(); - return; + try { + while (diffsCursor.moveToNext()) { + if (mIsMergeCancelled) { + return; + } + // delete all rows that match each element in the diffsCursor + fullyDeleteMatchingRows(diffsCursor, account, syncResult); + mDb.yieldIfContended(); } - // delete all rows that match each element in the diffsCursor - fullyDeleteMatchingRows(diffsCursor, account, syncResult); - mDb.yieldIfContended(); + } finally { + diffsCursor.close(); } - diffsCursor.deactivate(); } } @@ -471,26 +468,26 @@ public abstract class AbstractTableMerger final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn); // delete the rows explicitly so that the delete operation can be overridden - final Cursor c; final String[] selectionArgs; - if (deleteBySyncId) { - selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account}; - c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT, - selectionArgs, null, null, null); - } else { - int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID); - selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)}; - c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs, - null, null, null); - } + Cursor c = null; try { + if (deleteBySyncId) { + selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account}; + c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT, + selectionArgs, null, null, null); + } else { + int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID); + selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)}; + c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs, + null, null, null); + } c.moveToFirst(); while (!c.isAfterLast()) { deleteRow(c); // advances the cursor syncResult.stats.numDeletes++; } } finally { - c.deactivate(); + if (c != null) c.close(); } if (deleteBySyncId && mDeletedTable != null) { mDb.delete(mDeletedTable, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs); @@ -526,25 +523,28 @@ public abstract class AbstractTableMerger // Generate the client updates and insertions // Create a cursor for dirty records + long numInsertsOrUpdates = 0; Cursor localChangesCursor = mDb.query(mTable, null, SELECT_UNSYNCED, accountSelectionArgs, null, null, null); - long numInsertsOrUpdates = localChangesCursor.getCount(); - while (localChangesCursor.moveToNext()) { - if (mIsMergeCancelled) { - localChangesCursor.close(); - return; + try { + numInsertsOrUpdates = localChangesCursor.getCount(); + while (localChangesCursor.moveToNext()) { + if (mIsMergeCancelled) { + return; + } + if (clientDiffs == null) { + clientDiffs = temporaryInstanceFactory.getTemporaryInstance(); + } + mValues.clear(); + cursorRowToContentValues(localChangesCursor, mValues); + mValues.remove("_id"); + DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues, + _SYNC_LOCAL_ID); + clientDiffs.insert(mTableURL, mValues); } - if (clientDiffs == null) { - clientDiffs = temporaryInstanceFactory.getTemporaryInstance(); - } - mValues.clear(); - cursorRowToContentValues(localChangesCursor, mValues); - mValues.remove("_id"); - DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues, - _SYNC_LOCAL_ID); - clientDiffs.insert(mTableURL, mValues); + } finally { + localChangesCursor.close(); } - localChangesCursor.close(); // Generate the client deletions if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client deletions"); @@ -555,21 +555,22 @@ public abstract class AbstractTableMerger syncIdAndVersionProjection, _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs, null, null, mDeletedTable + "." + _SYNC_ID); - - numDeletedEntries = deletedCursor.getCount(); - while (deletedCursor.moveToNext()) { - if (mIsMergeCancelled) { - deletedCursor.close(); - return; + try { + numDeletedEntries = deletedCursor.getCount(); + while (deletedCursor.moveToNext()) { + if (mIsMergeCancelled) { + return; + } + if (clientDiffs == null) { + clientDiffs = temporaryInstanceFactory.getTemporaryInstance(); + } + mValues.clear(); + DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues); + clientDiffs.insert(mDeletedTableURL, mValues); } - if (clientDiffs == null) { - clientDiffs = temporaryInstanceFactory.getTemporaryInstance(); - } - mValues.clear(); - DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues); - clientDiffs.insert(mDeletedTableURL, mValues); + } finally { + deletedCursor.close(); } - deletedCursor.close(); } if (clientDiffs != null) { diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 10f3806d0ec9d..78ef3743f62b4 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -211,7 +211,7 @@ public class DatabaseUtils { sb.append(sqlString); sb.append('\''); } - + /** * SQL-escape a string. */ @@ -240,7 +240,7 @@ public class DatabaseUtils { appendEscapedSQLString(sql, value.toString()); } } - + /** * Concatenates two SQL WHERE clauses, handling empty or null values. * @hide @@ -252,12 +252,12 @@ public class DatabaseUtils { if (TextUtils.isEmpty(b)) { return a; } - + return "(" + a + ") AND (" + b + ")"; } - + /** - * return the collation key + * return the collation key * @param name * @return the collation key */ @@ -269,7 +269,7 @@ public class DatabaseUtils { return ""; } } - + /** * return the collation key in hex format * @param name @@ -280,7 +280,7 @@ public class DatabaseUtils { char[] keys = Hex.encodeHex(arr); return new String(keys, 0, getKeyLen(arr) * 2); } - + private static int getKeyLen(byte[] arr) { if (arr[arr.length - 1] != 0) { return arr.length; @@ -289,16 +289,16 @@ public class DatabaseUtils { return arr.length-1; } } - + private static byte[] getCollationKeyInBytes(String name) { if (mColl == null) { mColl = Collator.getInstance(); mColl.setStrength(Collator.PRIMARY); } - return mColl.getCollationKey(name).toByteArray(); + return mColl.getCollationKey(name).toByteArray(); } - - private static Collator mColl = null; + + private static Collator mColl = null; /** * Prints the contents of a Cursor to System.out. The position is restored * after printing. @@ -591,10 +591,12 @@ public class DatabaseUtils { public static long queryNumEntries(SQLiteDatabase db, String table) { Cursor cursor = db.query(table, countProjection, null, null, null, null, null); - cursor.moveToFirst(); - long count = cursor.getLong(0); - cursor.deactivate(); - return count; + try { + cursor.moveToFirst(); + return cursor.getLong(0); + } finally { + cursor.close(); + } } /** diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java index df599c7cfa1d3..8268fee0cb0f6 100644 --- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java +++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java @@ -155,14 +155,17 @@ public class SubscribedFeedsIntentService extends IntentService { ContentResolver contentResolver = context.getContentResolver(); Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI, sAccountProjection, null, null, null); - while (c.moveToNext()) { - String account = c.getString(0); - if (TextUtils.isEmpty(account)) { - continue; + try { + while (c.moveToNext()) { + String account = c.getString(0); + if (TextUtils.isEmpty(account)) { + continue; + } + accounts.add(account); } - accounts.add(account); + } finally { + c.close(); } - c.deactivate(); // Clear the auth tokens for all these accounts so that we are sure // they will still be valid until the next time we refresh them.