Merge "Improve carrier id testability"
diff --git a/assets/latest_carrier_id/carrier_list.pb b/assets/latest_carrier_id/carrier_list.pb
index 7edf27a..d5c520e 100644
--- a/assets/latest_carrier_id/carrier_list.pb
+++ b/assets/latest_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/latest_carrier_id/carrier_list.textpb b/assets/latest_carrier_id/carrier_list.textpb
index 52fc821..dd3fe60 100644
--- a/assets/latest_carrier_id/carrier_list.textpb
+++ b/assets/latest_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk28_carrier_id/carrier_list.pb b/assets/sdk28_carrier_id/carrier_list.pb
index 700eb89..88c6564 100644
--- a/assets/sdk28_carrier_id/carrier_list.pb
+++ b/assets/sdk28_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk28_carrier_id/carrier_list.textpb b/assets/sdk28_carrier_id/carrier_list.textpb
index 619d989..287c3d5 100644
--- a/assets/sdk28_carrier_id/carrier_list.textpb
+++ b/assets/sdk28_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.pb b/assets/sdk29_carrier_id/carrier_list.pb
index 3519d2c..0e1dde8 100644
--- a/assets/sdk29_carrier_id/carrier_list.pb
+++ b/assets/sdk29_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.textpb b/assets/sdk29_carrier_id/carrier_list.textpb
index b1c6825..e52cb71 100644
--- a/assets/sdk29_carrier_id/carrier_list.textpb
+++ b/assets/sdk29_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk30_carrier_id/carrier_list.pb b/assets/sdk30_carrier_id/carrier_list.pb
index a5c1bbf..44241f2 100644
--- a/assets/sdk30_carrier_id/carrier_list.pb
+++ b/assets/sdk30_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk30_carrier_id/carrier_list.textpb b/assets/sdk30_carrier_id/carrier_list.textpb
index 50ac074..b0a87ef 100644
--- a/assets/sdk30_carrier_id/carrier_list.textpb
+++ b/assets/sdk30_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index 6ff16e5..99e9ddd 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -904,31 +904,62 @@
                 count = db.delete("sr_pending", where, whereArgs);
                 break;
 
+            case SMS_ALL_ICC:
+            case SMS_ALL_ICC_SUBID:
+                {
+                    int subId;
+                    int deletedCnt;
+                    if (match == SMS_ALL_ICC) {
+                        subId = SmsManager.getDefaultSmsSubscriptionId();
+                    } else {
+                        try {
+                            subId = Integer.parseInt(url.getPathSegments().get(1));
+                        } catch (NumberFormatException e) {
+                            throw new IllegalArgumentException("Wrong path segements, uri= " + url);
+                        }
+                    }
+                    deletedCnt = deleteAllMessagesFromIcc(subId);
+                    // Notify changes even failure case since there might be some changes should be
+                    // known.
+                    getContext()
+                            .getContentResolver()
+                            .notifyChange(
+                                    match == SMS_ALL_ICC ? ICC_URI : ICC_SUBID_URI,
+                                    null,
+                                    true,
+                                    UserHandle.USER_ALL);
+                    return deletedCnt;
+                }
+
             case SMS_ICC:
             case SMS_ICC_SUBID:
-                int subId;
-                int messageIndex;
-                boolean success;
-                try {
-                    if (match == SMS_ICC) {
-                        subId = SmsManager.getDefaultSmsSubscriptionId();
-                        messageIndex = Integer.parseInt(url.getPathSegments().get(1));
-                    } else {
-                        subId = Integer.parseInt(url.getPathSegments().get(1));
-                        messageIndex = Integer.parseInt(url.getPathSegments().get(2));
+                {
+                    int subId;
+                    int messageIndex;
+                    boolean success;
+                    try {
+                        if (match == SMS_ICC) {
+                            subId = SmsManager.getDefaultSmsSubscriptionId();
+                            messageIndex = Integer.parseInt(url.getPathSegments().get(1));
+                        } else {
+                            subId = Integer.parseInt(url.getPathSegments().get(1));
+                            messageIndex = Integer.parseInt(url.getPathSegments().get(2));
+                        }
+                    } catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("Wrong path segements, uri= " + url);
                     }
-                } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Wrong path segements, uri= " + url);
+                    success = deleteMessageFromIcc(subId, messageIndex);
+                    // Notify changes even failure case since there might be some changes should be
+                    // known.
+                    getContext()
+                            .getContentResolver()
+                            .notifyChange(
+                                    match == SMS_ICC ? ICC_URI : ICC_SUBID_URI,
+                                    null,
+                                    true,
+                                    UserHandle.USER_ALL);
+                    return success ? 1 : 0; // return deleted count
                 }
-                success = deleteMessageFromIcc(subId, messageIndex);
-                // Notify changes even failure case since there might be some changes should be
-                // known.
-                getContext().getContentResolver().notifyChange(
-                        match == SMS_ICC ? ICC_URI : ICC_SUBID_URI,
-                        null,
-                        true,
-                        UserHandle.USER_ALL);
-                return success ? 1 : 0; // return deleted count
 
             default:
                 throw new IllegalArgumentException("Unknown URL");
@@ -962,6 +993,37 @@
         }
     }
 
+    /**
+     * Deletes all the messages from the ICC for a subscription ID.
+     *
+     * @param subId the subscription ID.
+     * @return return deleted messaegs count.
+     */
+    private int deleteAllMessagesFromIcc(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription ID " + subId);
+        }
+        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
+
+        // Use phone app permissions to avoid UID mismatch in AppOpsManager.noteOp() call.
+        long token = Binder.clearCallingIdentity();
+        try {
+            int deletedCnt = 0;
+            int maxIndex = smsManager.getSmsCapacityOnIcc();
+            for (int messageIndex = 1; messageIndex <= maxIndex; messageIndex++) {
+                if (smsManager.deleteMessageFromIcc(messageIndex)) {
+                    deletedCnt++;
+                } else {
+                    Log.e(TAG, "Fail to delete SMS at index " + messageIndex
+                            + " for subId " + subId);
+                }
+            }
+            return deletedCnt;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @Override
     public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
         final int callerUid = Binder.getCallingUid();
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 506c474..22d2cb3 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -3113,7 +3113,14 @@
     private Cursor getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn,
             String selection, String[] selectionArgs, String sort, int subId) {
         Cursor ret;
-        final TelephonyManager tm = ((TelephonyManager) getContext()
+        Context context = getContext();
+        SubscriptionManager subscriptionManager = (SubscriptionManager) context
+                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        if (!subscriptionManager.isActiveSubscriptionId(subId)) {
+            return null;
+        }
+
+        final TelephonyManager tm = ((TelephonyManager) context
                 .getSystemService(Context.TELEPHONY_SERVICE))
                 .createForSubscriptionId(subId);
         SQLiteDatabase db = getReadableDatabase();
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index 2018e2c..4673aac 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -51,11 +51,8 @@
 import junit.framework.TestCase;
 
 import org.junit.Test;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.IntStream;
@@ -123,12 +120,14 @@
     private class MockContextWithProvider extends MockContext {
         private final MockContentResolver mResolver;
         private TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
+        private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
 
         private final List<String> GRANTED_PERMISSIONS = Arrays.asList(
                 Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.WRITE_APN_SETTINGS,
                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
 
-        public MockContextWithProvider(TelephonyProvider telephonyProvider) {
+        public MockContextWithProvider(TelephonyProvider telephonyProvider,
+                Boolean isActiveSubscription) {
             mResolver = new MockContentResolver() {
                 @Override
                 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
@@ -146,7 +145,8 @@
 
             // return test subId 0 for all operators
             doReturn(TEST_OPERATOR).when(mTelephonyManager).getSimOperator(anyInt());
-
+            doReturn(isActiveSubscription).when(mSubscriptionManager)
+                    .isActiveSubscriptionId(anyInt());
             doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
             doReturn(TEST_OPERATOR).when(mTelephonyManager).getSimOperator();
             doReturn(TEST_CARRIERID).when(mTelephonyManager).getSimCarrierId();
@@ -171,6 +171,9 @@
             if (name.equals(Context.TELEPHONY_SERVICE)) {
                 Log.d(TAG, "getSystemService: returning mock TM");
                 return mTelephonyManager;
+            } else if (name.equals(Context.TELEPHONY_SUBSCRIPTION_SERVICE)){
+                Log.d(TAG, "getSystemService: returning mock SubscriptionManager");
+                return mSubscriptionManager;
             } else {
                 Log.d(TAG, "getSystemService: returning null");
                 return null;
@@ -181,6 +184,8 @@
         public String getSystemServiceName(Class<?> serviceClass) {
             if (serviceClass.equals(TelephonyManager.class)) {
               return Context.TELEPHONY_SERVICE;
+            } else if (serviceClass.equals(SubscriptionManager.class)) {
+                return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
             } else {
                 Log.d(TAG, "getSystemServiceName: returning null");
                 return null;
@@ -223,12 +228,15 @@
         super.setUp();
         MockitoAnnotations.initMocks(this);
         mTelephonyProviderTestable = new TelephonyProviderTestable();
-        mContext = new MockContextWithProvider(mTelephonyProviderTestable);
-        mContentResolver = (MockContentResolver) mContext.getContentResolver();
         notifyChangeCount = 0;
         notifyChangeRestoreCount = 0;
     }
 
+    private void setUpMockContext(boolean isActiveSubId) {
+        mContext = new MockContextWithProvider(mTelephonyProviderTestable, isActiveSubId);
+        mContentResolver = mContext.getContentResolver();
+    }
+
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
@@ -242,6 +250,8 @@
     @Test
     @SmallTest
     public void testBulkInsertCarriers() {
+        setUpMockContext(true);
+
         // insert 2 test contentValues
         ContentValues contentValues = new ContentValues();
         final String insertApn = "exampleApnName";
@@ -313,6 +323,8 @@
     @Test
     @SmallTest
     public void testMccMncMigration() {
+        setUpMockContext(true);
+
         CarrierIdProviderTestable carrierIdProvider = new CarrierIdProviderTestable();
         carrierIdProvider.initializeForTesting(mContext);
         mContentResolver.addProvider(Telephony.CarrierId.All.CONTENT_URI.getAuthority(),
@@ -372,6 +384,8 @@
     @Test
     @SmallTest
     public void testUpdateConflictingCarriers() {
+        setUpMockContext(true);
+
         // insert 2 test contentValues
         ContentValues contentValues = new ContentValues();
         final String insertApn = "exampleApnName";
@@ -429,6 +443,8 @@
     }
 
     private void doSimpleTestForUri(Uri uri) {
+        setUpMockContext(true);
+
         // insert test contentValues
         ContentValues contentValues = new ContentValues();
         final String insertApn = "exampleApnName";
@@ -479,6 +495,8 @@
     @Test
     @SmallTest
     public void testOwnedBy() {
+        setUpMockContext(true);
+
         // insert test contentValues
         ContentValues contentValues = new ContentValues();
         final String insertApn = "exampleApnName";
@@ -542,6 +560,8 @@
     @Test
     @SmallTest
     public void testSimTable() {
+        setUpMockContext(true);
+
         // insert test contentValues
         ContentValues contentValues = new ContentValues();
         final int insertSubId = 11;
@@ -627,6 +647,8 @@
     @Test
     @SmallTest
     public void testEnforceManagedUri() {
+        setUpMockContext(true);
+
         mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
         final int current = 1;
@@ -749,6 +771,8 @@
      * Test URL_TELEPHONY cannot insert, query, update or delete DPC records.
      */
     public void testTelephonyUriDpcRecordAccessControl() {
+        setUpMockContext(true);
+
         mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
         final int current = 1;
@@ -825,6 +849,8 @@
     @Test
     @SmallTest
     public void testDpcUri() {
+        setUpMockContext(true);
+
         int dpcRecordId = 0, othersRecordId = 0;
         try {
             mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
@@ -916,6 +942,8 @@
     @Test
     @SmallTest
     public void testDpcUriOnConflict() {
+        setUpMockContext(true);
+
         int dpcRecordId1 = 0, dpcRecordId2 = 0;
         try {
             mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
@@ -988,6 +1016,8 @@
     @Test
     @SmallTest
     public void testAccessUrlDpcThrowSecurityExceptionFromOtherUid() {
+        setUpMockContext(true);
+
         mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID + 123456);
 
         // Test insert().
@@ -1091,6 +1121,8 @@
     }
 
     private void preserveEditedValueInMerge(int value) {
+        setUpMockContext(true);
+
         // insert user deleted APN
         String carrierName1 = "carrier1";
         String numeric1 = "123234";
@@ -1138,6 +1170,8 @@
     }
 
     private void preserveDeletedValueInMerge(int value) {
+        setUpMockContext(true);
+
         // insert user deleted APN
         String carrierName1 = "carrier1";
         String numeric1 = "123234";
@@ -1184,6 +1218,8 @@
     @Test
     @SmallTest
     public void testQueryPreferredApn() {
+        setUpMockContext(true);
+
         // create APNs
         ContentValues preferredValues = new ContentValues();
         final String preferredApn = "preferredApn";
@@ -1230,6 +1266,8 @@
     @Test
     @SmallTest
     public void testApnSetId() {
+        setUpMockContext(true);
+
         // create APNs
         ContentValues values1 = new ContentValues();
         final String apn = "apnName";
@@ -1274,6 +1312,8 @@
     @Test
     @SmallTest
     public void testPreferApnSetUrl() {
+        setUpMockContext(true);
+
         // create APNs
         ContentValues values1 = new ContentValues();
         final String apn = "apnName";
@@ -1339,6 +1379,8 @@
     @Test
     @SmallTest
     public void testRestoreDefaultApn() {
+        setUpMockContext(true);
+
         // setup for multi-SIM
         TelephonyManager telephonyManager =
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -1435,6 +1477,8 @@
     @Test
     @SmallTest
     public void testUpdateWfcEnabled() {
+        setUpMockContext(true);
+
         // insert test contentValues
         ContentValues contentValues = new ContentValues();
         final int insertSubId = 1;
@@ -1481,6 +1525,8 @@
     @Test
     @SmallTest
     public void testSIMAPNLIST_MatchTheMVNOAPN() {
+        setUpMockContext(true);
+
         // Test on getSubscriptionMatchingAPNList() step 1
         final String apnName = "apnName";
         final String carrierName = "name";
@@ -1519,6 +1565,7 @@
                         Carriers.NUMERIC,
                         Carriers.MVNO_MATCH_DATA
                 };
+
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
                 testProjection, null, null, null);
 
@@ -1534,6 +1581,8 @@
     @Test
     @SmallTest
     public void testSIMAPNLIST_MatchTheMNOAPN() {
+        setUpMockContext(true);
+
         // Test on getSubscriptionMatchingAPNList() step 2
         final String apnName = "apnName";
         final String carrierName = "name";
@@ -1553,6 +1602,7 @@
                         Carriers.NAME,
                         Carriers.NUMERIC,
                 };
+
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
                 testProjection, null, null, null);
 
@@ -1565,6 +1615,8 @@
     @Test
     @SmallTest
     public void testSIMAPNLIST_MatchTheCarrierIDANDMNOAPN() {
+        setUpMockContext(true);
+
         // Test on getSubscriptionMatchingAPNList() will return the {MCCMNC}
         final String apnName = "apnName";
         final String carrierName = "name";
@@ -1592,6 +1644,7 @@
                 Carriers.NAME,
                 Carriers.CARRIER_ID,
             };
+
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST, testProjection, null, null, null);
 
         // The query based on SIM_APN_LIST will return MNO APN and the APN that has carrier id
@@ -1601,6 +1654,8 @@
     @Test
     @SmallTest
     public void testSIMAPNLIST_MatchTheCarrierAPNAndMVNOAPN() {
+        setUpMockContext(true);
+
         final String apnName = "apnName";
         final String carrierName = "name";
         final String mvnoType = "spn";
@@ -1638,6 +1693,7 @@
                 Carriers.CARRIER_ID,
                 Carriers.MVNO_TYPE,
             };
+
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
             testProjection, null, null, null);
 
@@ -1648,4 +1704,34 @@
                     || !TextUtils.isEmpty(cursor.getString(3)));
         }
     }
+
+    @Test
+    @SmallTest
+    public void testSIMAPNLIST_isNotActiveSubscription() {
+        setUpMockContext(false);
+
+        // Test on getSubscriptionMatchingAPNList() step 2
+        final String apnName = "apnName";
+        final String carrierName = "name";
+        final String numeric = TEST_OPERATOR;
+
+        // Insert the MNO APN
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(Carriers.APN, apnName);
+        contentValues.put(Carriers.NAME, carrierName);
+        contentValues.put(Carriers.NUMERIC, numeric);
+        mContentResolver.insert(Carriers.CONTENT_URI, contentValues);
+
+        // Query DB
+        final String[] testProjection =
+                {
+                        Carriers.APN,
+                        Carriers.NAME,
+                        Carriers.NUMERIC,
+                };
+        Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
+                testProjection, null, null, null);
+
+        assertNull(cursor);
+    }
 }