Merge "Adding DELETED column to SMS raw table to support message de-duping." into nyc-dev
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index 5956d33..748a703 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -28,7 +28,7 @@
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.FullBackupDataOutput;
-import android.content.ContentProvider;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
@@ -39,6 +39,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.provider.BaseColumns;
 import android.provider.Telephony;
 import android.telephony.PhoneNumberUtils;
@@ -224,8 +225,9 @@
 
     // Maximum messages for one backup file. After reaching the limit the agent backs up the file,
     // deletes it and creates a new one with the same name.
+    // Not final for the testing.
     @VisibleForTesting
-    static int MAX_MSG_PER_FILE = 1000;
+    int mMaxMsgPerFile = 1000;
 
 
     // Default values for SMS, MMS, Addresses restore.
@@ -263,23 +265,19 @@
     }
 
 
-    private final SparseArray<String> subId2phone = new SparseArray<String>();
+    private SparseArray<String> mSubId2phone = new SparseArray<String>();
+    private Map<String, Integer> mPhone2subId = new ArrayMap<String, Integer>();
 
-    // It's static cause it's used by DeferredSmsMmsRestoreService.
-    private static final Map<String, Integer> sPhone2subId = new ArrayMap<String, Integer>();
-    private ContentProvider mSmsProvider;
-    private ContentProvider mMmsProvider;
-    private ContentProvider mMmsSmsProvider;
-
+    private ContentResolver mContentResolver;
     // How many bytes we can backup to fit into quota.
     private long mBytesOverQuota;
 
     // Cache list of recipients by threadId. It reduces db requests heavily. Used during backup.
     @VisibleForTesting
-    static Map<Long, List<String>> sCacheRecipientsByThread;
+    Map<Long, List<String>> mCacheRecipientsByThread = null;
     // Cache threadId by list of recipients. Used during restore.
     @VisibleForTesting
-    static Map<Set<String>, Long> sCacheGetOrCreateThreadId;
+    Map<Set<String>, Long> mCacheGetOrCreateThreadId = null;
 
     @Override
     public void onCreate() {
@@ -292,35 +290,22 @@
             if (subInfo != null) {
                 for (SubscriptionInfo sub : subInfo) {
                     final String phoneNumber = getNormalizedNumber(sub);
-                    subId2phone.append(sub.getSubscriptionId(), phoneNumber);
-                    sPhone2subId.put(phoneNumber, sub.getSubscriptionId());
+                    mSubId2phone.append(sub.getSubscriptionId(), phoneNumber);
+                    mPhone2subId.put(phoneNumber, sub.getSubscriptionId());
                 }
             }
         }
-
-        mSmsProvider = new SmsProvider();
-        mSmsProvider.attachInfo(this, null);
-        mSmsProvider.onCreate();
-
-        mMmsProvider = new MmsProvider();
-        mMmsProvider.attachInfo(this, null);
-        mMmsProvider.onCreate();
-
-        mMmsSmsProvider = new MmsSmsProvider();
-        mMmsSmsProvider.attachInfo(this, null);
-        mMmsSmsProvider.onCreate();
-
-        sCacheRecipientsByThread = null;
-        sCacheGetOrCreateThreadId = null;
+        mContentResolver = getContentResolver();
     }
 
     @VisibleForTesting
-    void setProviders(ContentProvider smsProvider,
-                      ContentProvider mmsProvider,
-                      ContentProvider mmsSmsProvider) {
-        mSmsProvider = smsProvider;
-        mMmsProvider = mmsProvider;
-        mMmsSmsProvider = mmsSmsProvider;
+    void setContentResolver(ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+    }
+    @VisibleForTesting
+    void setSubId(SparseArray<String> subId2Phone, Map<String, Integer> phone2subId) {
+        mSubId2phone = subId2Phone;
+        mPhone2subId = phone2subId;
     }
 
     @Override
@@ -338,10 +323,10 @@
         }
 
         try (
-                Cursor smsCursor = mSmsProvider.query(Telephony.Sms.CONTENT_URI, SMS_PROJECTION,
+                Cursor smsCursor = mContentResolver.query(Telephony.Sms.CONTENT_URI, SMS_PROJECTION,
                         null, null, ORDER_BY_DATE);
                 // Do not backup non text-only MMS's.
-                Cursor mmsCursor = mMmsProvider.query(Telephony.Mms.CONTENT_URI, MMS_PROJECTION,
+                Cursor mmsCursor = mContentResolver.query(Telephony.Mms.CONTENT_URI, MMS_PROJECTION,
                         Telephony.Mms.TEXT_ONLY+"=1", null, ORDER_BY_DATE)) {
 
             if (smsCursor != null) {
@@ -415,41 +400,35 @@
         int messagesWritten = 0;
         try (JsonWriter jsonWriter = getJsonWriter(fileName)) {
             if (fileName.endsWith(SMS_BACKUP_FILE_SUFFIX)) {
-                messagesWritten = putSmsMessagesToJson(cursor, mMmsSmsProvider,
-                        subId2phone, jsonWriter, MAX_MSG_PER_FILE);
+                messagesWritten = putSmsMessagesToJson(cursor, jsonWriter);
             } else {
-                messagesWritten = putMmsMessagesToJson(cursor, mMmsProvider,
-                        mMmsSmsProvider, subId2phone, jsonWriter, MAX_MSG_PER_FILE);
+                messagesWritten = putMmsMessagesToJson(cursor, jsonWriter);
             }
         }
         backupFile(messagesWritten, fileName, data);
     }
 
     @VisibleForTesting
-    static int putMmsMessagesToJson(Cursor cursor, ContentProvider mmsProvider,
-                                    ContentProvider threadProvider,
-                                    SparseArray<String> subId2phone, JsonWriter jsonWriter,
-                                    int maxMsgPerFile) throws IOException {
+    int putMmsMessagesToJson(Cursor cursor,
+                             JsonWriter jsonWriter) throws IOException {
         jsonWriter.beginArray();
         int msgCount;
-        for (msgCount = 0; msgCount < maxMsgPerFile && !cursor.isAfterLast(); cursor.moveToNext()) {
-            msgCount +=
-                    writeMmsToWriter(cursor, mmsProvider, threadProvider, subId2phone, jsonWriter);
+        for (msgCount = 0; msgCount < mMaxMsgPerFile && !cursor.isAfterLast();
+                cursor.moveToNext()) {
+            msgCount += writeMmsToWriter(jsonWriter, cursor);
         }
         jsonWriter.endArray();
         return msgCount;
     }
 
     @VisibleForTesting
-    static int putSmsMessagesToJson(Cursor cursor, ContentProvider threadProvider,
-                                    SparseArray<String> subId2phone, JsonWriter jsonWriter,
-                                    int maxMsgPerFile) throws IOException {
+    int putSmsMessagesToJson(Cursor cursor, JsonWriter jsonWriter) throws IOException {
 
         jsonWriter.beginArray();
         int msgCount;
-        for (msgCount = 0; msgCount < maxMsgPerFile && !cursor.isAfterLast();
+        for (msgCount = 0; msgCount < mMaxMsgPerFile && !cursor.isAfterLast();
                 ++msgCount, cursor.moveToNext()) {
-            writeSmsToWriter(jsonWriter, cursor, threadProvider, subId2phone);
+            writeSmsToWriter(jsonWriter, cursor);
         }
         jsonWriter.endArray();
         return msgCount;
@@ -474,8 +453,6 @@
     public static class DeferredSmsMmsRestoreService extends IntentService {
         private static final String TAG = "DeferredSmsMmsRestoreService";
 
-        private ContentProvider mSmsProvider, mMmsProvider, mMmsSmsProvider;
-
         private final Comparator<File> mFileComparator = new Comparator<File>() {
             @Override
             public int compare(File lhs, File rhs) {
@@ -488,49 +465,60 @@
             setIntentRedelivery(true);
         }
 
+        private TelephonyBackupAgent mTelephonyBackupAgent;
+        private PowerManager.WakeLock mWakeLock;
+
         @Override
         protected void onHandleIntent(Intent intent) {
-            File[] files = getFilesDir().listFiles(new FileFilter() {
-                @Override
-                public boolean accept(File file) {
-                    return file.getName().endsWith(SMS_BACKUP_FILE_SUFFIX) ||
-                            file.getName().endsWith(MMS_BACKUP_FILE_SUFFIX);
+            try {
+                mWakeLock.acquire();
+                File[] files = getFilesDir().listFiles(new FileFilter() {
+                    @Override
+                    public boolean accept(File file) {
+                        return file.getName().endsWith(SMS_BACKUP_FILE_SUFFIX) ||
+                                file.getName().endsWith(MMS_BACKUP_FILE_SUFFIX);
+                    }
+                });
+
+                if (files == null) {
+                    return;
                 }
-            });
+                Arrays.sort(files, mFileComparator);
 
-            if (files == null) {
-                return;
-            }
-            Arrays.sort(files, mFileComparator);
-
-            for (File file : files) {
-                final String fileName = file.getName();
-                try (FileInputStream fileInputStream = new FileInputStream(file)) {
-                    TelephonyBackupAgent.doRestoreFile(fileName, fileInputStream.getFD(),
-                            mSmsProvider, mMmsProvider, mMmsSmsProvider);
-                    file.delete();
-                } catch (IOException e) {
-                    if (DEBUG) {
-                        Log.e(TAG, e.toString());
+                for (File file : files) {
+                    final String fileName = file.getName();
+                    try (FileInputStream fileInputStream = new FileInputStream(file)) {
+                        mTelephonyBackupAgent.doRestoreFile(fileName, fileInputStream.getFD());
+                        file.delete();
+                    } catch (IOException e) {
+                        if (DEBUG) {
+                            Log.e(TAG, e.toString());
+                        }
                     }
                 }
+            } finally {
+                mWakeLock.release();
             }
         }
 
         @Override
         public void onCreate() {
             super.onCreate();
-            mSmsProvider = new SmsProvider();
-            mSmsProvider.attachInfo(this, null);
-            mSmsProvider.onCreate();
+            mTelephonyBackupAgent = new TelephonyBackupAgent();
+            mTelephonyBackupAgent.attach(this);
+            mTelephonyBackupAgent.onCreate();
 
-            mMmsProvider = new MmsProvider();
-            mMmsProvider.attachInfo(this, null);
-            mMmsProvider.onCreate();
+            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        }
 
-            mMmsSmsProvider = new MmsSmsProvider();
-            mMmsSmsProvider.attachInfo(this, null);
-            mMmsSmsProvider.onCreate();
+        @Override
+        public void onDestroy() {
+            if (mTelephonyBackupAgent != null) {
+                mTelephonyBackupAgent.onDestroy();
+                mTelephonyBackupAgent = null;
+            }
+            super.onDestroy();
         }
 
         public static Intent getIntent(Context context) {
@@ -544,9 +532,7 @@
         startService(DeferredSmsMmsRestoreService.getIntent(this));
     }
 
-    private static void doRestoreFile(String fileName, FileDescriptor fd,
-                                      ContentProvider smsProvider, ContentProvider mmsProvider,
-                                      ContentProvider mmsSmsProvider) throws IOException {
+    private void doRestoreFile(String fileName, FileDescriptor fd) throws IOException {
         if (DEBUG) {
             Log.i(TAG, "Restoring file " + fileName);
         }
@@ -556,12 +542,12 @@
                 if (DEBUG) {
                     Log.i(TAG, "Restoring SMS");
                 }
-                putSmsMessagesToProvider(jsonReader, smsProvider, mmsSmsProvider, sPhone2subId);
+                putSmsMessagesToProvider(jsonReader);
             } else if (fileName.endsWith(MMS_BACKUP_FILE_SUFFIX)) {
                 if (DEBUG) {
                     Log.i(TAG, "Restoring text MMS");
                 }
-                putMmsMessagesToProvider(jsonReader, mmsProvider, mmsSmsProvider, sPhone2subId);
+                putMmsMessagesToProvider(jsonReader);
             } else {
                 if (DEBUG) {
                     Log.e(TAG, "Unknown file to restore:" + fileName);
@@ -571,44 +557,40 @@
     }
 
     @VisibleForTesting
-    static void putSmsMessagesToProvider(JsonReader jsonReader, ContentProvider smsProvider,
-                                         ContentProvider threadProvider,
-                                         Map<String, Integer> phone2subId) throws IOException {
+    void putSmsMessagesToProvider(JsonReader jsonReader) throws IOException {
         jsonReader.beginArray();
         int msgCount = 0;
-        final int bulkInsertSize = MAX_MSG_PER_FILE;
+        final int bulkInsertSize = mMaxMsgPerFile;
         ContentValues[] values = new ContentValues[bulkInsertSize];
         while (jsonReader.hasNext()) {
-            ContentValues cv = readSmsValuesFromReader(jsonReader, threadProvider, phone2subId);
-            if (doesSmsExist(smsProvider, cv)) {
+            ContentValues cv = readSmsValuesFromReader(jsonReader);
+            if (doesSmsExist(cv)) {
                 continue;
             }
             values[(msgCount++) % bulkInsertSize] = cv;
             if (msgCount % bulkInsertSize == 0) {
-                smsProvider.bulkInsert(Telephony.Sms.CONTENT_URI, values);
+                mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, values);
             }
         }
         if (msgCount % bulkInsertSize > 0) {
-            smsProvider.bulkInsert(Telephony.Sms.CONTENT_URI,
+            mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI,
                     Arrays.copyOf(values, msgCount % bulkInsertSize));
         }
         jsonReader.endArray();
     }
 
     @VisibleForTesting
-    static void putMmsMessagesToProvider(JsonReader jsonReader, ContentProvider mmsProvider,
-                                         ContentProvider threadProvider,
-                                         Map<String, Integer> phone2subId) throws IOException {
+    void putMmsMessagesToProvider(JsonReader jsonReader) throws IOException {
         jsonReader.beginArray();
         while (jsonReader.hasNext()) {
-            final Mms mms = readMmsFromReader(jsonReader, threadProvider, phone2subId);
-            if (doesMmsExist(mmsProvider, mms)) {
+            final Mms mms = readMmsFromReader(jsonReader);
+            if (doesMmsExist(mms)) {
                 if (DEBUG) {
                     Log.e(TAG, String.format("Mms: %s already exists", mms.toString()));
                 }
                 continue;
             }
-            addMmsMessage(mmsProvider, mms);
+            addMmsMessage(mms);
         }
     }
 
@@ -616,26 +598,26 @@
     static final String[] PROJECTION_ID = {BaseColumns._ID};
     private static final int ID_IDX = 0;
 
-    private static boolean doesSmsExist(ContentProvider smsProvider, ContentValues smsValues) {
+    private boolean doesSmsExist(ContentValues smsValues) {
         final String where = String.format("%s = %d and %s = %s",
                 Telephony.Sms.DATE, smsValues.getAsLong(Telephony.Sms.DATE),
                 Telephony.Sms.BODY,
                 DatabaseUtils.sqlEscapeString(smsValues.getAsString(Telephony.Sms.BODY)));
-        try (Cursor cursor = smsProvider.query(Telephony.Sms.CONTENT_URI, PROJECTION_ID, where,
+        try (Cursor cursor = mContentResolver.query(Telephony.Sms.CONTENT_URI, PROJECTION_ID, where,
                 null, null)) {
             return cursor != null && cursor.getCount() > 0;
         }
     }
 
-    private static boolean doesMmsExist(ContentProvider mmsProvider, Mms mms) {
+    private boolean doesMmsExist(Mms mms) {
         final String where = String.format("%s = %d",
                 Telephony.Sms.DATE, mms.values.getAsLong(Telephony.Mms.DATE));
-        try (Cursor cursor = mmsProvider.query(Telephony.Mms.CONTENT_URI, PROJECTION_ID, where,
+        try (Cursor cursor = mContentResolver.query(Telephony.Mms.CONTENT_URI, PROJECTION_ID, where,
                 null, null)) {
             if (cursor != null && cursor.moveToFirst()) {
                 do {
                     final int mmsId = cursor.getInt(ID_IDX);
-                    final MmsBody body = getMmsBody(mmsProvider, mmsId);
+                    final MmsBody body = getMmsBody(mmsId);
                     if (body != null && body.equals(mms.body)) {
                         return true;
                     }
@@ -653,9 +635,7 @@
                 subscriptionInfo.getCountryIso().toUpperCase(Locale.US));
     }
 
-    private static void writeSmsToWriter(JsonWriter jsonWriter, Cursor cursor,
-                                         ContentProvider threadProvider,
-                                         SparseArray<String> subId2phone) throws IOException {
+    private void writeSmsToWriter(JsonWriter jsonWriter, Cursor cursor) throws IOException {
         jsonWriter.beginObject();
 
         for (int i=0; i<cursor.getColumnCount(); ++i) {
@@ -667,7 +647,7 @@
             switch (name) {
                 case Telephony.Sms.SUBSCRIPTION_ID:
                     final int subId = cursor.getInt(i);
-                    final String selfNumber = subId2phone.get(subId);
+                    final String selfNumber = mSubId2phone.get(subId);
                     if (selfNumber != null) {
                         jsonWriter.name(SELF_PHONE_KEY).value(selfNumber);
                     }
@@ -675,7 +655,7 @@
                 case Telephony.Sms.THREAD_ID:
                     final long threadId = cursor.getLong(i);
                     writeRecipientsToWriter(jsonWriter.name(RECIPIENTS),
-                            getRecipientsByThread(threadProvider, threadId));
+                            getRecipientsByThread(threadId));
                     break;
                 case Telephony.Sms._ID:
                     break;
@@ -699,10 +679,7 @@
         jsonWriter.endArray();
     }
 
-    @VisibleForTesting
-    static ContentValues readSmsValuesFromReader(JsonReader jsonReader,
-                                                 ContentProvider threadProvider,
-                                                 Map<String, Integer> phone2id)
+    private ContentValues readSmsValuesFromReader(JsonReader jsonReader)
             throws IOException {
         ContentValues values = new ContentValues(8+sDefaultValuesSms.size());
         values.putAll(sDefaultValuesSms);
@@ -721,12 +698,12 @@
                     break;
                 case RECIPIENTS:
                     values.put(Telephony.Sms.THREAD_ID,
-                            getOrCreateThreadId(threadProvider, getRecipients(jsonReader)));
+                            getOrCreateThreadId(getRecipients(jsonReader)));
                     break;
                 case SELF_PHONE_KEY:
                     final String selfPhone = jsonReader.nextString();
-                    if (phone2id.containsKey(selfPhone)) {
-                        values.put(Telephony.Sms.SUBSCRIPTION_ID, phone2id.get(selfPhone));
+                    if (mPhone2subId.containsKey(selfPhone)) {
+                        values.put(Telephony.Sms.SUBSCRIPTION_ID, mPhone2subId.get(selfPhone));
                     }
                     break;
                 default:
@@ -751,12 +728,9 @@
         return recipients;
     }
 
-    private static int writeMmsToWriter(Cursor cursor, ContentProvider mmsProvider,
-                                        ContentProvider threadProvider,
-                                        SparseArray<String> subId2phone,
-                                        JsonWriter jsonWriter) throws IOException {
+    private int writeMmsToWriter(JsonWriter jsonWriter, Cursor cursor) throws IOException {
         final int mmsId = cursor.getInt(ID_IDX);
-        final MmsBody body = getMmsBody(mmsProvider, mmsId);
+        final MmsBody body = getMmsBody(mmsId);
         if (body == null || body.text == null) {
             return 0;
         }
@@ -772,7 +746,7 @@
             switch (name) {
                 case Telephony.Mms.SUBSCRIPTION_ID:
                     final int subId = cursor.getInt(i);
-                    final String selfNumber = subId2phone.get(subId);
+                    final String selfNumber = mSubId2phone.get(subId);
                     if (selfNumber != null) {
                         jsonWriter.name(SELF_PHONE_KEY).value(selfNumber);
                     }
@@ -780,7 +754,7 @@
                 case Telephony.Mms.THREAD_ID:
                     final long threadId = cursor.getLong(i);
                     writeRecipientsToWriter(jsonWriter.name(RECIPIENTS),
-                            getRecipientsByThread(threadProvider, threadId));
+                            getRecipientsByThread(threadId));
                     break;
                 case Telephony.Mms._ID:
                 case Telephony.Mms.SUBJECT_CHARSET:
@@ -793,7 +767,7 @@
             }
         }
         // Addresses.
-        writeMmsAddresses(jsonWriter.name(MMS_ADDRESSES_KEY), mmsProvider, mmsId);
+        writeMmsAddresses(jsonWriter.name(MMS_ADDRESSES_KEY), mmsId);
         // Body (text of the message).
         jsonWriter.name(MMS_BODY_KEY).value(body.text);
         // Charset of the body text.
@@ -807,8 +781,7 @@
         return 1;
     }
 
-    private static Mms readMmsFromReader(JsonReader jsonReader, ContentProvider threadProvider,
-                                         Map<String, Integer> phone2id) throws IOException {
+    private Mms readMmsFromReader(JsonReader jsonReader) throws IOException {
         Mms mms = new Mms();
         mms.values = new ContentValues(6+sDefaultValuesMms.size());
         mms.values.putAll(sDefaultValuesMms);
@@ -820,8 +793,8 @@
             switch (name) {
                 case SELF_PHONE_KEY:
                     final String selfPhone = jsonReader.nextString();
-                    if (phone2id.containsKey(selfPhone)) {
-                        mms.values.put(Telephony.Mms.SUBSCRIPTION_ID, phone2id.get(selfPhone));
+                    if (mPhone2subId.containsKey(selfPhone)) {
+                        mms.values.put(Telephony.Mms.SUBSCRIPTION_ID, mPhone2subId.get(selfPhone));
                     }
                     break;
                 case MMS_ADDRESSES_KEY:
@@ -835,7 +808,7 @@
                     break;
                 case RECIPIENTS:
                     mms.values.put(Telephony.Sms.THREAD_ID,
-                            getOrCreateThreadId(threadProvider, getRecipients(jsonReader)));
+                            getOrCreateThreadId(getRecipients(jsonReader)));
                     break;
                 case Telephony.Mms.SUBJECT:
                 case Telephony.Mms.SUBJECT_CHARSET:
@@ -870,14 +843,14 @@
         return mms;
     }
 
-    private static MmsBody getMmsBody(ContentProvider mmsProvider, int mmsId) {
+    private MmsBody getMmsBody(int mmsId) {
         Uri MMS_PART_CONTENT_URI = Telephony.Mms.CONTENT_URI.buildUpon()
                 .appendPath(String.valueOf(mmsId)).appendPath("part").build();
 
         String body = null;
         int charSet = 0;
 
-        try (Cursor cursor = mmsProvider.query(MMS_PART_CONTENT_URI, MMS_TEXT_PROJECTION,
+        try (Cursor cursor = mContentResolver.query(MMS_PART_CONTENT_URI, MMS_TEXT_PROJECTION,
                 Telephony.Mms.Part.CONTENT_TYPE + "=?", new String[]{ContentType.TEXT_PLAIN},
                 ORDER_BY_ID)) {
             if (cursor != null && cursor.moveToFirst()) {
@@ -891,14 +864,13 @@
         return (body == null ? null : new MmsBody(body, charSet));
     }
 
-    private static void writeMmsAddresses(JsonWriter jsonWriter, ContentProvider mmsProvider,
-                                          int mmsId) throws IOException {
+    private void writeMmsAddresses(JsonWriter jsonWriter, int mmsId) throws IOException {
         Uri.Builder builder = Telephony.Mms.CONTENT_URI.buildUpon();
         builder.appendPath(String.valueOf(mmsId)).appendPath("addr");
         Uri uriAddrPart = builder.build();
 
         jsonWriter.beginArray();
-        try (Cursor cursor = mmsProvider.query(uriAddrPart, MMS_ADDR_PROJECTION,
+        try (Cursor cursor = mContentResolver.query(uriAddrPart, MMS_ADDR_PROJECTION,
                 null/*selection*/, null/*selectionArgs*/, ORDER_BY_ID)) {
             if (cursor != null && cursor.moveToFirst()) {
                 do {
@@ -949,7 +921,7 @@
         jsonReader.endArray();
     }
 
-    private static void addMmsMessage(ContentProvider mmsProvider, Mms mms) {
+    private void addMmsMessage(Mms mms) {
         if (DEBUG) {
             Log.e(TAG, "Add mms:\n" + mms.toString());
         }
@@ -969,7 +941,7 @@
             values.put(Telephony.Mms.Part.CONTENT_ID, "<smil>");
             values.put(Telephony.Mms.Part.CONTENT_LOCATION, "smil.xml");
             values.put(Telephony.Mms.Part.TEXT, smil);
-            if (mmsProvider.insert(partUri, values) == null) {
+            if (mContentResolver.insert(partUri, values) == null) {
                 if (DEBUG) {
                     Log.e(TAG, "Could not insert SMIL part");
                 }
@@ -987,7 +959,7 @@
             values.put(Telephony.Mms.Part.CONTENT_LOCATION, srcName);
             values.put(Telephony.Mms.Part.CHARSET, mms.body.charSet);
             values.put(Telephony.Mms.Part.TEXT, mms.body.text);
-            if (mmsProvider.insert(partUri, values) == null) {
+            if (mContentResolver.insert(partUri, values) == null) {
                 if (DEBUG) {
                     Log.e(TAG, "Could not insert body part");
                 }
@@ -996,7 +968,7 @@
         }
 
         // Insert mms.
-        final Uri mmsUri = mmsProvider.insert(Telephony.Mms.CONTENT_URI, mms.values);
+        final Uri mmsUri = mContentResolver.insert(Telephony.Mms.CONTENT_URI, mms.values);
         if (mmsUri == null) {
             if (DEBUG) {
                 Log.e(TAG, "Could not insert mms");
@@ -1008,7 +980,7 @@
         { // Update parts with the right mms id.
             ContentValues values = new ContentValues(1);
             values.put(Telephony.Mms.Part.MSG_ID, mmsId);
-            mmsProvider.update(partUri, values, null, null);
+            mContentResolver.update(partUri, values, null, null);
         }
 
         { // Insert adderesses into "addr".
@@ -1016,7 +988,7 @@
             for (ContentValues mmsAddress : mms.addresses) {
                 ContentValues values = new ContentValues(mmsAddress);
                 values.put(Telephony.Mms.Addr.MSG_ID, mmsId);
-                mmsProvider.insert(addrUri, values);
+                mContentResolver.insert(addrUri, values);
             }
         }
     }
@@ -1083,70 +1055,38 @@
         }
     }
 
+    private long getOrCreateThreadId(Set<String> recipients) {
+        if (mCacheGetOrCreateThreadId == null) {
+            mCacheGetOrCreateThreadId = new HashMap<>();
+        }
+
+        if (!mCacheGetOrCreateThreadId.containsKey(recipients)) {
+            mCacheGetOrCreateThreadId.put(recipients,
+                    Telephony.Threads.getOrCreateThreadId(this, recipients));
+        }
+
+        return mCacheGetOrCreateThreadId.get(recipients);
+    }
+
     @VisibleForTesting
     static final Uri THREAD_ID_CONTENT_URI = Uri.parse("content://mms-sms/threadID");
 
-    // Copied from frameworks/opt/telephony/src/java/android/provider/Telephony.java because we
-    // can't use ContentResolver during backup/restore.
-    private static long getOrCreateThreadId(
-            ContentProvider contentProvider, Set<String> recipients) {
-        if (sCacheGetOrCreateThreadId == null) {
-            sCacheGetOrCreateThreadId = new HashMap<>();
-        }
-
-        if (sCacheGetOrCreateThreadId.containsKey(recipients)) {
-            return sCacheGetOrCreateThreadId.get(recipients);
-        }
-
-        Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
-
-        for (String recipient : recipients) {
-            if (Telephony.Mms.isEmailAddress(recipient)) {
-                recipient = Telephony.Mms.extractAddrSpec(recipient);
-            }
-
-            uriBuilder.appendQueryParameter("recipient", recipient);
-        }
-
-        Uri uri = uriBuilder.build();
-
-        try (Cursor cursor = contentProvider.query(uri, PROJECTION_ID, null, null, null)) {
-            if (cursor != null) {
-                if (cursor.moveToFirst()) {
-                    final long threadId = cursor.getLong(ID_IDX);
-                    sCacheGetOrCreateThreadId.put(recipients, threadId);
-                    return threadId;
-                } else {
-                    if (DEBUG) {
-                        Log.e(TAG, "getOrCreateThreadId returned no rows!");
-                    }
-                }
-            }
-        }
-
-        if (DEBUG) {
-            Log.e(TAG, "getOrCreateThreadId failed with " + recipients.size() + " recipients");
-        }
-        throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
-    }
-
     // Mostly copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
-    private static List<String> getRecipientsByThread(final ContentProvider threadProvider,
-                                                      final long threadId) {
-        if (sCacheRecipientsByThread == null) {
-            sCacheRecipientsByThread = new HashMap<>();
+    private List<String> getRecipientsByThread(final long threadId) {
+        if (mCacheRecipientsByThread == null) {
+            mCacheRecipientsByThread = new HashMap<>();
         }
 
-        if (!sCacheRecipientsByThread.containsKey(threadId)) {
-            final String spaceSepIds = getRawRecipientIdsForThread(threadProvider, threadId);
+        if (!mCacheRecipientsByThread.containsKey(threadId)) {
+            final String spaceSepIds = getRawRecipientIdsForThread(threadId);
             if (!TextUtils.isEmpty(spaceSepIds)) {
-                sCacheRecipientsByThread.put(threadId, getAddresses(threadProvider, spaceSepIds));
+                mCacheRecipientsByThread.put(threadId, getAddresses(spaceSepIds));
             } else {
-                sCacheRecipientsByThread.put(threadId, new ArrayList<String>());
+                mCacheRecipientsByThread.put(threadId, new ArrayList<String>());
             }
         }
 
-        return sCacheRecipientsByThread.get(threadId);
+        return mCacheRecipientsByThread.get(threadId);
     }
 
     @VisibleForTesting
@@ -1158,12 +1098,11 @@
     // Copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
     // NOTE: There are phones on which you can't get the recipients from the thread id for SMS
     // until you have a message in the conversation!
-    private static String getRawRecipientIdsForThread(final ContentProvider threadProvider,
-                                                      final long threadId) {
+    private String getRawRecipientIdsForThread(final long threadId) {
         if (threadId <= 0) {
             return null;
         }
-        final Cursor thread = threadProvider.query(
+        final Cursor thread = mContentResolver.query(
                 ALL_THREADS_URI,
                 SMS_RECIPIENTS_PROJECTION, "_id=?", new String[]{String.valueOf(threadId)}, null);
         if (thread != null) {
@@ -1185,8 +1124,7 @@
             Uri.parse("content://mms-sms/canonical-address");
 
     // Copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
-    private static List<String> getAddresses(final ContentProvider threadProvider,
-                                             final String spaceSepIds) {
+    private List<String> getAddresses(final String spaceSepIds) {
         final List<String> numbers = new ArrayList<String>();
         final String[] ids = spaceSepIds.split(" ");
         for (final String id : ids) {
@@ -1211,7 +1149,7 @@
             // TODO: build a single query where we get all the addresses at once.
             Cursor c = null;
             try {
-                c = threadProvider.query(
+                c = mContentResolver.query(
                         ContentUris.withAppendedId(SINGLE_CANONICAL_ADDRESS_URI, longId),
                         null, null, null, null);
             } catch (final Exception e) {
diff --git a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
index 288b36b..8bf45c9 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -18,8 +18,11 @@
 
 import android.annotation.TargetApi;
 import android.app.backup.FullBackupDataOutput;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.ContextWrapper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
@@ -27,13 +30,19 @@
 import android.provider.Telephony;
 import android.test.AndroidTestCase;
 import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
 import android.test.mock.MockCursor;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.JsonReader;
 import android.util.JsonWriter;
+import android.util.Log;
 import android.util.SparseArray;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
@@ -42,6 +51,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 
 /**
@@ -72,15 +82,15 @@
 
     private StringWriter mStringWriter;
 
+    /* Content resolver passed to the backupAgent */
+    private MockContentResolver mMockContentResolver = new MockContentResolver();
+
     /* Map uri -> cursors. Being used for contentprovider. */
     private Map<Uri, FakeCursor> mCursors;
-    /* Content provider passed to the backupAgent */
-    private MockContentProvider mContentProvider;
     /* Content provider with threadIds.*/
     private ThreadProvider mThreadProvider = new ThreadProvider();
 
     private static final String EMPTY_JSON_ARRAY = "[]";
-    private int mStoredMaxMsgPerFile;
 
     TelephonyBackupAgent mTelephonyBackupAgent;
 
@@ -88,9 +98,6 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        mTelephonyBackupAgent = new TelephonyBackupAgent();
-        mTelephonyBackupAgent.attach(getContext());
-
         /* Filling up subscription maps */
         mStringWriter = new StringWriter();
         mSubId2Phone = new SparseArray<String>();
@@ -199,7 +206,7 @@
                 "\"sub_cs\":\"10\"}";
         mAllMmsJson = makeJsonArray(mMmsJson);
 
-        mContentProvider = new MockContentProvider() {
+        ContentProvider contentProvider = new MockContentProvider() {
             @Override
             public Cursor query(Uri uri, String[] projection, String selection,
                                 String[] selectionArgs, String sortOrder) {
@@ -211,19 +218,31 @@
                     fakeCursor.nextRow = 0;
                     return fakeCursor;
                 }
-                return super.query(uri, projection, selection, selectionArgs, sortOrder);
+                fail("No cursor for " + uri.toString());
+                return null;
             }
         };
 
-        mStoredMaxMsgPerFile = TelephonyBackupAgent.MAX_MSG_PER_FILE;
-        TelephonyBackupAgent.sCacheGetOrCreateThreadId = null;
-        TelephonyBackupAgent.sCacheRecipientsByThread = null;
+        mMockContentResolver.addProvider("sms", contentProvider);
+        mMockContentResolver.addProvider("mms", contentProvider);
+        mMockContentResolver.addProvider("mms-sms", mThreadProvider);
+
+        mTelephonyBackupAgent = new TelephonyBackupAgent();
+        mTelephonyBackupAgent.attach(new ContextWrapper(getContext()) {
+            @Override
+            public ContentResolver getContentResolver() {
+                return mMockContentResolver;
+            }
+        });
+
+
         mTelephonyBackupAgent.clearSharedPreferences();
+        mTelephonyBackupAgent.setContentResolver(mMockContentResolver);
+        mTelephonyBackupAgent.setSubId(mSubId2Phone, mPhone2SubId);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        TelephonyBackupAgent.MAX_MSG_PER_FILE = mStoredMaxMsgPerFile;
         mTelephonyBackupAgent.clearSharedPreferences();
         super.tearDown();
     }
@@ -351,8 +370,7 @@
      * @throws Exception
      */
     public void testBackupSms_NoSms() throws Exception {
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new ThreadProvider(), mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals(EMPTY_JSON_ARRAY, mStringWriter.toString());
     }
 
@@ -361,9 +379,9 @@
      * @throws Exception
      */
     public void testBackupSms_AllSms() throws Exception {
+        mTelephonyBackupAgent.mMaxMsgPerFile = 4;
         mSmsTable.addAll(Arrays.asList(mSmsRows));
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mThreadProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 4);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals(mAllSmsJson, mStringWriter.toString());
     }
 
@@ -372,9 +390,9 @@
      * @throws Exception
      */
     public void testBackupSms_AllSmsWithExactFileLimit() throws Exception {
+        mTelephonyBackupAgent.mMaxMsgPerFile = 3;
         mSmsTable.addAll(Arrays.asList(mSmsRows));
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mThreadProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 3);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals(mAllSmsJson, mStringWriter.toString());
     }
 
@@ -383,20 +401,18 @@
      * @throws Exception
      */
     public void testBackupSms_AllSmsOneMessagePerFile() throws Exception {
+        mTelephonyBackupAgent.mMaxMsgPerFile = 1;
         mSmsTable.addAll(Arrays.asList(mSmsRows));
 
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mThreadProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mSmsJson[0] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mThreadProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mSmsJson[1] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mThreadProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mSmsJson[2] + "]", mStringWriter.toString());
     }
 
@@ -405,8 +421,7 @@
      * @throws Exception
      */
     public void testBackupMms_NoMms() throws Exception {
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 4);
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals(EMPTY_JSON_ARRAY, mStringWriter.toString());
     }
 
@@ -415,9 +430,9 @@
      * @throws Exception
      */
     public void testBackupMms_AllMms() throws Exception {
+        mTelephonyBackupAgent.mMaxMsgPerFile = 4;
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 4);
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals(mAllMmsJson, mStringWriter.toString());
     }
 
@@ -426,19 +441,17 @@
      * @throws Exception
      */
     public void testBackupMms_OneMessagePerFile() throws Exception {
+        mTelephonyBackupAgent.mMaxMsgPerFile = 1;
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mMmsJson[0] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mMmsJson[1] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals("[" + mMmsJson[2] + "]", mStringWriter.toString());
     }
 
@@ -448,8 +461,8 @@
      */
     public void testBackupMms_WithExactFileLimit() throws Exception {
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
-                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 3);
+        mTelephonyBackupAgent.mMaxMsgPerFile = 3;
+        mTelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, new JsonWriter(mStringWriter));
         assertEquals(mAllMmsJson, mStringWriter.toString());
     }
 
@@ -460,8 +473,8 @@
     public void testRestoreSms_NoSms() throws Exception {
         JsonReader jsonReader = new JsonReader(new StringReader(EMPTY_JSON_ARRAY));
         FakeSmsProvider smsProvider = new FakeSmsProvider(null);
-        TelephonyBackupAgent.putSmsMessagesToProvider(jsonReader, smsProvider,
-                new ThreadProvider(), mPhone2SubId);
+        mMockContentResolver.addProvider("sms", smsProvider);
+        mTelephonyBackupAgent.putSmsMessagesToProvider(jsonReader);
         assertEquals(0, smsProvider.getRowsAdded());
     }
 
@@ -470,10 +483,10 @@
      * @throws Exception
      */
     public void testRestoreSms_AllSms() throws Exception {
-        JsonReader jsonReader = new JsonReader(new StringReader(mAllSmsJson));
+        JsonReader jsonReader = new JsonReader(new StringReader(addRandomDataToJson(mAllSmsJson)));
         FakeSmsProvider smsProvider = new FakeSmsProvider(mSmsRows);
-        TelephonyBackupAgent.putSmsMessagesToProvider(jsonReader, smsProvider,
-                new ThreadProvider(), mPhone2SubId);
+        mMockContentResolver.addProvider("sms", smsProvider);
+        mTelephonyBackupAgent.putSmsMessagesToProvider(jsonReader);
         assertEquals(mSmsRows.length, smsProvider.getRowsAdded());
     }
 
@@ -484,26 +497,37 @@
     public void testRestoreMms_NoMms() throws Exception {
         JsonReader jsonReader = new JsonReader(new StringReader(EMPTY_JSON_ARRAY));
         FakeMmsProvider mmsProvider = new FakeMmsProvider(null);
-        TelephonyBackupAgent.putMmsMessagesToProvider(jsonReader, mmsProvider,
-                new ThreadProvider(), mPhone2SubId);
+        mMockContentResolver.addProvider("mms", mmsProvider);
+        mTelephonyBackupAgent.putMmsMessagesToProvider(jsonReader);
         assertEquals(0, mmsProvider.getRowsAdded());
     }
 
     /**
+     * Test restore sms with three mms json object in the array.
+     * @throws Exception
+     */
+    public void testRestoreMms_AllMms() throws Exception {
+        JsonReader jsonReader = new JsonReader(new StringReader(addRandomDataToJson(mAllMmsJson)));
+        FakeMmsProvider mmsProvider = new FakeMmsProvider(mMmsAllContentValues);
+        mMockContentResolver.addProvider("mms", mmsProvider);
+        mTelephonyBackupAgent.putMmsMessagesToProvider(jsonReader);
+        assertEquals(18, mmsProvider.getRowsAdded());
+    }
+
+    /**
      * Test with quota exceeded. Checking size of the backup before it hits quota and after.
      * It still backs up more than a quota since there is meta-info which matters with small amounts
      * of data. The agent does not take backup meta-info into consideration.
      * @throws Exception
      */
     public void testBackup_WithQuotaExceeded() throws Exception {
-        TelephonyBackupAgent.MAX_MSG_PER_FILE = 1;
+        mTelephonyBackupAgent.mMaxMsgPerFile = 1;
         final int backupSize = 6144;
         final int backupSizeAfterFirstQuotaHit = 5120;
         final int backupSizeAfterSecondQuotaHit = 4096;
 
         mSmsTable.addAll(Arrays.asList(mSmsRows));
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        mTelephonyBackupAgent.setProviders(mContentProvider, mContentProvider, mThreadProvider);
 
         FullBackupDataOutput fullBackupDataOutput = new FullBackupDataOutput();
         mTelephonyBackupAgent.onFullBackup(fullBackupDataOutput);
@@ -521,16 +545,16 @@
         assertEquals(backupSizeAfterSecondQuotaHit, fullBackupDataOutput.getSize());
     }
 
-    /**
-     * Test restore sms with three mms json object in the array.
-     * @throws Exception
-     */
-    public void testRestoreMms_AllMms() throws Exception {
-        JsonReader jsonReader = new JsonReader(new StringReader(mAllMmsJson));
-        FakeMmsProvider mmsProvider = new FakeMmsProvider(mMmsAllContentValues);
-        TelephonyBackupAgent.putMmsMessagesToProvider(jsonReader, mmsProvider,
-                mThreadProvider, mPhone2SubId);
-        assertEquals(18, mmsProvider.getRowsAdded());
+    // Adding random keys to JSON to test handling it by the BackupAgent on restore.
+    private String addRandomDataToJson(String jsonString) throws JSONException {
+        JSONArray jsonArray = new JSONArray(jsonString);
+        JSONArray res = new JSONArray();
+        for (int i = 0; i < jsonArray.length(); ++i) {
+            JSONObject jsonObject = jsonArray.getJSONObject(i);
+            jsonObject.put(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+            res = res.put(jsonObject);
+        }
+        return res.toString();
     }
 
     /**