Merge "Do not overwrite carrier/user edits with UNEDITED" am: 18fb27e440 am: 4951b9d97a
am: fbfe455d48  -s ours

Change-Id: I0d72dd19a6dd5e2ba764205737c325489cee7647
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 224fe2f..38f9fc0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
 
     <protected-broadcast android:name="android.provider.action.EXTERNAL_PROVIDER_CHANGE" />
     <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
diff --git a/assets/carrier_list.pb b/assets/carrier_list.pb
new file mode 100644
index 0000000..0568e03
--- /dev/null
+++ b/assets/carrier_list.pb
Binary files differ
diff --git a/res/values-en-rCA/config.xml b/res/values-en-rCA/config.xml
new file mode 100644
index 0000000..99877a6
--- /dev/null
+++ b/res/values-en-rCA/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-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..f11997b
--- /dev/null
+++ b/res/values-en-rCA/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">"Mobile Network Configuration"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"Phone and Messaging Storage"</string>
+</resources>
diff --git a/res/values-en-rXC/config.xml b/res/values-en-rXC/config.xml
new file mode 100644
index 0000000..274d8aa
--- /dev/null
+++ b/res/values-en-rXC/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-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..22950f7
--- /dev/null
+++ b/res/values-en-rXC/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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎Mobile Network Configuration‎‏‎‎‏‎"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎Phone and Messaging Storage‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index e1e6246..6d618f7 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/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/src/com/android/providers/telephony/MmsProvider.java b/src/com/android/providers/telephony/MmsProvider.java
index 547b22e..30158c3 100644
--- a/src/com/android/providers/telephony/MmsProvider.java
+++ b/src/com/android/providers/telephony/MmsProvider.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.ContentProvider;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
@@ -38,6 +39,7 @@
 import android.provider.Telephony.CanonicalAddressesColumns;
 import android.provider.Telephony.Mms;
 import android.provider.Telephony.Mms.Addr;
+import android.provider.Telephony.Mms.Inbox;
 import android.provider.Telephony.Mms.Part;
 import android.provider.Telephony.Mms.Rate;
 import android.provider.Telephony.MmsSms;
@@ -360,6 +362,7 @@
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         ContentValues finalValues;
         Uri res = Mms.CONTENT_URI;
+        Uri caseSpecificUri = null;
         long rowId;
 
         if (table.equals(TABLE_PDU)) {
@@ -409,6 +412,11 @@
                 return null;
             }
 
+            // Notify change when an MMS is received.
+            if (msgBox == Mms.MESSAGE_BOX_INBOX) {
+                caseSpecificUri = ContentUris.withAppendedId(Mms.Inbox.CONTENT_URI, rowId);
+            }
+
             res = Uri.parse(res + "/" + rowId);
         } else if (table.equals(TABLE_ADDR)) {
             finalValues = new ContentValues(values);
@@ -584,7 +592,7 @@
         }
 
         if (notify) {
-            notifyChange(res);
+            notifyChange(res, caseSpecificUri);
         }
         return res;
     }
@@ -680,7 +688,7 @@
         }
 
         if ((deletedRows > 0) && notify) {
-            notifyChange(uri);
+            notifyChange(uri, null);
         }
         return deletedRows;
     }
@@ -856,7 +864,7 @@
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         int count = db.update(table, finalValues, finalSelection, selectionArgs);
         if (notify && (count > 0)) {
-            notifyChange(uri);
+            notifyChange(uri, null);
         }
         return count;
     }
@@ -973,11 +981,16 @@
         values.remove(Mms._ID);
     }
 
-    private void notifyChange(final Uri uri) {
+    private void notifyChange(final Uri uri, final Uri caseSpecificUri) {
         final Context context = getContext();
+        if (caseSpecificUri != null) {
+            context.getContentResolver().notifyChange(
+                caseSpecificUri, null, true, UserHandle.USER_ALL);
+        }
         context.getContentResolver().notifyChange(
                 MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
-        ProviderUtil.notifyIfNotDefaultSmsApp(uri, getCallingPackage(), context);
+        ProviderUtil.notifyIfNotDefaultSmsApp(caseSpecificUri == null ? uri : caseSpecificUri,
+                getCallingPackage(), context);
     }
 
     private final static String TAG = "MmsProvider";
diff --git a/tests/Android.mk b/tests/Android.mk
index ffd2e39..0065386 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -4,11 +4,15 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := mockito-target \
-                               legacy-android-test \
                                compatibility-device-util \
                                android-support-test
 
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_JAVA_LIBRARIES := \
+    android.test.runner \
+    telephony-common \
+    android.test.base \
+    android.test.mock \
+
 
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index b935a31..7fd7f61 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -815,4 +815,133 @@
             // Should catch SecurityException.
         }
     }
+
+    /**
+     * Verify that user/carrier edited/deleted APNs have priority in the EDITED field over
+     * insertions which set EDITED=UNEDITED. In these cases instead of merging the APNs using the
+     * new APN's value we keep the old value.
+     */
+    @Test
+    @SmallTest
+    public void testPreserveEdited() {
+        preserveEditedValueInMerge(Carriers.USER_EDITED);
+    }
+
+    @Test
+    @SmallTest
+    public void testPreserveUserDeleted() {
+        preserveDeletedValueInMerge(Carriers.USER_DELETED);
+    }
+
+    @Test
+    @SmallTest
+    public void testPreserveUserDeletedButPresentInXml() {
+        preserveDeletedValueInMerge(Carriers.USER_DELETED_BUT_PRESENT_IN_XML);
+    }
+
+    @Test
+    @SmallTest
+    public void testPreserveCarrierEdited() {
+        preserveEditedValueInMerge(Carriers.CARRIER_EDITED);
+    }
+
+    @Test
+    @SmallTest
+    public void testPreserveCarrierDeleted() {
+        preserveDeletedValueInMerge(Carriers.CARRIER_DELETED);
+    }
+
+    @Test
+    @SmallTest
+    public void testPreserveCarrierDeletedButPresentInXml() {
+        preserveDeletedValueInMerge(Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML);
+    }
+
+    private void preserveEditedValueInMerge(int value) {
+        // insert user deleted APN
+        String carrierName1 = "carrier1";
+        String numeric1 = "123234";
+        String mcc1 = "123";
+        String mnc1 = "234";
+        ContentValues editedValue = new ContentValues();
+        editedValue.put(Carriers.NAME, carrierName1);
+        editedValue.put(Carriers.NUMERIC, numeric1);
+        editedValue.put(Carriers.MCC, mcc1);
+        editedValue.put(Carriers.MNC, mnc1);
+        editedValue.put(Carriers.EDITED, value);
+        assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
+
+        Cursor cur = mContentResolver.query(URI_TELEPHONY, null, null, null, null);
+        assertEquals(1, cur.getCount());
+
+        // insert APN that conflicts with edited APN
+        String carrierName2 = "carrier2";
+        ContentValues values = new ContentValues();
+        values.put(Carriers.NAME, carrierName2);
+        values.put(Carriers.NUMERIC, numeric1);
+        values.put(Carriers.MCC, mcc1);
+        values.put(Carriers.MNC, mnc1);
+        values.put(Carriers.EDITED, Carriers.UNEDITED);
+        mContentResolver.insert(URI_TELEPHONY, values);
+
+        String[] testProjection = {
+            Carriers.NAME,
+            Carriers.APN,
+            Carriers.EDITED,
+            Carriers.TYPE,
+            Carriers.PROTOCOL,
+            Carriers.BEARER_BITMASK,
+        };
+        final int indexOfName = 0;
+        final int indexOfEdited = 2;
+
+        // Assert that the conflicting APN is merged into the existing user-edited APN, so only 1
+        // APN exists in the db
+        cur = mContentResolver.query(URI_TELEPHONY, testProjection, null, null, null);
+        assertEquals(1, cur.getCount());
+        cur.moveToFirst();
+        assertEquals(carrierName2, cur.getString(indexOfName));
+        assertEquals(value, cur.getInt(indexOfEdited));
+    }
+
+    private void preserveDeletedValueInMerge(int value) {
+        // insert user deleted APN
+        String carrierName1 = "carrier1";
+        String numeric1 = "123234";
+        String mcc1 = "123";
+        String mnc1 = "234";
+        ContentValues editedValue = new ContentValues();
+        editedValue.put(Carriers.NAME, carrierName1);
+        editedValue.put(Carriers.NUMERIC, numeric1);
+        editedValue.put(Carriers.MCC, mcc1);
+        editedValue.put(Carriers.MNC, mnc1);
+        editedValue.put(Carriers.EDITED, value);
+        assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
+
+        // insert APN that conflicts with edited APN
+        String carrierName2 = "carrier2";
+        ContentValues values = new ContentValues();
+        values.put(Carriers.NAME, carrierName2);
+        values.put(Carriers.NUMERIC, numeric1);
+        values.put(Carriers.MCC, mcc1);
+        values.put(Carriers.MNC, mnc1);
+        values.put(Carriers.EDITED, Carriers.UNEDITED);
+        mContentResolver.insert(URI_TELEPHONY, values);
+
+        String[] testProjection = {
+            Carriers.NAME,
+            Carriers.APN,
+            Carriers.EDITED,
+            Carriers.TYPE,
+            Carriers.PROTOCOL,
+            Carriers.BEARER_BITMASK,
+        };
+        final int indexOfEdited = 2;
+
+        // Assert that the conflicting APN is merged into the existing user-deleted APN.
+        // Entries marked deleted will not show up in queries so we verify that no APNs can
+        // be seen
+        Cursor cur = mContentResolver.query(URI_TELEPHONY, testProjection, null, null, null);
+        assertEquals(0, cur.getCount());
+    }
 }