1ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hupackage com.android.emailcommon.provider; 2ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 3ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport android.content.ContentResolver; 4ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport android.content.ContentValues; 5ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport android.database.Cursor; 6ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport android.net.Uri; 7ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 8ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu/** 9ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * {@link EmailContent}-like base class for change log tables. 10ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Accounts that upsync message changes require a change log to track local changes between upsyncs. 11ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * A single instance of this class (or subclass) represents one change to upsync to the server. 12ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * This object may actually correspond to multiple rows in the table. 13ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * This class (and subclasses) also contains constants for the table columns and values stored in 14ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * the DB. The base class contains the ones common to all change logs. 15ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 16ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hupublic abstract class MessageChangeLogTable { 17ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 18ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu // DB columns. Note that this class (and subclasses) use some denormalized columns 19ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu // (e.g. accountKey) for simplicity at query time and debugging ease. 20ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Column name for the row key; this is an autoincrement key. */ 21ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String ID = "_id"; 22ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Column name for a foreign key into Message for the message that's moving. */ 23ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String MESSAGE_KEY = "messageKey"; 24ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Column name for the server-side id for messageKey. */ 25ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String SERVER_ID = "messageServerId"; 26ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Column name for a foreign key into Account for the message that's moving. */ 27ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String ACCOUNT_KEY = "accountKey"; 28ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Column name for a status value indicating where we are with processing this move request. */ 29ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String STATUS = "status"; 30ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 31ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu // Status values. 32ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Status value indicating this move has not yet been unpsynced. */ 33ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final int STATUS_NONE = 0; 34ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String STATUS_NONE_STRING = String.valueOf(STATUS_NONE); 35ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Status value indicating this move is being upsynced right now. */ 36ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final int STATUS_PROCESSING = 1; 37ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final String STATUS_PROCESSING_STRING = String.valueOf(STATUS_PROCESSING); 38ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Status value indicating this move failed to upsync. */ 39ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public static final int STATUS_FAILED = 2; 40e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu public static final String STATUS_FAILED_STRING = String.valueOf(STATUS_FAILED); 41ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 42ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Selection string for querying this table. */ 43ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String SELECTION_BY_ACCOUNT_KEY_AND_STATUS = 44ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu ACCOUNT_KEY + "=? and " + STATUS + "=?"; 45ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 46ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** Selection string prefix for deleting moves for a set of messages. */ 47ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String SELECTION_BY_MESSAGE_KEYS_PREFIX = MESSAGE_KEY + " in ("; 48ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 49ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected final long mMessageKey; 50ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected final String mServerId; 51ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected long mLastId; 52ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 53ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected MessageChangeLogTable(final long messageKey, final String serverId, final long id) { 54ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu mMessageKey = messageKey; 55ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu mServerId = serverId; 56ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu mLastId = id; 57ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 58ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 59ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public final long getMessageId() { 60ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return mMessageKey; 61ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 62ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 63ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu public final String getServerId() { 64ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return mServerId; 65ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 66ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 67ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 68ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Update status of all change entries for an account: 69ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * - {@link #STATUS_NONE} -> {@link #STATUS_PROCESSING} 70ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * - {@link #STATUS_PROCESSING} -> {@link #STATUS_FAILED} 71ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 72ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The content uri for this table. 73ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param accountId The account we want to update. 74ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The number of change entries that are now in {@link #STATUS_PROCESSING}. 75ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 76ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static int startProcessing(final ContentResolver cr, final Uri uri, 77ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String accountId) { 78ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String[] args = new String[2]; 79ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu args[0] = accountId; 80ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final ContentValues cv = new ContentValues(1); 81ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 82ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu // First mark anything that's still processing as failed. 83ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu args[1] = STATUS_PROCESSING_STRING; 84ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu cv.put(STATUS, STATUS_FAILED); 85ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu cr.update(uri, cv, SELECTION_BY_ACCOUNT_KEY_AND_STATUS, args); 86ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 87ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu // Now mark all unprocessed messages as processing. 88ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu args[1] = STATUS_NONE_STRING; 89ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu cv.put(STATUS, STATUS_PROCESSING); 90ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return cr.update(uri, cv, SELECTION_BY_ACCOUNT_KEY_AND_STATUS, args); 91ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 92ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 93ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 94ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Query for all move records that are in {@link #STATUS_PROCESSING}. 95ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Note that this function assumes the underlying table uses an autoincrement id key: it assumes 96ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * that ascending id is the same as chronological order. 97ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 98ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The content uri for this table. 99ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param projection The projection to use for this query. 100ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param accountId The account we want to update. 101ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return A {@link android.database.Cursor} containing all rows, in id order. 102ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 103ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static Cursor getRowsToProcess(final ContentResolver cr, final Uri uri, 104ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String[] projection, final String accountId) { 105ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String[] args = { accountId, STATUS_PROCESSING_STRING }; 106ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return cr.query(uri, projection, SELECTION_BY_ACCOUNT_KEY_AND_STATUS, args, ID + " ASC"); 107ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 108ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 109ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 110ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Create a selection string for all messages in a set. 111ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageKeys The set of messages we're interested in. 112ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param count The number of messages we're interested in. 113ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The selection string for these messages. 114ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 115ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static String getSelectionForMessages(final long[] messageKeys, final int count) { 116ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final StringBuilder sb = new StringBuilder(SELECTION_BY_MESSAGE_KEYS_PREFIX); 117ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu for (int i = 0; i < count; ++i) { 118ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu if (i != 0) { 119ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sb.append(","); 120ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 121ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sb.append(messageKeys[i]); 122ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 123ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sb.append(")"); 124ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return sb.toString(); 125ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 126ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 127ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 128ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Delete all rows for a set of messages. Used to clear no-op changes (i.e. multiple rows for 129ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * a message that reverts it to the original state) and after successful upsync. 130ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 131ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The content uri for this table. 132ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageKeys The messages to clear. 133ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param count The number of message keys. 134ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The number of rows deleted from the DB. 135ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 136ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected static int deleteRowsForMessages(final ContentResolver cr, final Uri uri, 137ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long[] messageKeys, final int count) { 138ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu if (count == 0) { 139ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return 0; 140ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 141ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return cr.delete(uri, getSelectionForMessages(messageKeys, count), null); 142ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 143ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 144ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 145ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Set the status value for a set of messages. 146ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 147ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The {@link Uri} for the update. 148ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageKeys The messages to update. 149ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param count The number of messageKeys. 150ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param status The new status value for the messages. 151ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The number of rows updated. 152ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 153ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static int updateStatusForMessages(final ContentResolver cr, final Uri uri, 154ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long[] messageKeys, final int count, final int status) { 155ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu if (count == 0) { 156ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return 0; 157ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 158ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final ContentValues cv = new ContentValues(1); 159ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu cv.put(STATUS, status); 160ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return cr.update(uri, cv, getSelectionForMessages(messageKeys, count), null); 161ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 162ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 163ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 164ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Set a set of messages to status = retry. 165ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 166ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The {@link Uri} for the update. 167ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageKeys The messages to update. 168ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param count The number of messageKeys. 169ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The number of rows updated. 170ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 171ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected static int retryMessages(final ContentResolver cr, final Uri uri, 172ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long[] messageKeys, final int count) { 173ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return updateStatusForMessages(cr, uri, messageKeys, count, STATUS_NONE); 174ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 175ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 176ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 177ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Set a set of messages to status = failed. 178ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 179ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The {@link Uri} for the update. 180ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageKeys The messages to update. 181ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param count The number of messageKeys. 182ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return The number of rows updated. 183ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 184ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected static int failMessages(final ContentResolver cr, final Uri uri, 185ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long[] messageKeys, final int count) { 186ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return updateStatusForMessages(cr, uri, messageKeys, count, STATUS_FAILED); 187ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 188ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 189ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 190ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Start processing our table and get a {@link Cursor} for the rows to process. 191ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param cr A {@link ContentResolver}. 192ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param uri The {@link Uri} for the update. 193ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param projection The projection to use for our read. 194ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param accountId The account we're interested in. 195ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @return A {@link Cursor} with the change log rows we're interested in. 196ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 197ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu protected static Cursor getCursor(final ContentResolver cr, final Uri uri, 198ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String[] projection, final long accountId) { 199ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final String accountIdString = String.valueOf(accountId); 200ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu if (startProcessing(cr, uri, accountIdString) <= 0) { 201ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return null; 202ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 203ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return getRowsToProcess(cr, uri, projection, accountIdString); 204ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 205ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu} 206