Merge "Fix apn restore issue for multi-sim"
am: 6a39c8ba87

Change-Id: Icfda508bc792f9af8f9df35c17f13db6bb3c7f7f
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 78ccd50..c33f485 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -27,6 +27,7 @@
 import static android.provider.Telephony.Carriers.CARRIER_ENABLED;
 import static android.provider.Telephony.Carriers.CONTENT_URI;
 import static android.provider.Telephony.Carriers.CURRENT;
+import static android.provider.Telephony.Carriers.DEFAULT_SORT_ORDER;
 import static android.provider.Telephony.Carriers.EDITED;
 import static android.provider.Telephony.Carriers.MAX_CONNS;
 import static android.provider.Telephony.Carriers.MAX_CONNS_TIME;
@@ -104,7 +105,11 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IApnSourceService;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.SubscriptionController;
+import com.android.internal.telephony.dataconnection.ApnSetting;
+import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -211,7 +216,8 @@
     private static final List<String> CARRIERS_UNIQUE_FIELDS = new ArrayList<String>();
     private static final Map<String, String> CARRIERS_UNIQUE_FIELDS_DEFAULTS = new HashMap();
 
-    private static Boolean s_apnSourceServiceExists;
+    @VisibleForTesting
+    static Boolean s_apnSourceServiceExists;
 
     protected final Object mLock = new Object();
     @GuardedBy("mLock")
@@ -3095,9 +3101,19 @@
 
     private void restoreDefaultAPN(int subId) {
         SQLiteDatabase db = getWritableDatabase();
+        TelephonyManager telephonyManager =
+                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        String where = null;
+        if (telephonyManager.getPhoneCount() > 1) {
+            where = getWhereClauseForRestoreDefaultApn(db, subId);
+        }
+        if (TextUtils.isEmpty(where)) {
+            where = IS_NOT_OWNED_BY_DPC;
+        }
+        log("restoreDefaultAPN: where: " + where);
 
         try {
-            db.delete(CARRIERS_TABLE, IS_NOT_OWNED_BY_DPC, null);
+            db.delete(CARRIERS_TABLE, where, null);
         } catch (SQLException e) {
             loge("got exception when deleting to restore: " + e);
         }
@@ -3123,6 +3139,54 @@
         }
     }
 
+    private String getWhereClauseForRestoreDefaultApn(SQLiteDatabase db, int subId) {
+        IccRecords iccRecords = getIccRecords(subId);
+        if (iccRecords == null) {
+            return null;
+        }
+        TelephonyManager telephonyManager =
+                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        String simOperator = telephonyManager.getSimOperator(subId);
+        Cursor cursor = db.query(CARRIERS_TABLE, new String[] {MVNO_TYPE, MVNO_MATCH_DATA},
+                NUMERIC + "='" + simOperator + "'", null, null, null, DEFAULT_SORT_ORDER);
+        String where = null;
+
+        if (cursor != null) {
+            cursor.moveToFirst();
+            while (!cursor.isAfterLast()) {
+                String mvnoType = cursor.getString(0 /* MVNO_TYPE index */);
+                String mvnoMatchData = cursor.getString(1 /* MVNO_MATCH_DATA index */);
+                if (!TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)
+                        && ApnSetting.mvnoMatches(iccRecords, mvnoType, mvnoMatchData)) {
+                    where = NUMERIC + "='" + simOperator + "'"
+                            + " AND " + MVNO_TYPE + "='" + mvnoType + "'"
+                            + " AND " + MVNO_MATCH_DATA + "='" + mvnoMatchData + "'"
+                            + " AND " + IS_NOT_OWNED_BY_DPC;
+                    break;
+                }
+                cursor.moveToNext();
+            }
+            cursor.close();
+
+            if (TextUtils.isEmpty(where)) {
+                where = NUMERIC + "='" + simOperator + "'"
+                        + " AND (" + MVNO_TYPE + "='' OR " + MVNO_MATCH_DATA + "='')"
+                        + " AND " + IS_NOT_OWNED_BY_DPC;
+            }
+        }
+        return where;
+    }
+
+    @VisibleForTesting
+    IccRecords getIccRecords(int subId) {
+        TelephonyManager telephonyManager =
+                TelephonyManager.from(getContext()).createForSubscriptionId(subId);
+        int family = telephonyManager.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ?
+                UiccController.APP_FAM_3GPP : UiccController.APP_FAM_3GPP2;
+        return UiccController.getInstance().getIccRecords(
+                SubscriptionManager.getPhoneId(subId), family);
+    }
+
     private synchronized void updateApnDb() {
         if (apnSourceServiceExists(getContext())) {
             loge("called updateApnDb when apn source service exists");
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index 14e2491..5e10917 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -90,6 +90,10 @@
     private static final Uri CONTENT_URI_WITH_SUBID = Uri.parse(
             "content://telephony/carriers/subId/" + TEST_SUBID);
 
+    // Used to test the "restore to default"
+    private static final Uri URL_RESTOREAPN_USING_SUBID = Uri.parse(
+            "content://telephony/carriers/restore/subId/" + TEST_SUBID);
+
     // Constants for DPC related tests.
     private static final Uri URI_DPC = Uri.parse("content://telephony/carriers/dpc");
     private static final Uri URI_TELEPHONY = Carriers.CONTENT_URI;
@@ -971,4 +975,94 @@
         Cursor cur = mContentResolver.query(URI_TELEPHONY, testProjection, null, null, null);
         assertEquals(0, cur.getCount());
     }
+
+    /**
+     * Test URL_RESTOREAPN_USING_SUBID works correctly.
+     */
+    @Test
+    @SmallTest
+    public void testRestoreDefaultApn() {
+        // setup for multi-SIM
+        TelephonyManager telephonyManager =
+                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(2).when(telephonyManager).getPhoneCount();
+
+        // create APN to be deleted (including MVNO values)
+        ContentValues targetValues = new ContentValues();
+        targetValues.put(Carriers.APN, "apnName");
+        targetValues.put(Carriers.NAME, "name");
+        targetValues.put(Carriers.NUMERIC, TEST_OPERATOR);
+        targetValues.put(Carriers.MVNO_TYPE, "spn");
+        targetValues.put(Carriers.MVNO_MATCH_DATA, TelephonyProviderTestable.TEST_SPN);
+        // create other operator APN (sama MCCMNC)
+        ContentValues otherValues = new ContentValues();
+        final String otherApn = "otherApnName";
+        final String otherName = "otherName";
+        final String otherMvnoTyp = "spn";
+        final String otherMvnoMatchData = "testOtherOperator";
+        otherValues.put(Carriers.APN, otherApn);
+        otherValues.put(Carriers.NAME, otherName);
+        otherValues.put(Carriers.NUMERIC, TEST_OPERATOR);
+        otherValues.put(Carriers.MVNO_TYPE, otherMvnoTyp);
+        otherValues.put(Carriers.MVNO_MATCH_DATA, otherMvnoMatchData);
+
+        // insert APNs
+        Log.d(TAG, "testRestoreDefaultApn: Bulk inserting contentValues=" + targetValues + ", "
+                + otherValues);
+        ContentValues[] values = new ContentValues[]{ targetValues, otherValues };
+        mContentResolver.bulkInsert(Carriers.CONTENT_URI, values);
+
+        // restore to default
+        mContentResolver.delete(URL_RESTOREAPN_USING_SUBID, null, null);
+
+        // get values in table
+        final String[] testProjection =
+        {
+            Carriers.APN,
+            Carriers.NAME,
+            Carriers.MVNO_TYPE,
+            Carriers.MVNO_MATCH_DATA,
+        };
+        // verify that deleted result match results of query
+        Cursor cursor = mContentResolver.query(
+                Carriers.CONTENT_URI, testProjection, null, null, null);
+        assertEquals(1, cursor.getCount());
+        cursor.moveToFirst();
+        assertEquals(otherApn, cursor.getString(0));
+        assertEquals(otherName, cursor.getString(1));
+        assertEquals(otherMvnoTyp, cursor.getString(2));
+        assertEquals(otherMvnoMatchData, cursor.getString(3));
+
+        // create APN to be deleted (not include MVNO values)
+        ContentValues targetValues2 = new ContentValues();
+        targetValues2.put(Carriers.APN, "apnName");
+        targetValues2.put(Carriers.NAME, "name");
+        targetValues2.put(Carriers.NUMERIC, TEST_OPERATOR);
+
+        // insert APN
+        mContentResolver.insert(Carriers.CONTENT_URI, targetValues2);
+
+        // restore to default
+        mContentResolver.delete(URL_RESTOREAPN_USING_SUBID, null, null);
+
+        // verify that deleted result match results of query
+        cursor = mContentResolver.query(Carriers.CONTENT_URI, testProjection, null, null, null);
+        assertEquals(1, cursor.getCount());
+        cursor.moveToFirst();
+        assertEquals(otherApn, cursor.getString(0));
+        assertEquals(otherName, cursor.getString(1));
+        assertEquals(otherMvnoTyp, cursor.getString(2));
+        assertEquals(otherMvnoMatchData, cursor.getString(3));
+
+        // setup for single-SIM
+        doReturn(1).when(telephonyManager).getPhoneCount();
+
+        // restore to default
+        mContentResolver.delete(URL_RESTOREAPN_USING_SUBID, null, null);
+
+        // verify that deleted values are gone
+        cursor = mContentResolver.query(
+                Carriers.CONTENT_URI, testProjection, null, null, null);
+        assertEquals(0, cursor.getCount());
+    }
 }
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java b/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
index 2d3acd7..0a12831 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTestable.java
@@ -26,8 +26,12 @@
 
 import java.util.List;
 import java.util.ArrayList;
+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
@@ -35,6 +39,9 @@
 public class TelephonyProviderTestable extends TelephonyProvider {
     private static final String TAG = "TelephonyProviderTestable";
 
+    @VisibleForTesting
+    public static final String TEST_SPN = "testspn";
+
     private InMemoryTelephonyProviderDbHelper mDbHelper;
     private MockInjector mMockInjector;
 
@@ -51,6 +58,7 @@
     public boolean onCreate() {
         Log.d(TAG, "onCreate called: mDbHelper = new InMemoryTelephonyProviderDbHelper()");
         mDbHelper = new InMemoryTelephonyProviderDbHelper();
+        s_apnSourceServiceExists = false;
         return true;
     }
 
@@ -82,6 +90,14 @@
         return false;
     }
 
+    @Override
+    IccRecords getIccRecords(int subId) {
+        Log.d(TAG, "getIccRecords called");
+        IccRecords iccRecords = mock(IccRecords.class);
+        doReturn(TEST_SPN).when(iccRecords).getServiceProviderName();
+        return iccRecords;
+    }
+
     public void fakeCallingUid(int uid) {
         mMockInjector.fakeCallingUid(uid);
     }