merge in nyc-release history after reset to nyc-dev
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index 1e92966..e860332 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -125,8 +125,8 @@
     private static final String SELF_PHONE_KEY = "self_phone";
     // JSON key for list of addresses of MMS message.
     private static final String MMS_ADDRESSES_KEY = "mms_addresses";
-    // JSON key for list of recipients of sms message.
-    private static final String SMS_RECIPIENTS = "sms_recipients";
+    // JSON key for list of recipients of the message.
+    private static final String RECIPIENTS = "recipients";
     // JSON key for MMS body.
     private static final String MMS_BODY_KEY = "mms_body";
     // JSON key for MMS charset.
@@ -180,7 +180,8 @@
             Telephony.Mms.MMS_VERSION,
             Telephony.Mms.TEXT_ONLY,
             Telephony.Mms.MESSAGE_BOX,
-            Telephony.Mms.CONTENT_LOCATION
+            Telephony.Mms.CONTENT_LOCATION,
+            Telephony.Mms.THREAD_ID
     };
 
     // Columns from addr database for backup/restore. This database is used for fetching addresses
@@ -324,8 +325,8 @@
             if (cursor != null) {
                 while (!cursor.isLast() && !cursor.isAfterLast()) {
                     try (JsonWriter jsonWriter = getJsonWriter(MMS_BACKUP_FILE)) {
-                        putMmsMessagesToJson(cursor, mMmsProvider, subId2phone, jsonWriter,
-                                MAX_MSG_PER_FILE);
+                        putMmsMessagesToJson(cursor, mMmsProvider, mMmsSmsProvider, subId2phone,
+                                jsonWriter, MAX_MSG_PER_FILE);
                     }
                     backupFile(MMS_BACKUP_FILE, data);
                 }
@@ -335,11 +336,13 @@
 
     @VisibleForTesting
     static void putMmsMessagesToJson(Cursor cursor, ContentProvider mmsProvider,
+                                     ContentProvider threadProvider,
                                      SparseArray<String> subId2phone, JsonWriter jsonWriter,
                                      int maxMsgPerFile) throws IOException {
         jsonWriter.beginArray();
         for (int msgCount=0; msgCount<maxMsgPerFile && cursor.moveToNext();) {
-            msgCount += writeMmsToWriter(jsonWriter, cursor, subId2phone, mmsProvider);
+            msgCount +=
+                    writeMmsToWriter(cursor, mmsProvider, threadProvider, subId2phone, jsonWriter);
         }
         jsonWriter.endArray();
     }
@@ -495,7 +498,7 @@
                     break;
                 case Telephony.Sms.THREAD_ID:
                     final long threadId = cursor.getLong(i);
-                    writeSmsRecipientsToWriter(jsonWriter.name(SMS_RECIPIENTS),
+                    writeRecipientsToWriter(jsonWriter.name(RECIPIENTS),
                             getRecipientsByThread(threadProvider, threadId));
                     break;
                 case Telephony.Sms._ID:
@@ -509,7 +512,7 @@
 
     }
 
-    private static void writeSmsRecipientsToWriter(JsonWriter jsonWriter, List<String> recipients)
+    private static void writeRecipientsToWriter(JsonWriter jsonWriter, List<String> recipients)
             throws IOException {
         jsonWriter.beginArray();
         if (recipients != null) {
@@ -540,9 +543,9 @@
                 case Telephony.Sms.ADDRESS:
                     values.put(name, jsonReader.nextString());
                     break;
-                case SMS_RECIPIENTS:
+                case RECIPIENTS:
                     values.put(Telephony.Sms.THREAD_ID,
-                            getOrCreateThreadId(threadProvider, getSmsRecipients(jsonReader)));
+                            getOrCreateThreadId(threadProvider, getRecipients(jsonReader)));
                     break;
                 case SELF_PHONE_KEY:
                     final String selfPhone = jsonReader.nextString();
@@ -562,7 +565,7 @@
         return values;
     }
 
-    private static Set<String> getSmsRecipients(JsonReader jsonReader) throws IOException {
+    private static Set<String> getRecipients(JsonReader jsonReader) throws IOException {
         Set<String> recipients = new ArraySet<String>();
         jsonReader.beginArray();
         while (jsonReader.hasNext()) {
@@ -572,9 +575,10 @@
         return recipients;
     }
 
-    private static int writeMmsToWriter(JsonWriter jsonWriter, Cursor cursor,
+    private static int writeMmsToWriter(Cursor cursor, ContentProvider mmsProvider,
+                                        ContentProvider threadProvider,
                                         SparseArray<String> subId2phone,
-                                        ContentProvider mmsProvider) throws IOException {
+                                        JsonWriter jsonWriter) throws IOException {
         // Do not backup non text-only MMS's.
         if (cursor.getInt(cursor.getColumnIndex(Telephony.Mms.TEXT_ONLY)) != 1) {
             return 0;
@@ -594,13 +598,18 @@
                 continue;
             }
             switch (name) {
-                case Telephony.Sms.SUBSCRIPTION_ID:
+                case Telephony.Mms.SUBSCRIPTION_ID:
                     final int subId = cursor.getInt(i);
                     final String selfNumber = subId2phone.get(subId);
                     if (selfNumber != null) {
                         jsonWriter.name(SELF_PHONE_KEY).value(selfNumber);
                     }
                     break;
+                case Telephony.Mms.THREAD_ID:
+                    final long threadId = cursor.getLong(i);
+                    writeRecipientsToWriter(jsonWriter.name(RECIPIENTS),
+                            getRecipientsByThread(threadProvider, threadId));
+                    break;
                 case Telephony.Mms._ID:
                 case Telephony.Mms.TEXT_ONLY:
                 case Telephony.Mms.SUBJECT_CHARSET:
@@ -633,14 +642,13 @@
         mms.values = new ContentValues(6+defaultValuesMms.size());
         mms.values.putAll(defaultValuesMms);
         jsonReader.beginObject();
-        String selfPhone = null;
         String bodyText = null;
         int bodyCharset = CharacterSets.DEFAULT_CHARSET;
         while (jsonReader.hasNext()) {
             String name = jsonReader.nextName();
             switch (name) {
                 case SELF_PHONE_KEY:
-                    selfPhone = jsonReader.nextString();
+                    final String selfPhone = jsonReader.nextString();
                     if (phone2id.containsKey(selfPhone)) {
                         mms.values.put(Telephony.Mms.SUBSCRIPTION_ID, phone2id.get(selfPhone));
                     }
@@ -654,6 +662,10 @@
                 case MMS_BODY_CHARSET_KEY:
                     bodyCharset = jsonReader.nextInt();
                     break;
+                case RECIPIENTS:
+                    mms.values.put(Telephony.Sms.THREAD_ID,
+                            getOrCreateThreadId(threadProvider, getRecipients(jsonReader)));
+                    break;
                 case Telephony.Mms.SUBJECT:
                 case Telephony.Mms.SUBJECT_CHARSET:
                 case Telephony.Mms.DATE:
@@ -678,21 +690,6 @@
             mms.body = new MmsBody(bodyText, bodyCharset);
         }
 
-        { // Get ThreadId.
-            Set<String> recipients = new ArraySet<String>();
-            for (ContentValues mmsAddress : mms.addresses) {
-                String address = getDecodedString(
-                        getStringBytes(mmsAddress.getAsString(Telephony.Mms.Addr.ADDRESS),
-                                CharacterSets.ISO_8859_1),
-                        mmsAddress.getAsInteger(Telephony.Mms.Addr.CHARSET));
-                if (selfPhone != null && selfPhone.equals(address))
-                    continue;
-                recipients.add(address);
-            }
-            mms.values.put(Telephony.Mms.THREAD_ID,
-                    getOrCreateThreadId(threadProvider, recipients));
-        }
-
         // Set default charset for subject.
         if (mms.values.get(Telephony.Mms.SUBJECT) != null &&
                 mms.values.get(Telephony.Mms.SUBJECT_CHARSET) == null) {
@@ -953,7 +950,8 @@
         }
     }
 
-    private static final Uri THREAD_ID_CONTENT_URI = Uri.parse("content://mms-sms/threadID");
+    @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(
@@ -994,7 +992,8 @@
         return null;
     }
 
-    private static final Uri ALL_THREADS_URI =
+    @VisibleForTesting
+    static final Uri ALL_THREADS_URI =
             Telephony.Threads.CONTENT_URI.buildUpon().
                     appendQueryParameter("simple", "true").build();
     private static final int RECIPIENT_IDS  = 1;
@@ -1024,7 +1023,8 @@
         return null;
     }
 
-    private static final Uri SINGLE_CANONICAL_ADDRESS_URI =
+    @VisibleForTesting
+    static final Uri SINGLE_CANONICAL_ADDRESS_URI =
             Uri.parse("content://mms-sms/canonical-address");
 
     // Copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
diff --git a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
index 4920c53..1dcb3db 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -17,6 +17,7 @@
 package com.android.providers.telephony;
 
 import android.annotation.TargetApi;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
@@ -27,6 +28,7 @@
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockCursor;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.JsonReader;
 import android.util.JsonWriter;
 import android.util.SparseArray;
@@ -38,6 +40,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 
 /**
@@ -47,27 +50,42 @@
  */
 @TargetApi(Build.VERSION_CODES.M)
 public class TelephonyBackupAgentTest extends AndroidTestCase {
+    /* Map subscriptionId -> phone number */
     private SparseArray<String> mSubId2Phone;
+    /* Map phone number -> subscriptionId */
     private ArrayMap<String, Integer> mPhone2SubId;
+    /* Table being used for sms cursor */
     private final List<ContentValues> mSmsTable = new ArrayList<>();
+    /* Table begin used for mms cursor */
     private final List<ContentValues> mMmsTable = new ArrayList<>();
+    /* Table contains parts, addresses of mms */
     private final List<ContentValues> mMmsAllContentValues = new ArrayList<>();
+    /* Cursors being used to access sms, mms tables */
     private FakeCursor mSmsCursor, mMmsCursor;
+    /* Test data with sms and mms */
     private ContentValues[] mSmsRows, mMmsRows;
+    /* Non-text mms for testing it is not being backed up */
     private ContentValues mMmsNonText;
+    /* Json representation for the test data */
     private String[] mSmsJson, mMmsJson;
+    /* sms, mms json concatenated as json array */
     private String mAllSmsJson, mAllMmsJson;
 
-
     private StringWriter mStringWriter;
+
+    /* 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 = "[]";
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        /* Filling up subscription maps */
         mStringWriter = new StringWriter();
         mSubId2Phone = new SparseArray<String>();
         mSubId2Phone.append(1, "+111111111111111");
@@ -78,31 +96,39 @@
             mPhone2SubId.put(mSubId2Phone.valueAt(i), mSubId2Phone.keyAt(i));
         }
 
+        /* Bind tables to the cursors */
         mSmsCursor = new FakeCursor(mSmsTable, TelephonyBackupAgent.SMS_PROJECTION);
         mMmsCursor = new FakeCursor(mMmsTable, TelephonyBackupAgent.MMS_PROJECTION);
+
         mCursors = new HashMap<Uri, FakeCursor>();
 
+        /* Generating test data */
         mSmsRows = new ContentValues[3];
         mSmsJson = new String[3];
         mSmsRows[0] = createSmsRow(1, 1, "+1232132214124", "sms 1", "sms subject", 9087978987l,
                 999999999, 3, 44, 1);
         mSmsJson[0] = "{\"self_phone\":\"+111111111111111\",\"address\":" +
                 "\"+1232132214124\",\"body\":\"sms 1\",\"subject\":\"sms subject\",\"date\":" +
-                "\"9087978987\",\"date_sent\":\"999999999\",\"status\":\"3\",\"type\":\"44\"}";
+                "\"9087978987\",\"date_sent\":\"999999999\",\"status\":\"3\",\"type\":\"44\"," +
+                "\"recipients\":[\"+123 (213) 2214124\"]}";
+        mThreadProvider.getOrCreateThreadId(new String[]{"+123 (213) 2214124"});
 
         mSmsRows[1] = createSmsRow(2, 2, "+1232132214124", "sms 2", null, 9087978987l, 999999999,
                 0, 4, 1);
         mSmsJson[1] = "{\"address\":\"+1232132214124\",\"body\":\"sms 2\",\"date\":" +
-                "\"9087978987\",\"date_sent\":\"999999999\",\"status\":\"0\",\"type\":\"4\"}";
+                "\"9087978987\",\"date_sent\":\"999999999\",\"status\":\"0\",\"type\":\"4\"," +
+                "\"recipients\":[\"+123 (213) 2214124\"]}";
 
         mSmsRows[2] = createSmsRow(4, 3, "+1232221412433 +1232221412444", "sms 3", null,
                 111111111111l, 999999999, 2, 3, 2);
         mSmsJson[2] =  "{\"self_phone\":\"+333333333333333\",\"address\":" +
                 "\"+1232221412433 +1232221412444\",\"body\":\"sms 3\",\"date\":\"111111111111\"," +
                 "\"date_sent\":" +
-                "\"999999999\",\"status\":\"2\",\"type\":\"3\"}";
+                "\"999999999\",\"status\":\"2\",\"type\":\"3\"," +
+                "\"recipients\":[\"+1232221412433\",\"+1232221412444\"]}";
+        mThreadProvider.getOrCreateThreadId(new String[]{"+1232221412433", "+1232221412444"});
 
-        mAllSmsJson = concatJson(mSmsJson);
+        mAllSmsJson = makeJsonArray(mSmsJson);
 
 
 
@@ -113,41 +139,57 @@
                 17 /*version*/, 1 /*textonly*/,
                 11 /*msgBox*/, "location 1" /*contentLocation*/, "MMs body 1" /*body*/,
                 111 /*body charset*/,
-                new String[]{"+11121212", "example@example.com", "+999999999"} /*addresses*/,
-                1 /*threadId*/);
+                new String[]{"+111 (111) 11111111", "+11121212", "example@example.com",
+                        "+999999999"} /*addresses*/,
+                3 /*threadId*/);
 
         mMmsJson[0] = "{\"self_phone\":\"+111111111111111\",\"sub\":\"Subject 1\"," +
                 "\"date\":\"111111\",\"date_sent\":\"111112\",\"m_type\":\"3\",\"v\":\"17\"," +
-                "\"msg_box\":\"11\",\"ct_l\":\"location 1\",\"mms_addresses\":[{\"type\":10," +
-                "\"address\":\"+11121212\",\"charset\":100},{\"type\":11,\"address\":" +
-                "\"example@example.com\",\"charset\":101},{\"type\":12,\"address\":\"+999999999\"" +
-                ",\"charset\":102}],\"mms_body\":\"MMs body 1\",\"mms_charset\":111,\"" +
+                "\"msg_box\":\"11\",\"ct_l\":\"location 1\"," +
+                "\"recipients\":[\"+11121212\",\"example@example.com\",\"+999999999\"]," +
+                "\"mms_addresses\":" +
+                "[{\"type\":10,\"address\":\"+111 (111) 11111111\",\"charset\":100}," +
+                "{\"type\":11,\"address\":\"+11121212\",\"charset\":101},{\"type\":12,\"address\":"+
+                "\"example@example.com\",\"charset\":102},{\"type\":13,\"address\":\"+999999999\"" +
+                ",\"charset\":103}],\"mms_body\":\"MMs body 1\",\"mms_charset\":111,\"" +
                 "sub_cs\":\"100\"}";
+        mThreadProvider.getOrCreateThreadId(new String[]{"+11121212", "example@example.com",
+                "+999999999"});
 
         mMmsRows[1] = createMmsRow(2 /*id*/, 2 /*subid*/, null /*subject*/, 100 /*subcharset*/,
                 111122 /*date*/, 1111112 /*datesent*/, 4 /*type*/, 18 /*version*/, 1 /*textonly*/,
                 222 /*msgBox*/, "location 2" /*contentLocation*/, "MMs body 2" /*body*/,
                 121 /*body charset*/,
-                new String[]{"example@example.com", "+999999999"} /*addresses*/, 2 /*threadId*/);
-
+                new String[]{"+7 (333) ", "example@example.com", "+999999999"} /*addresses*/,
+                4 /*threadId*/);
         mMmsJson[1] = "{\"date\":\"111122\",\"date_sent\":\"1111112\",\"m_type\":\"4\"," +
-                "\"v\":\"18\",\"msg_box\":\"222\",\"ct_l\":\"location 2\",\"mms_addresses\":" +
-                "[{\"type\":10,\"address\":\"example@example.com\",\"charset\":100}," +
-                "{\"type\":11,\"address\":\"+999999999\",\"charset\":101}]," +
+                "\"v\":\"18\",\"msg_box\":\"222\",\"ct_l\":\"location 2\"," +
+                "\"recipients\":[\"example@example.com\",\"+999999999\"]," +
+                "\"mms_addresses\":" +
+                "[{\"type\":10,\"address\":\"+7 (333) \",\"charset\":100}," +
+                "{\"type\":11,\"address\":\"example@example.com\",\"charset\":101}," +
+                "{\"type\":12,\"address\":\"+999999999\",\"charset\":102}]," +
                 "\"mms_body\":\"MMs body 2\",\"mms_charset\":121}";
+        mThreadProvider.getOrCreateThreadId(new String[]{"example@example.com", "+999999999"});
 
-        mMmsRows[2] = createMmsRow(10 /*id*/, 3 /*subid*/, "Subject 10" /*subject*/,
+        mMmsRows[2] = createMmsRow(9 /*id*/, 3 /*subid*/, "Subject 10" /*subject*/,
                 10 /*subcharset*/, 111133 /*date*/, 1111132 /*datesent*/, 5 /*type*/,
                 19 /*version*/, 1 /*textonly*/,
                 333 /*msgBox*/, null /*contentLocation*/, "MMs body 3" /*body*/,
-                131 /*body charset*/, new String[]{"+8888888888"} /*addresses*/, 3 /*threadId*/);
+                131 /*body charset*/,
+                new String[]{"333 333333333333", "+1232132214124"} /*addresses*/,
+                1 /*threadId*/);
 
         mMmsJson[2] = "{\"self_phone\":\"+333333333333333\",\"sub\":\"Subject 10\"," +
                 "\"date\":\"111133\",\"date_sent\":\"1111132\",\"m_type\":\"5\",\"v\":\"19\"," +
-                "\"msg_box\":\"333\",\"mms_addresses\":[{\"type\":10,\"address\":\"+8888888888\"," +
-                "\"charset\":100}],\"mms_body\":\"MMs body 3\",\"mms_charset\":131," +
+                "\"msg_box\":\"333\"," +
+                "\"recipients\":[\"+123 (213) 2214124\"]," +
+                "\"mms_addresses\":" +
+                "[{\"type\":10,\"address\":\"333 333333333333\",\"charset\":100}," +
+                "{\"type\":11,\"address\":\"+1232132214124\",\"charset\":101}]," +
+                "\"mms_body\":\"MMs body 3\",\"mms_charset\":131," +
                 "\"sub_cs\":\"10\"}";
-        mAllMmsJson = concatJson(mMmsJson);
+        mAllMmsJson = makeJsonArray(mMmsJson);
 
 
         // Should not be backed up. Cause flag text_only is false.
@@ -174,7 +216,7 @@
 
     }
 
-    private static String concatJson(String[] json) {
+    private static String makeJsonArray(String[] json) {
         StringBuilder stringBuilder = new StringBuilder("[");
         for (int i=0; i<json.length; ++i) {
             if (i > 0) {
@@ -308,47 +350,43 @@
      * Test with 3 sms in the provider with the limit per file 4.
      * @throws Exception
      */
-
-    public void DISABLED_testBackupSms_AllSms() throws Exception {
+    public void testBackupSms_AllSms() throws Exception {
         mSmsTable.addAll(Arrays.asList(mSmsRows));
         TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mSubId2Phone,
-                new JsonWriter(mStringWriter), new ThreadProvider(), 4);
-        final String expected =
-                "[" + mSmsJson[0] + "," + mSmsJson[1] + "," + mSmsJson[2] + "]";
-        assertEquals(expected, mStringWriter.toString());
+                new JsonWriter(mStringWriter), mThreadProvider, 4);
+        assertEquals(mAllSmsJson, mStringWriter.toString());
     }
 
     /**
      * Test with 3 sms in the provider with the limit per file 3.
      * @throws Exception
      */
-    public void DISABLED_testBackupSms_AllSmsWithExactFileLimit() throws Exception {
+    public void testBackupSms_AllSmsWithExactFileLimit() throws Exception {
         mSmsTable.addAll(Arrays.asList(mSmsRows));
         TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mSubId2Phone,
-                new JsonWriter(mStringWriter), new ThreadProvider(), 3);
-        final String expected =
-                "[" + mSmsJson[0] + "," + mSmsJson[1] + "," + mSmsJson[2] + "]";
-        assertEquals(expected, mStringWriter.toString());
+                new JsonWriter(mStringWriter), mThreadProvider, 3);
+        assertEquals(mAllSmsJson, mStringWriter.toString());
     }
 
     /**
      * Test with 3 sms in the provider with the limit per file 1.
      * @throws Exception
      */
-    public void DISABLED_testBackupSms_AllSmsOneMessagePerFile() throws Exception {
+    public void testBackupSms_AllSmsOneMessagePerFile() throws Exception {
         mSmsTable.addAll(Arrays.asList(mSmsRows));
+
         TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mSubId2Phone,
-                new JsonWriter(mStringWriter), new ThreadProvider(), 1);
+                new JsonWriter(mStringWriter), mThreadProvider, 1);
         assertEquals("[" + mSmsJson[0] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
         TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mSubId2Phone,
-                new JsonWriter(mStringWriter), new ThreadProvider(), 1);
+                new JsonWriter(mStringWriter), mThreadProvider, 1);
         assertEquals("[" + mSmsJson[1] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
         TelephonyBackupAgent.putSmsMessagesToJson(mSmsCursor, mSubId2Phone,
-                new JsonWriter(mStringWriter), new ThreadProvider(), 1);
+                new JsonWriter(mStringWriter), mThreadProvider, 1);
         assertEquals("[" + mSmsJson[2] + "]", mStringWriter.toString());
     }
 
@@ -357,8 +395,8 @@
      * @throws Exception
      */
     public void testBackupMms_NoMms() throws Exception {
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 4);
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 4);
         assertEquals(EMPTY_JSON_ARRAY, mStringWriter.toString());
     }
 
@@ -369,11 +407,9 @@
     public void testBackupMms_AllMms() throws Exception {
         mMmsTable.addAll(Arrays.asList(mMmsRows));
         mMmsTable.add(mMmsNonText);
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 4);
-        final String expected =
-                "[" + mMmsJson[0] + "," + mMmsJson[1] + "," + mMmsJson[2] + "]";
-        assertEquals(expected, mStringWriter.toString());
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 4);
+        assertEquals(mAllMmsJson, mStringWriter.toString());
     }
 
     /**
@@ -382,18 +418,18 @@
      */
     public void testBackupMms_OneMessagePerFile() throws Exception {
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
         assertEquals("[" + mMmsJson[0] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 1);
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
         assertEquals("[" + mMmsJson[1] + "]", mStringWriter.toString());
 
         mStringWriter = new StringWriter();
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 2);
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 1);
         assertEquals("[" + mMmsJson[2] + "]", mStringWriter.toString());
     }
 
@@ -403,11 +439,9 @@
      */
     public void testBackupMms_WithExactFileLimit() throws Exception {
         mMmsTable.addAll(Arrays.asList(mMmsRows));
-        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider, mSubId2Phone,
-                new JsonWriter(mStringWriter), 3);
-        final String expected =
-                "[" + mMmsJson[0] + "," + mMmsJson[1] + "," + mMmsJson[2] + "]";
-        assertEquals(expected, mStringWriter.toString());
+        TelephonyBackupAgent.putMmsMessagesToJson(mMmsCursor, mContentProvider,
+                mThreadProvider, mSubId2Phone, new JsonWriter(mStringWriter), 3);
+        assertEquals(mAllMmsJson, mStringWriter.toString());
     }
 
     /**
@@ -426,7 +460,7 @@
      * Test restore sms with three sms json object in the array.
      * @throws Exception
      */
-    public void DISABLED_testRestoreSms_AllSms() throws Exception {
+    public void testRestoreSms_AllSms() throws Exception {
         JsonReader jsonReader = new JsonReader(new StringReader(mAllSmsJson));
         FakeSmsProvider smsProvider = new FakeSmsProvider(mSmsRows);
         TelephonyBackupAgent.putSmsMessagesToProvider(jsonReader, smsProvider,
@@ -454,8 +488,8 @@
         JsonReader jsonReader = new JsonReader(new StringReader(mAllMmsJson));
         FakeMmsProvider mmsProvider = new FakeMmsProvider(mMmsAllContentValues);
         TelephonyBackupAgent.putMmsMessagesToProvider(jsonReader, mmsProvider,
-                new ThreadProvider(), mPhone2SubId);
-        assertEquals(15, mmsProvider.getRowsAdded());
+                mThreadProvider, mPhone2SubId);
+        assertEquals(18, mmsProvider.getRowsAdded());
     }
 
     /**
@@ -560,7 +594,7 @@
             }
 
             for (String key : modifiedValues.keySet()) {
-                assertEquals(modifiedValues.get(key), values.get(key));
+                assertEquals("Key:"+key, modifiedValues.get(key), values.get(key));
             }
             assertEquals(modifiedValues.size(), values.size());
             return retUri;
@@ -594,29 +628,72 @@
      * class that implements MmsSms provider for thread ids.
      */
     private static class ThreadProvider extends MockContentProvider {
+        ArrayList<Set<Integer> > id2Thread = new ArrayList<>();
+        ArrayList<String> id2Recipient = new ArrayList<>();
 
-        Map<List<String>, Integer> threadIds;
+        public int getOrCreateThreadId(final String[] recipients) {
+            Set<Integer> ids = new ArraySet<>();
+            for (String rec : recipients) {
+                if (!id2Recipient.contains(rec)) {
+                    id2Recipient.add(rec);
+                }
+                ids.add(id2Recipient.indexOf(rec)+1);
+            }
+            if (!id2Thread.contains(ids)) {
+                id2Thread.add(ids);
+            }
+            return id2Thread.indexOf(ids)+1;
+        }
 
-        public ThreadProvider() {
-            threadIds = new ArrayMap<>();
+        private String getSpaceSepIds(int threadId) {
+            String spaceSepIds = null;
+            for (Integer id : id2Thread.get(threadId-1)) {
+                spaceSepIds = (spaceSepIds == null ? "" : spaceSepIds + " ") + String.valueOf(id);
+            }
+            return spaceSepIds;
+        }
+
+        private String getRecipient(int recipientId) {
+            return id2Recipient.get(recipientId-1);
         }
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                             String sortOrder) {
-            List<String> recipients = uri.getQueryParameters("recipient");
-            int threadId = threadIds.size() + 1;
-            if (threadIds.containsKey(recipients)) {
-                threadId = threadIds.get(recipients);
-            } else {
-                threadIds.put(recipients, threadId);
-            }
+            if (uri.equals(TelephonyBackupAgent.ALL_THREADS_URI)) {
+                final int threadId = Integer.parseInt(selectionArgs[0]);
+                final String spaceSepIds = getSpaceSepIds(threadId);
+                List<ContentValues> table = new ArrayList<>();
+                ContentValues row = new ContentValues();
+                row.put(Telephony.Threads.RECIPIENT_IDS, spaceSepIds);
+                table.add(row);
+                return new FakeCursor(table, projection);
+            } else if (uri.toString().startsWith(
+                    TelephonyBackupAgent.SINGLE_CANONICAL_ADDRESS_URI.toString())) {
+                final int recipientId = (int)ContentUris.parseId(uri);
+                final String recipient = getRecipient(recipientId);
+                List<ContentValues> table = new ArrayList<>();
+                ContentValues row = new ContentValues();
+                row.put(Telephony.CanonicalAddressesColumns.ADDRESS, recipient);
+                table.add(row);
 
-            List<ContentValues> table = new ArrayList<>();
-            ContentValues row = new ContentValues();
-            row.put(BaseColumns._ID, String.valueOf(threadId));
-            table.add(row);
-            return new FakeCursor(table, projection);
+                return new FakeCursor(table,
+                        projection != null
+                                ? projection
+                                : new String[] { Telephony.CanonicalAddressesColumns.ADDRESS });
+            } else if (uri.toString().startsWith(
+                    TelephonyBackupAgent.THREAD_ID_CONTENT_URI.toString())) {
+                List<String> recipients = uri.getQueryParameters("recipient");
+
+                final int threadId =
+                        getOrCreateThreadId(recipients.toArray(new String[recipients.size()]));
+                List<ContentValues> table = new ArrayList<>();
+                ContentValues row = new ContentValues();
+                row.put(BaseColumns._ID, String.valueOf(threadId));
+                table.add(row);
+                return new FakeCursor(table, projection);
+            };
+            return null;
         }
     }