Merge "Load APN configure file from product image preferentially instead of system image"
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 7f2de12..77093a6 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -644,8 +644,6 @@
                 row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.CARRIER_ID));
             } else if (CarrierId.CARRIER_NAME.equals(columnName)) {
                 row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.CARRIER_NAME));
-            } else if (CarrierId.MNO_CARRIER_ID.equals(columnName)) {
-                row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.MNO_CARRIER_ID));
             } else {
                 throw new IllegalArgumentException("Invalid column " + projectionIn[i]);
             }
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index f7a446b..feac8f4 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -552,7 +552,8 @@
         createCommonTables(db);
 
         if (IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
-            RcsProviderHelper.createRcsTables(db);
+            RcsProviderThreadHelper.createThreadTables(db);
+            RcsProviderParticipantHelper.createParticipantTables(db);
         }
 
         createCommonTriggers(db);
@@ -1640,7 +1641,8 @@
             if (currentVersion <= 67 || !IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
                 return;
             }
-            RcsProviderHelper.createRcsTables(db);
+            RcsProviderThreadHelper.createThreadTables(db);
+            RcsProviderParticipantHelper.createParticipantTables(db);
             return;
         }
 
diff --git a/src/com/android/providers/telephony/RcsProvider.java b/src/com/android/providers/telephony/RcsProvider.java
index 83ff130..c0fffd0 100644
--- a/src/com/android/providers/telephony/RcsProvider.java
+++ b/src/com/android/providers/telephony/RcsProvider.java
@@ -15,9 +15,6 @@
  */
 package com.android.providers.telephony;
 
-import static com.android.providers.telephony.RcsProviderHelper.ID;
-import static com.android.providers.telephony.RcsProviderHelper.THREAD_TABLE;
-
 import android.app.AppOpsManager;
 import android.content.ContentProvider;
 import android.content.ContentValues;
@@ -32,19 +29,22 @@
 /**
  * Content provider to handle RCS messages. The functionality here is similar to SmsProvider,
  * MmsProvider etc. This is not meant to be public.
+ *
  * @hide
  */
 public class RcsProvider extends ContentProvider {
-    private final static String TAG = "RcsProvider";
+    static final String TAG = "RcsProvider";
     static final String AUTHORITY = "rcs";
     private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
 
     private static final int THREAD = 1;
+    private static final int PARTICIPANT = 2;
 
     SQLiteOpenHelper mDbOpenHelper;
 
     static {
         URL_MATCHER.addURI(AUTHORITY, "thread", THREAD);
+        URL_MATCHER.addURI(AUTHORITY, "participant", PARTICIPANT);
     }
 
     @Override
@@ -64,7 +64,10 @@
 
         switch (match) {
             case THREAD:
-                RcsProviderHelper.buildThreadQuery(qb);
+                RcsProviderThreadHelper.buildThreadQuery(qb);
+                break;
+            case PARTICIPANT:
+                RcsProviderParticipantHelper.buildParticipantsQuery(qb);
                 break;
             default:
                 Log.e(TAG, "Invalid query: " + uri);
@@ -83,13 +86,21 @@
     public Uri insert(Uri uri, ContentValues values) {
         int match = URL_MATCHER.match(uri);
         SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+        writableDatabase.beginTransaction();
 
-        switch (match) {
-            case THREAD:
-                writableDatabase.insert(THREAD_TABLE, ID, values);
-                break;
-            default:
-                Log.e(TAG, "Invalid insert: " + uri);
+        try {
+            switch (match) {
+                case THREAD:
+                    RcsProviderThreadHelper.insert(writableDatabase, values);
+                    break;
+                case PARTICIPANT:
+                    RcsProviderParticipantHelper.insert(writableDatabase, values);
+                    break;
+                default:
+                    Log.e(TAG, "Invalid insert: " + uri);
+            }
+        } finally {
+            writableDatabase.endTransaction();
         }
 
         return null;
@@ -100,13 +111,23 @@
         int match = URL_MATCHER.match(uri);
         int deletedCount = 0;
         SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+        writableDatabase.beginTransaction();
 
-        switch (match) {
-            case THREAD:
-                deletedCount = writableDatabase.delete(THREAD_TABLE, selection, selectionArgs);
-                break;
-            default:
-                Log.e(TAG, "Invalid delete: " + uri);
+        try {
+            switch (match) {
+                case THREAD:
+                    deletedCount = RcsProviderThreadHelper.delete(writableDatabase, selection,
+                            selectionArgs);
+                    break;
+                case PARTICIPANT:
+                    deletedCount = RcsProviderParticipantHelper.delete(writableDatabase, selection,
+                            selectionArgs);
+                    break;
+                default:
+                    Log.e(TAG, "Invalid delete: " + uri);
+            }
+        } finally {
+            writableDatabase.endTransaction();
         }
 
         return deletedCount;
@@ -118,15 +139,23 @@
         int updatedCount = 0;
         SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
 
-        switch (match) {
-            case THREAD:
-                updatedCount = writableDatabase.update(
-                        THREAD_TABLE, values, selection, selectionArgs);
-                break;
-            default:
-                Log.e(TAG, "Invalid update: " + uri);
+        writableDatabase.beginTransaction();
+        try {
+            switch (match) {
+                case THREAD:
+                    updatedCount = RcsProviderThreadHelper.update(
+                            writableDatabase, values, selection, selectionArgs);
+                    break;
+                case PARTICIPANT:
+                    updatedCount = RcsProviderParticipantHelper.update(
+                            writableDatabase, values, selection, selectionArgs);
+                    break;
+                default:
+                    Log.e(TAG, "Invalid update: " + uri);
+            }
+        } finally {
+            writableDatabase.endTransaction();
         }
-
         return updatedCount;
     }
 }
diff --git a/src/com/android/providers/telephony/RcsProviderHelper.java b/src/com/android/providers/telephony/RcsProviderHelper.java
deleted file mode 100644
index 3966f53..0000000
--- a/src/com/android/providers/telephony/RcsProviderHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteQueryBuilder;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Constants and helpers for RcsProvider to keep the code clean.
- * @hide
- */
-class RcsProviderHelper {
-    static final String ID = "_id";
-    static final String THREAD_TABLE = "rcs_thread";
-    static final String OWNER_PARTICIPANT = "owner_participant";
-
-    @VisibleForTesting
-    public static void createRcsTables(SQLiteDatabase db) {
-        db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
-                ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
-                OWNER_PARTICIPANT + " INTEGER " +
-                ");");
-    }
-
-    static void buildThreadQuery(SQLiteQueryBuilder qb) {
-        qb.setTables(THREAD_TABLE);
-    }
-}
diff --git a/src/com/android/providers/telephony/RcsProviderParticipantHelper.java b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
new file mode 100644
index 0000000..913b8eb
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
@@ -0,0 +1,105 @@
+/*
+ * 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 static com.android.providers.telephony.RcsProvider.TAG;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ims.RcsMessageStoreController;
+
+/**
+ * Constants and helpers related to participants for {@link RcsProvider} to keep the code clean.
+ *
+ * @hide
+ */
+public class RcsProviderParticipantHelper {
+    static final String ID_COLUMN = "_id";
+    static final String PARTICIPANT_TABLE = "rcs_participant";
+    static final String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
+    static final String RCS_ALIAS_COLUMN = "rcs_alias";
+
+    static final String CANONICAL_ADDRESSES_TABLE = "canonical_addresses";
+    static final String ADDRESS_COLUMN = "address";
+
+    private static final int NO_EXISTING_ADDRESS = Integer.MIN_VALUE;
+
+    @VisibleForTesting
+    public static void createParticipantTables(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE " + PARTICIPANT_TABLE + " (" +
+                ID_COLUMN + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+                CANONICAL_ADDRESS_ID_COLUMN + " INTEGER ," +
+                RCS_ALIAS_COLUMN + " TEXT, " +
+                "FOREIGN KEY(" + CANONICAL_ADDRESS_ID_COLUMN + ") "
+                + "REFERENCES canonical_addresses(address)" +
+                ");");
+    }
+
+    static void buildParticipantsQuery(SQLiteQueryBuilder qb) {
+        qb.setTables(PARTICIPANT_TABLE);
+    }
+
+    static void insert(SQLiteDatabase db, ContentValues values) {
+        // TODO - implement
+    }
+
+    static int delete(SQLiteDatabase db, String selection,
+            String[] selectionArgs) {
+        int deletedRows = db.delete(PARTICIPANT_TABLE, selection, selectionArgs);
+        db.setTransactionSuccessful();
+        return deletedRows;
+    }
+
+    static int update(SQLiteDatabase db, ContentValues values,
+            String selection, String[] selectionArgs) {
+        int updatedRows = db.update(PARTICIPANT_TABLE, values, selection, selectionArgs);
+        db.setTransactionSuccessful();
+        return updatedRows;
+    }
+
+    private static int getCanonicalAddressId(SQLiteDatabase db, ContentValues values) {
+        String address = values.getAsString(RcsMessageStoreController.PARTICIPANT_ADDRESS_KEY);
+
+        // see if the address already exists
+        // TODO(sahinc) - refine this to match phone number formats in canonical addresses, or find
+        // TODO(sahinc) - another solution.
+        Cursor existingCanonicalAddressAsCursor = db.query(CANONICAL_ADDRESSES_TABLE,
+                new String[]{ID_COLUMN}, ADDRESS_COLUMN + "=" + address,
+                null, null, null, null);
+        long canonicalAddressId = NO_EXISTING_ADDRESS;
+
+        if (existingCanonicalAddressAsCursor != null
+                && existingCanonicalAddressAsCursor.moveToFirst()) {
+            canonicalAddressId = existingCanonicalAddressAsCursor.getLong(0);
+            existingCanonicalAddressAsCursor.close();
+        }
+
+        // If there is no existing canonical address, add one.
+        if (canonicalAddressId == NO_EXISTING_ADDRESS) {
+            canonicalAddressId = db.insert(CANONICAL_ADDRESSES_TABLE, ADDRESS_COLUMN, values);
+        }
+
+        if (canonicalAddressId == NO_EXISTING_ADDRESS) {
+            Log.e(TAG, "Could not create an entry in canonical addresses");
+        }
+
+        return (int) canonicalAddressId;
+    }
+}
diff --git a/src/com/android/providers/telephony/RcsProviderThreadHelper.java b/src/com/android/providers/telephony/RcsProviderThreadHelper.java
new file mode 100644
index 0000000..f993b2e
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProviderThreadHelper.java
@@ -0,0 +1,63 @@
+/*
+ * 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.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Constants and helpers related to threads for {@link RcsProvider} to keep the code clean.
+ *
+ * @hide
+ */
+class RcsProviderThreadHelper {
+    static final String ID_COLUMN = "_id";
+    static final String THREAD_TABLE = "rcs_thread";
+    static final String OWNER_PARTICIPANT = "owner_participant";
+
+    @VisibleForTesting
+    public static void createThreadTables(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
+                ID_COLUMN + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+                OWNER_PARTICIPANT + " INTEGER " +
+                ");");
+    }
+
+    static void buildThreadQuery(SQLiteQueryBuilder qb) {
+        qb.setTables(THREAD_TABLE);
+    }
+
+    static void insert(SQLiteDatabase db, ContentValues values) {
+        db.insert(THREAD_TABLE, OWNER_PARTICIPANT, values);
+        db.setTransactionSuccessful();
+    }
+
+    static int delete(SQLiteDatabase db, String selection, String[] selectionArgs) {
+        int deletedRowCount = db.delete(THREAD_TABLE, selection, selectionArgs);
+        db.setTransactionSuccessful();
+        return deletedRowCount;
+    }
+
+    static int update(SQLiteDatabase db, ContentValues values, String selection,
+            String[] selectionArgs) {
+        int updatedRowCount = db.update(THREAD_TABLE, values, selection, selectionArgs);
+        db.setTransactionSuccessful();
+        return updatedRowCount;
+    }
+}
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 00a9077..7244510 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -143,7 +143,7 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false; // STOPSHIP if true
 
-    private static final int DATABASE_VERSION = 32 << 16;
+    private static final int DATABASE_VERSION = 33 << 16;
     private static final int URL_UNKNOWN = 0;
     private static final int URL_TELEPHONY = 1;
     private static final int URL_CURRENT = 2;
@@ -385,7 +385,8 @@
                 + SubscriptionManager.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
                 + SubscriptionManager.GROUP_UUID + " TEXT,"
                 + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1,"
-                + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT"
+                + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT,"
+                + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1"
                 + ");";
     }
 
@@ -1199,6 +1200,20 @@
                 oldVersion = 32 << 16 | 6;
             }
 
+            if (oldVersion < (33 << 16 | 6)) {
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+                            + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                                "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 33 << 16 | 6;
+            }
+
             if (DBG) {
                 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
             }
@@ -2889,7 +2904,12 @@
         int mvnoIndex = ret.getColumnIndex(MVNO_TYPE);
         int mvnoDataIndex = ret.getColumnIndex(MVNO_MATCH_DATA);
 
-        IccRecords iccRecords = getIccRecords(subId);
+        IccRecords iccRecords = UiccController.getInstance().getIccRecords(
+                SubscriptionManager.getPhoneId(subId), UiccController.APP_FAM_3GPP);
+        if (iccRecords == null) {
+            loge("iccRecords is null");
+            return null;
+        }
 
         //Separate the result into MatrixCursor
         while (ret.moveToNext()) {
diff --git a/tests/Android.mk b/tests/Android.mk
index 14f528f..3505c29 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -5,7 +5,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := mockito-target \
                                compatibility-device-util \
-                               android-support-test
+                               android-support-test \
+                               truth-prebuilt
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTest.java b/tests/src/com/android/providers/telephony/RcsProviderTest.java
index 708078f..2417f51 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTest.java
@@ -15,13 +15,13 @@
  */
 package com.android.providers.telephony;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.app.AppOpsManager;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.ProviderInfo;
+import android.database.Cursor;
 import android.net.Uri;
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
@@ -30,12 +30,14 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 public class RcsProviderTest {
     private MockContentResolver mContentResolver;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         RcsProvider rcsProvider = new RcsProviderTestable();
         MockContextWithProvider context = new MockContextWithProvider(rcsProvider);
         mContentResolver = context.getContentResolver();
@@ -46,23 +48,39 @@
     @Test
     public void testInsertThread() {
         ContentValues contentValues = new ContentValues();
-        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+        contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
 
         Uri uri = mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
-        assertNull(uri);
+        assertThat(uri).isNull();
     }
 
     @Test
     public void testUpdateThread() {
         ContentValues contentValues = new ContentValues();
-        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+        contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
         mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
 
-        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 12);
+        contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 12);
         int updateCount = mContentResolver.update(Uri.parse("content://rcs/thread"),
                 contentValues, "owner_participant=5", null);
 
-        assertEquals(1, updateCount);
+        assertThat(updateCount).isEqualTo(1);
+    }
+
+    @Test
+    public void testCanQueryAllThreads() {
+        // insert two threads
+        ContentValues contentValues = new ContentValues();
+        Uri threadsUri = Uri.parse("content://rcs/thread");
+        contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 7);
+        mContentResolver.insert(threadsUri, contentValues);
+
+        contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 13);
+        mContentResolver.insert(threadsUri, contentValues);
+
+        //verify two threads are inserted
+        Cursor cursor = mContentResolver.query(threadsUri, null, null, null, null);
+        assertThat(cursor.getCount()).isEqualTo(2);
     }
 
     class MockContextWithProvider extends MockContext {
@@ -95,5 +113,4 @@
             }
         }
     }
-
 }
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTestable.java b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
index 1e4da11..64ae3ef 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
@@ -39,7 +39,7 @@
 
         @Override
         public void onCreate(SQLiteDatabase db) {
-            RcsProviderHelper.createRcsTables(db);
+            RcsProviderThreadHelper.createThreadTables(db);
         }
 
         @Override
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index b77e5cf..2ca823a 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -42,15 +42,21 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.uicc.UiccController;
+
 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;
 
-
 /**
  * Tests for testing CRUD operations of TelephonyProvider.
  * Uses a MockContentResolver to get permission WRITE_APN_SETTINGS in order to test insert/delete
@@ -70,6 +76,12 @@
     private MockContentResolver mContentResolver;
     private TelephonyProviderTestable mTelephonyProviderTestable;
 
+    @Mock
+    private UiccController mUiccController;
+
+    @Mock
+    private IccRecords mIcRecords;
+
     private int notifyChangeCount;
     private int notifyChangeRestoreCount;
     private int notifyWfcCount;
@@ -79,6 +91,7 @@
     private static final String TEST_OPERATOR = "123456";
     private static final String TEST_MCC = "123";
     private static final String TEST_MNC = "456";
+    private static final String TEST_SPN = TelephonyProviderTestable.TEST_SPN;
 
     // Used to test the path for URL_TELEPHONY_USING_SUBID with subid 1
     private static final Uri CONTENT_URI_WITH_SUBID = Uri.parse(
@@ -138,6 +151,9 @@
 
             doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
             doReturn(TEST_OPERATOR).when(mTelephonyManager).getSimOperator();
+            doReturn(mIcRecords).when(mUiccController).getIccRecords(anyInt(),
+                    ArgumentMatchers.eq(UiccController.APP_FAM_3GPP));
+            doReturn(TEST_SPN).when(mIcRecords).getServiceProviderName();
 
             // Add authority="telephony" to given telephonyProvider
             ProviderInfo providerInfo = new ProviderInfo();
@@ -199,9 +215,11 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        MockitoAnnotations.initMocks(this);
         mTelephonyProviderTestable = new TelephonyProviderTestable();
         mContext = new MockContextWithProvider(mTelephonyProviderTestable);
         mContentResolver = (MockContentResolver) mContext.getContentResolver();
+        replaceInstance(UiccController.class, "mInstance", null, mUiccController);
         notifyChangeCount = 0;
         notifyChangeRestoreCount = 0;
     }
@@ -724,7 +742,7 @@
         mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
         final int current = 1;
-        final String numeric = "123456789";
+        final String numeric = TEST_OPERATOR;
         final String selection = Carriers.NUMERIC + "=?";
         final String[] selectionArgs = { numeric };
 
@@ -802,7 +820,7 @@
             mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
             final int current = 1;
-            final String numeric = "123456789";
+            final String numeric = TEST_OPERATOR;
 
             // Insert DPC record.
             final String dpcRecordApn = "exampleApnNameDPC";
@@ -893,7 +911,7 @@
             mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
             final int current = 1;
-            final String numeric = "123456789";
+            final String numeric = TEST_OPERATOR;
 
             // Insert DPC record 1.
             final String dpcRecordApn1 = "exampleApnNameDPC";
@@ -1445,22 +1463,23 @@
         assertEquals(0, notifyWfcCountWithTestSubId);
     }
 
+    protected void replaceInstance(final Class c, final String instanceName,
+            final Object obj, final Object newValue)
+            throws Exception {
+        Field field = c.getDeclaredField(instanceName);
+        field.setAccessible(true);
+        field.set(obj, newValue);
+    }
+
     @Test
     @SmallTest
     public void testSIMAPNLIST_APNMatchTheMCCMNCAndMVNO() {
         // Test on getCurrentAPNList() step 1
-        TelephonyManager telephonyManager =
-                ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE));
-        doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
-
         final String apnName = "apnName";
         final String carrierName = "name";
         final String numeric = TEST_OPERATOR;
         final String mvnoType = "spn";
-        final String mvnoData = TelephonyProviderTestable.TEST_SPN;
-        final int carrierId = 100;
-        doReturn(carrierId).when(telephonyManager).getSimCarrierId();
-        doReturn(numeric).when(telephonyManager).getSimOperator();
+        final String mvnoData = TEST_SPN;
 
         // Insert the APN and DB only have the MCC/MNC and MVNO APN
         ContentValues contentValues = new ContentValues();
@@ -1473,12 +1492,12 @@
 
         // Query DB
         final String[] testProjection =
-            {
-                Carriers.APN,
-                Carriers.NAME,
-                Carriers.NUMERIC,
-                Carriers.MVNO_MATCH_DATA
-            };
+                {
+                        Carriers.APN,
+                        Carriers.NAME,
+                        Carriers.NUMERIC,
+                        Carriers.MVNO_MATCH_DATA
+                };
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
                 testProjection, null, null, null);
 
@@ -1493,21 +1512,9 @@
     @SmallTest
     public void testSIMAPNLIST_APNMatchTheParentMCCMNC() {
         // Test on getCurrentAPNList() step 2
-        TelephonyManager telephonyManager =
-                ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE));
-        doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
-
         final String apnName = "apnName";
         final String carrierName = "name";
         final String numeric = TEST_OPERATOR;
-        final String mvnoData = TelephonyProviderTestable.TEST_SPN;
-        final int carrierId = 100;
-        final int mnoCarrierId = 101;
-
-        doReturn(carrierId).when(telephonyManager).getSimCarrierId();
-        doReturn(numeric).when(telephonyManager).getSimOperator();
-        doReturn(mvnoData).when(telephonyManager).getSimOperatorName();
-        doReturn(mnoCarrierId).when(telephonyManager).getSimMNOCarrierId();
 
         // Insert the APN and DB only have the MNO APN
         ContentValues contentValues = new ContentValues();
@@ -1518,11 +1525,11 @@
 
         // Query DB
         final String[] testProjection =
-            {
-                Carriers.APN,
-                Carriers.NAME,
-                Carriers.NUMERIC,
-            };
+                {
+                        Carriers.APN,
+                        Carriers.NAME,
+                        Carriers.NUMERIC,
+                };
         Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
                 testProjection, null, null, null);