Merge "getSingleMessageFromIcc does not make sense" am: 596a3b0b73 am: b615a887ea
am: 8475fa5c99

Change-Id: I3b71e5409321a7241cd144cb7a80d3fff9b68f13
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9ac0815..578067e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -66,6 +66,13 @@
                   android:singleUser="true"
                   android:readPermission="android.permission.READ_SMS" />
 
+        <provider android:name="SmsChangesProvider"
+                  android:authorities="sms-changes"
+                  android:multiprocess="false"
+                  android:exported="true"
+                  android:singleUser="true"
+                  android:readPermission="android.permission.READ_SMS" />
+
         <!-- This is a singleton provider that is used by all users.
              A new instance is not created for each user. And the db is shared
              as well.
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1c53b15..309a57b 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -17,5 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" product="tablet" msgid="9194799012395299737">"تهيئة شبكة الجوال"</string>
-    <string name="app_label" product="default" msgid="8338087656149558019">"سعة تخزينية للهاتف والرسائل"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"مساحة تخزين للهاتف والرسائل"</string>
 </resources>
diff --git a/res/values-as/config.xml b/res/values-as/config.xml
new file mode 100644
index 0000000..99877a6
--- /dev/null
+++ b/res/values-as/config.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="persist_apns_for_plmn">
+    <item msgid="6413072509259000954">"20404"</item>
+    <item msgid="5639159280778239123">"310004"</item>
+    <item msgid="3860605521380788028">"310120"</item>
+    <item msgid="537693705785480198">"311480"</item>
+  </string-array>
+</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
new file mode 100644
index 0000000..6994d18
--- /dev/null
+++ b/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" product="tablet" msgid="9194799012395299737">"ম’বাইল নেটৱৰ্ক কনফিগাৰেশ্বন"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"ফ\'ন আৰু বাৰ্তাৰ সঞ্চয়াগাৰ"</string>
+</resources>
diff --git a/res/values-en-rXC/config.xml b/res/values-en-rXC/config.xml
index 274d8aa..5fadb9d 100644
--- a/res/values-en-rXC/config.xml
+++ b/res/values-en-rXC/config.xml
@@ -2,9 +2,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
   <string-array name="persist_apns_for_plmn">
-    <item msgid="6413072509259000954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎20404‎‏‎‎‏‎"</item>
-    <item msgid="5639159280778239123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎310004‎‏‎‎‏‎"</item>
-    <item msgid="3860605521380788028">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎310120‎‏‎‎‏‎"</item>
-    <item msgid="537693705785480198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎311480‎‏‎‎‏‎"</item>
+    <item msgid="6413072509259000954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎20404‎‏‎‎‏‎"</item>
+    <item msgid="5639159280778239123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎310004‎‏‎‎‏‎"</item>
+    <item msgid="3860605521380788028">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎310120‎‏‎‎‏‎"</item>
+    <item msgid="537693705785480198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎311480‎‏‎‎‏‎"</item>
   </string-array>
 </resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 22950f7..e40d9ab 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -16,6 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" product="tablet" msgid="9194799012395299737">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎Mobile Network Configuration‎‏‎‎‏‎"</string>
-    <string name="app_label" product="default" msgid="8338087656149558019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎Phone and Messaging Storage‎‏‎‎‏‎"</string>
+    <string name="app_label" product="tablet" msgid="9194799012395299737">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎Mobile Network Configuration‎‏‎‎‏‎"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎Phone and Messaging Storage‎‏‎‎‏‎"</string>
 </resources>
diff --git a/res/values-or/config.xml b/res/values-or/config.xml
new file mode 100644
index 0000000..99877a6
--- /dev/null
+++ b/res/values-or/config.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="persist_apns_for_plmn">
+    <item msgid="6413072509259000954">"20404"</item>
+    <item msgid="5639159280778239123">"310004"</item>
+    <item msgid="3860605521380788028">"310120"</item>
+    <item msgid="537693705785480198">"311480"</item>
+  </string-array>
+</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
new file mode 100644
index 0000000..b004c4f
--- /dev/null
+++ b/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" product="tablet" msgid="9194799012395299737">"ମୋବାଇଲ୍ ନେଟ୍‌ୱର୍କ କନଫିଗରେଶନ୍"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"ଫୋନ୍ ଓ ମେସେଜିଙ୍ଗ ଷ୍ଟୋରେଜ୍"</string>
+</resources>
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index d4efeb9..013db19 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -330,6 +330,7 @@
          */
         public CarrierIdDatabaseHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
+            Log.d(TAG, "CarrierIdDatabaseHelper: " + DATABASE_VERSION);
             setWriteAheadLoggingEnabled(false);
         }
 
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 3d3711a..5fc36d2 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.DefaultDatabaseErrorHandler;
@@ -292,12 +293,12 @@
         mContext = context;
         // Memory optimization - close idle connections after 30s of inactivity
         setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+        setWriteAheadLoggingEnabled(false);
         try {
             PhoneFactory.addLocalLog(TAG, 100);
         } catch (IllegalArgumentException e) {
             // ignore
         }
-        setWriteAheadLoggingEnabled(false);
     }
 
     private static synchronized MmsSmsDatabaseErrorHandler getDbErrorHandler(Context context) {
@@ -1068,6 +1069,29 @@
                    Sms.TYPE + "=" + Sms.MESSAGE_TYPE_INBOX +
                    " OR " +
                    Sms.TYPE + "=" + Sms.MESSAGE_TYPE_SENT + ";");
+
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            // Create a table to keep track of changes to SMS table - specifically on update to read
+            // and deletion of msgs
+            db.execSQL("CREATE TABLE sms_changes (" +
+                       "_id INTEGER PRIMARY KEY," +
+                       "orig_rowid INTEGER," +
+                       "sub_id INTEGER," +
+                       "type INTEGER," +
+                       "new_read_status INTEGER" +
+                       ");");
+            db.execSQL("CREATE TRIGGER sms_update_on_read_change_row " +
+                        "AFTER UPDATE OF read ON sms WHEN NEW.read != OLD.read " +
+                        "BEGIN " +
+                        "  INSERT INTO sms_changes VALUES(null, NEW._id, NEW.sub_id, " +
+                        "0, NEW.read); " +
+                        "END;");
+            db.execSQL("CREATE TRIGGER sms_delete_change_row " +
+                       "AFTER DELETE ON sms " +
+                       "BEGIN " +
+                       "  INSERT INTO sms_changes values(null, OLD._id, OLD.sub_id, 1, null); " +
+                       "END;");
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/providers/telephony/SmsChangesProvider.java b/src/com/android/providers/telephony/SmsChangesProvider.java
new file mode 100644
index 0000000..3f14e2b
--- /dev/null
+++ b/src/com/android/providers/telephony/SmsChangesProvider.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.telephony;
+
+import android.app.AppOpsManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * This is the ContentProvider for the table sms_changes.
+ * This provider is applicable only for Android Auto builds as
+ * this table exists only in Android Auto environment.
+ *
+ * This provider does not notify of changes.
+ * Interested observers should instead listen to notification on sms table, instead.
+ */
+public class SmsChangesProvider extends ContentProvider {
+    private final static String TAG = "SmsChangesProvider";
+
+    private static final String TABLE_SMS_CHANGES = "sms_changes";
+
+    // Db open helper for tables stored in CE(Credential Encrypted) storage.
+    private SQLiteOpenHelper mCeOpenHelper;
+
+    @Override
+    public String getType(Uri url) {
+        return null;
+    }
+
+    @Override
+    public boolean onCreate() {
+        setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
+        mCeOpenHelper = MmsSmsDatabaseHelper.getInstanceForCe(getContext());
+        return true;
+    }
+
+
+    @Override
+    public Cursor query(Uri url, String[] projectionIn, String selection,
+            String[] selectionArgs, String sort) {
+        // return if FEATURE_AUTOMOTIVE is not set
+        if (!isAutoFeatureSet()) {
+            return null;
+        }
+
+        // Only support one type of query
+        //  Caller sends content://mms-sms and other params
+        if (!isUrlSupported(url)) {
+            return null;
+        }
+
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+        qb.setTables(TABLE_SMS_CHANGES);
+        SQLiteDatabase db = mCeOpenHelper.getReadableDatabase();
+        return qb.query(db, projectionIn, selection, selectionArgs,
+                null /* groupBy */, null /* having */,
+                null /* sortOrder */);
+    }
+
+    @Override
+    public Uri insert(Uri url, ContentValues initialValues) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri url, String where, String[] whereArgs) {
+        // return if FEATURE_AUTOMOTIVE is not set
+        if (!isAutoFeatureSet()) {
+            return 0;
+        }
+
+        // only support deletion of all data from the table
+        if (!isUrlSupported(url)) return 0;
+
+        return mCeOpenHelper.getWritableDatabase().delete(TABLE_SMS_CHANGES,
+                null /* whereClause */, null /* whereArgs */);
+    }
+
+    private boolean isUrlSupported(Uri url) {
+        if (sURLMatcher.match(url) != SMSCHANGES_URL) {
+            Log.e(TAG, "Invalid or Unsupported request: " + url);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
+        return 0;
+    }
+
+    private boolean isAutoFeatureSet() {
+        return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    private static final int SMSCHANGES_URL = 0;
+
+    private static final UriMatcher sURLMatcher =
+            new UriMatcher(UriMatcher.NO_MATCH);
+
+    static {
+        sURLMatcher.addURI("sms-changes", null, SMSCHANGES_URL);
+    }
+}
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index e2e6d10..0c59603 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -16,6 +16,9 @@
 
 package com.android.providers.telephony;
 
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.ContentProvider;
@@ -33,6 +36,7 @@
 import android.os.Binder;
 import android.os.UserHandle;
 import android.provider.Contacts;
+import android.provider.Settings;
 import android.provider.Telephony;
 import android.provider.Telephony.MmsSms;
 import android.provider.Telephony.Sms;
@@ -842,6 +846,19 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected int interpretDefaultAppOpMode(int op) {
+        if (op == AppOpsManager.OP_WRITE_SMS) {
+            return MODE_IGNORED;
+        } else {
+            boolean accessRestrictionEnabled = Settings.Global.getInt(
+                    getContext().getContentResolver(),
+                    Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1;
+            return accessRestrictionEnabled ? MODE_IGNORED : MODE_ALLOWED;
+        }
+    }
+
     // Db open helper for tables stored in CE(Credential Encrypted) storage.
     @VisibleForTesting
     public SQLiteOpenHelper mCeOpenHelper;
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index ad4367c..437b5a2 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -1155,8 +1155,12 @@
             values.put(Telephony.Mms.Part.NAME, srcName);
             values.put(Telephony.Mms.Part.CONTENT_ID, "<"+srcName+">");
             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);
+
+            values.put(
+                    Telephony.Mms.Part.CHARSET,
+                    mms.body == null ? CharacterSets.DEFAULT_CHARSET : mms.body.charSet);
+            values.put(Telephony.Mms.Part.TEXT, mms.body == null ? "" : mms.body.text);
+
             if (mContentResolver.insert(partUri, values) == null) {
                 if (DEBUG) {
                     Log.e(TAG, "Could not insert body part");
diff --git a/tests/Android.bp b/tests/Android.bp
index 801a40c..f1be84b 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -2,8 +2,8 @@
     name: "TelephonyProviderTests",
     static_libs: [
         "mockito-target",
-        "compatibility-device-util",
-        "android-support-test",
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
         "truth-prebuilt",
     ],
     libs: [
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 91e8953..59fd8bd 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -21,7 +21,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.providers.telephony"
         android:label="Tests for TelephonyProvider">
     </instrumentation>
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index ad703de..23310f9 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="TelephonyProviderTests" />
     <test class="com.android.tradefed.testtype.InstrumentationTest" >
         <option name="package" value="com.android.providers.telephony.tests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests/src/com/android/providers/telephony/RcsProviderDeleteTest.java b/tests/src/com/android/providers/telephony/RcsProviderDeleteTest.java
index 77a5a70..c0cef0a 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderDeleteTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderDeleteTest.java
@@ -24,16 +24,16 @@
 
 import static com.android.providers.telephony.RcsProvider.RCS_MESSAGE_TABLE;
 import static com.android.providers.telephony.RcsProviderHelper.setup1To1Thread;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/tests/src/com/android/providers/telephony/RcsProviderInsertTest.java b/tests/src/com/android/providers/telephony/RcsProviderInsertTest.java
index 7e63d7f..1a48a49 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderInsertTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderInsertTest.java
@@ -25,15 +25,15 @@
 import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NEW_NAME_COLUMN;
 
 import static com.android.providers.telephony.RcsProviderHelper.setup1To1Thread;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/tests/src/com/android/providers/telephony/RcsProviderQueryTest.java b/tests/src/com/android/providers/telephony/RcsProviderQueryTest.java
index 7b0ed62..c0718a9 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderQueryTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderQueryTest.java
@@ -40,14 +40,12 @@
 import static android.telephony.ims.RcsThreadQueryParams.THREAD_QUERY_PARAMETERS_KEY;
 
 import static com.android.providers.telephony.RcsProviderHelper.setup1To1Thread;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ims.RcsEventQueryParams;
 import android.telephony.ims.RcsGroupThread;
 import android.telephony.ims.RcsMessageQueryParams;
@@ -56,6 +54,8 @@
 import android.telephony.ims.RcsThreadQueryParams;
 import android.test.mock.MockContentResolver;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.providers.telephony.RcsProviderTestable.MockContextWithProvider;
 
 import org.junit.After;
diff --git a/tests/src/com/android/providers/telephony/RcsProviderUpdateTest.java b/tests/src/com/android/providers/telephony/RcsProviderUpdateTest.java
index 45ab0ca..4ba7c1c 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderUpdateTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderUpdateTest.java
@@ -25,19 +25,18 @@
 import static android.provider.Telephony.RcsColumns.RcsMessageDeliveryColumns.DELIVERED_TIMESTAMP_COLUMN;
 import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.CANONICAL_ADDRESS_ID_COLUMN;
 import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_ALIAS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN;
 
 import static com.android.providers.telephony.RcsProviderHelper.setup1To1Thread;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.Telephony.RcsColumns.RcsMessageDeliveryColumns;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java b/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
index c5ad5a0..5cc90eb 100644
--- a/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
+++ b/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
@@ -16,24 +16,6 @@
 
 package com.android.providers.telephony;
 
-import android.content.Context;
-import android.content.pm.ProviderInfo;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-
 import static android.provider.Telephony.ServiceStateTable;
 import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
 
@@ -41,13 +23,23 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
 /**
  * Tests for simple queries of ServiceStateProvider.
  *
diff --git a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
index 49106ee..37cf6e3 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -40,6 +40,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.google.android.mms.pdu.CharacterSets;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -74,6 +76,8 @@
     private final List<ContentValues> mMmsTable = new ArrayList<>();
     /* Table contains parts, addresses of mms */
     private final List<ContentValues> mMmsAllContentValues = new ArrayList<>();
+    /* Table contains parts, addresses of mms for null body test case */
+    private final List<ContentValues> mMmsNullBodyContentValues = new ArrayList<>();
     /* Cursors being used to access sms, mms tables */
     private FakeCursor mSmsCursor, mMmsCursor;
     /* Test data with sms and mms */
@@ -81,7 +85,7 @@
     /* Json representation for the test data */
     private String[] mSmsJson, mMmsJson, mMmsAttachmentJson;
     /* sms, mms json concatenated as json array */
-    private String mAllSmsJson, mAllMmsJson, mMmsAllAttachmentJson;
+    private String mAllSmsJson, mAllMmsJson, mMmsAllAttachmentJson, mMmsAllNullBodyJson;
 
     private StringWriter mStringWriter;
 
@@ -169,7 +173,7 @@
                 new String[]{"+111 (111) 11111111", "+11121212", "example@example.com",
                         "+999999999"} /*addresses*/,
                 3 /*threadId*/, false /*read*/, null /*smil*/, null /*attachmentTypes*/,
-                null /*attachmentFilenames*/);
+                null /*attachmentFilenames*/, mMmsAllContentValues);
 
         mMmsJson[0] = "{\"self_phone\":\"+111111111111111\",\"sub\":\"Subject 1\"," +
                 "\"date\":\"111111\",\"date_sent\":\"111112\",\"m_type\":\"3\",\"v\":\"17\"," +
@@ -191,7 +195,7 @@
                 121 /*body charset*/,
                 new String[]{"+7 (333) ", "example@example.com", "+999999999"} /*addresses*/,
                 4 /*threadId*/, true /*read*/, null /*smil*/, null /*attachmentTypes*/,
-                null /*attachmentFilenames*/);
+                null /*attachmentFilenames*/, mMmsAllContentValues);
         mMmsJson[1] = "{\"date\":\"111122\",\"date_sent\":\"1111112\",\"m_type\":\"4\"," +
                 "\"v\":\"18\",\"msg_box\":\"222\",\"ct_l\":\"location 2\"," +
                 "\"recipients\":[\"example@example.com\",\"+999999999\"]," +
@@ -210,7 +214,7 @@
                 131 /*body charset*/,
                 new String[]{"333 333333333333", "+1232132214124"} /*addresses*/,
                 1 /*threadId*/, false /*read*/, null /*smil*/, null /*attachmentTypes*/,
-                null /*attachmentFilenames*/);
+                null /*attachmentFilenames*/, mMmsAllContentValues);
 
         mMmsJson[2] = "{\"self_phone\":\"+333333333333333\",\"sub\":\"Subject 10\"," +
                 "\"date\":\"111133\",\"date_sent\":\"1111132\",\"m_type\":\"5\",\"v\":\"19\"," +
@@ -239,7 +243,7 @@
                         + " width='100%'/></layout></head><body><par dur='5000ms'>"
                         + "<img src='image000000.jpg' region='Image' /></par></body></smil>",
                 new String[] {"image/jpg"} /*attachmentTypes*/,
-                new String[] {"GreatPict.jpg"}  /*attachmentFilenames*/);
+                new String[] {"GreatPict.jpg"}  /*attachmentFilenames*/, mMmsAllContentValues);
 
         mMmsAttachmentJson[0] = "{\"self_phone\":\"+111111111111111\",\"sub\":\"Subject 1\"," +
                 "\"date\":\"111111\",\"date_sent\":\"111112\",\"m_type\":\"3\",\"v\":\"17\"," +
@@ -255,6 +259,20 @@
 
         mMmsAllAttachmentJson = makeJsonArray(mMmsAttachmentJson);
 
+        createMmsRow(10 /*id*/, 1 /*subid*/, "Subject 1" /*subject*/,
+                100 /*subcharset*/, 111111 /*date*/, 111112 /*datesent*/, 3 /*type*/,
+                17 /*version*/, 0 /*textonly*/,
+                11 /*msgBox*/, "location 1" /*contentLocation*/, "" /*body*/,
+                CharacterSets.DEFAULT_CHARSET /*body charset*/, new String[] {} /*addresses*/,
+                3 /*threadId*/, false /*read*/, null /*smil*/, null /*attachmentTypes*/,
+                null /*attachmentFilenames*/, mMmsNullBodyContentValues);
+
+        mMmsAllNullBodyJson = makeJsonArray(new String[] {"{\"self_phone\":\"+111111111111111\"," +
+                "\"sub\":\"Subject 1\",\"date\":\"111111\",\"date_sent\":\"111112\",\"m_type\":" +
+                "\"3\",\"v\":\"17\",\"msg_box\":\"11\",\"ct_l\":\"location 1\"," +
+                "\"recipients\":[\"+11121212\",\"example@example.com\",\"+999999999\"]," +
+                "\"read\":\"0\", \"mms_addresses\":[],\"mms_charset\":111,\"sub_cs\":\"100\"}"});
+
 
         ContentProvider contentProvider = new MockContentProvider() {
             @Override
@@ -341,7 +359,8 @@
                                        String contentLocation, String body,
                                        int bodyCharset, String[] addresses, long threadId,
                                        boolean read, String smil, String[] attachmentTypes,
-                                       String[] attachmentFilenames) {
+                                       String[] attachmentFilenames,
+                                       List<ContentValues> rowsContainer) {
         ContentValues mmsRow = new ContentValues();
         mmsRow.put(Telephony.Mms._ID, id);
         mmsRow.put(Telephony.Mms.SUBSCRIPTION_ID, subId);
@@ -364,8 +383,8 @@
         final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).
                 appendPath("part").build();
         mCursors.put(partUri, createBodyCursor(body, bodyCharset, smil, attachmentTypes,
-                attachmentFilenames));
-        mMmsAllContentValues.add(mmsRow);
+                attachmentFilenames, rowsContainer));
+        rowsContainer.add(mmsRow);
 
         final Uri addrUri = Telephony.Mms.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).
                 appendPath("addr").build();
@@ -380,7 +399,8 @@
 
     // Cursor with parts of Mms.
     private FakeCursor createBodyCursor(String body, int charset, String existingSmil,
-            String[] attachmentTypes, String[] attachmentFilenames) {
+            String[] attachmentTypes, String[] attachmentFilenames,
+            List<ContentValues> rowsContainer) {
         List<ContentValues> table = new ArrayList<>();
         final String srcName = String.format("text.%06d.txt", 0);
         final String smilBody = TextUtils.isEmpty(existingSmil) ?
@@ -395,7 +415,7 @@
         smilPart.put(Telephony.Mms.Part.CONTENT_ID, "<smil>");
         smilPart.put(Telephony.Mms.Part.CONTENT_LOCATION, "smil.xml");
         smilPart.put(Telephony.Mms.Part.TEXT, smil);
-        mMmsAllContentValues.add(smilPart);
+        rowsContainer.add(smilPart);
 
         // Text part
         final ContentValues bodyPart = new ContentValues();
@@ -407,7 +427,7 @@
         bodyPart.put(Telephony.Mms.Part.CHARSET, charset);
         bodyPart.put(Telephony.Mms.Part.TEXT, body);
         table.add(bodyPart);
-        mMmsAllContentValues.add(bodyPart);
+        rowsContainer.add(bodyPart);
 
         // Attachments
         if (attachmentTypes != null) {
@@ -421,7 +441,7 @@
                 attachmentPart.put(Telephony.Mms.Part.CONTENT_ID, "<"+attachmentFilename+">");
                 attachmentPart.put(Telephony.Mms.Part.CONTENT_LOCATION, attachmentFilename);
                 table.add(attachmentPart);
-                mMmsAllContentValues.add(attachmentPart);
+                rowsContainer.add(attachmentPart);
             }
         }
 
@@ -622,6 +642,17 @@
         assertEquals(7, mmsProvider.getRowsAdded());
     }
 
+    public void testRestoreMmsWithNullBody() throws Exception {
+        JsonReader jsonReader = new JsonReader
+                (new StringReader(addRandomDataToJson(mMmsAllNullBodyJson)));
+        FakeMmsProvider mmsProvider = new FakeMmsProvider(mMmsNullBodyContentValues);
+        mMockContentResolver.addProvider("mms", mmsProvider);
+
+        mTelephonyBackupAgent.putMmsMessagesToProvider(jsonReader);
+
+        assertEquals(3, 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
diff --git a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
index cf534e2..8287352 100644
--- a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
@@ -25,12 +25,12 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.support.test.InstrumentationRegistry;
 import android.telephony.SubscriptionManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index 5723227..b996dc3 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -34,7 +34,6 @@
 import android.os.Process;
 import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
-import android.support.test.InstrumentationRegistry;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
@@ -42,6 +41,8 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
 
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java b/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
index 0a12831..6c2371d 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
@@ -15,23 +15,20 @@
  */
 package com.android.providers.telephony;
 
-import android.content.Context;
+import static android.provider.Telephony.Carriers.*;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.provider.Telephony;
-import android.support.test.InstrumentationRegistry;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.List;
-import java.util.ArrayList;
+import androidx.test.InstrumentationRegistry;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.providers.telephony.TelephonyProvider;
-import static android.provider.Telephony.Carriers.*;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 
 /**
  * A subclass of TelephonyProvider used for testing on an in-memory database