Merge "Fix comment on conflict policy"
diff --git a/OWNERS b/OWNERS
index 7aabde8..0716d33 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1,9 @@
 amitmahajan@google.com
 fionaxu@google.com
-jminjie@google.com
-rgreenwalt@google.com
-tomtaylor@google.com
 jackyu@google.com
-refuhoo@google.com
\ No newline at end of file
+rgreenwalt@google.com
+refuhoo@google.com
+mpq@google.com
+jminjie@google.com
+shuoq@google.com
+
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index ed590fc..4cbbc79 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -31,10 +31,13 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.provider.Telephony.CarrierIdentification;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.nano.CarrierIdProto;
 
 import java.io.ByteArrayOutputStream;
@@ -45,6 +48,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import libcore.io.IoUtils;
 
@@ -77,39 +82,41 @@
     private static final String PREF_FILE = CarrierIdProvider.class.getSimpleName();
 
     private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-    private static final int URL_UPDATE_FROM_PB = 1;
-    private static final int URL_GET_VERSION    = 2;
+
+    private static final int URL_ALL                = 1;
+    private static final int URL_ALL_UPDATE_FROM_PB = 2;
+    private static final int URL_ALL_GET_VERSION    = 3;
 
     /**
-     * index 0: {@link CarrierIdentification#MCCMNC}
+     * index 0: {@link CarrierIdentification.All#MCCMNC}
      */
     private static final int MCCMNC_INDEX                = 0;
     /**
-     * index 1: {@link CarrierIdentification#IMSI_PREFIX_XPATTERN}
+     * index 1: {@link CarrierIdentification.All#IMSI_PREFIX_XPATTERN}
      */
     private static final int IMSI_PREFIX_INDEX           = 1;
     /**
-     * index 2: {@link CarrierIdentification#GID1}
+     * index 2: {@link CarrierIdentification.All#GID1}
      */
     private static final int GID1_INDEX                  = 2;
     /**
-     * index 3: {@link CarrierIdentification#GID2}
+     * index 3: {@link CarrierIdentification.All#GID2}
      */
     private static final int GID2_INDEX                  = 3;
     /**
-     * index 4: {@link CarrierIdentification#PLMN}
+     * index 4: {@link CarrierIdentification.All#PLMN}
      */
     private static final int PLMN_INDEX                  = 4;
     /**
-     * index 5: {@link CarrierIdentification#SPN}
+     * index 5: {@link CarrierIdentification.All#SPN}
      */
     private static final int SPN_INDEX                   = 5;
     /**
-     * index 6: {@link CarrierIdentification#APN}
+     * index 6: {@link CarrierIdentification.All#APN}
      */
     private static final int APN_INDEX                   = 6;
     /**
-    * index 7: {@link CarrierIdentification#ICCID_PREFIX}
+    * index 7: {@link CarrierIdentification.All#ICCID_PREFIX}
     */
     private static final int ICCID_PREFIX_INDEX          = 7;
     /**
@@ -125,29 +132,36 @@
     public static final String CARRIER_ID_TABLE = "carrier_id";
 
     private static final List<String> CARRIERS_ID_UNIQUE_FIELDS = new ArrayList<>(Arrays.asList(
-            CarrierIdentification.MCCMNC,
-            CarrierIdentification.GID1,
-            CarrierIdentification.GID2,
-            CarrierIdentification.PLMN,
-            CarrierIdentification.IMSI_PREFIX_XPATTERN,
-            CarrierIdentification.SPN,
-            CarrierIdentification.APN,
-            CarrierIdentification.ICCID_PREFIX));
+            CarrierIdentification.All.MCCMNC,
+            CarrierIdentification.All.GID1,
+            CarrierIdentification.All.GID2,
+            CarrierIdentification.All.PLMN,
+            CarrierIdentification.All.IMSI_PREFIX_XPATTERN,
+            CarrierIdentification.All.SPN,
+            CarrierIdentification.All.APN,
+            CarrierIdentification.All.ICCID_PREFIX));
 
     private CarrierIdDatabaseHelper mDbHelper;
 
+    /**
+     * Stores carrier id information for the current active subscriptions.
+     * Key is the active subId and entryValue is a pair of carrier id(int) and Carrier Name(String).
+     */
+    private final Map<Integer, Pair<Integer, String>> mCurrentSubscriptionMap =
+            new ConcurrentHashMap<>();
+
     @VisibleForTesting
     public static String getStringForCarrierIdTableCreation(String tableName) {
         return "CREATE TABLE " + tableName
                 + "(_id INTEGER PRIMARY KEY,"
-                + CarrierIdentification.MCCMNC + " TEXT NOT NULL,"
-                + CarrierIdentification.GID1 + " TEXT,"
-                + CarrierIdentification.GID2 + " TEXT,"
-                + CarrierIdentification.PLMN + " TEXT,"
-                + CarrierIdentification.IMSI_PREFIX_XPATTERN + " TEXT,"
-                + CarrierIdentification.SPN + " TEXT,"
-                + CarrierIdentification.APN + " TEXT,"
-                + CarrierIdentification.ICCID_PREFIX + " TEXT,"
+                + CarrierIdentification.All.MCCMNC + " TEXT NOT NULL,"
+                + CarrierIdentification.All.GID1 + " TEXT,"
+                + CarrierIdentification.All.GID2 + " TEXT,"
+                + CarrierIdentification.All.PLMN + " TEXT,"
+                + CarrierIdentification.All.IMSI_PREFIX_XPATTERN + " TEXT,"
+                + CarrierIdentification.All.SPN + " TEXT,"
+                + CarrierIdentification.All.APN + " TEXT,"
+                + CarrierIdentification.All.ICCID_PREFIX + " TEXT,"
                 + CarrierIdentification.NAME + " TEXT,"
                 + CarrierIdentification.CID + " INTEGER DEFAULT -1,"
                 + "UNIQUE (" + TextUtils.join(", ", CARRIERS_ID_UNIQUE_FIELDS) + "));";
@@ -156,7 +170,7 @@
     @VisibleForTesting
     public static String getStringForIndexCreation(String tableName) {
         return "CREATE INDEX IF NOT EXISTS mccmncIndex ON " + tableName + " ("
-                + CarrierIdentification.MCCMNC + ");";
+                + CarrierIdentification.All.MCCMNC + ");";
     }
 
     @Override
@@ -164,8 +178,9 @@
         Log.d(TAG, "onCreate");
         mDbHelper = new CarrierIdDatabaseHelper(getContext());
         mDbHelper.getReadableDatabase();
-        s_urlMatcher.addURI(AUTHORITY, "update_db", URL_UPDATE_FROM_PB);
-        s_urlMatcher.addURI(AUTHORITY, "get_version", URL_GET_VERSION);
+        s_urlMatcher.addURI(AUTHORITY, "all", URL_ALL);
+        s_urlMatcher.addURI(AUTHORITY, "all/update_db", URL_ALL_UPDATE_FROM_PB);
+        s_urlMatcher.addURI(AUTHORITY, "all/get_version", URL_ALL_GET_VERSION);
         updateDatabaseFromPb(mDbHelper.getWritableDatabase());
         return true;
     }
@@ -179,7 +194,6 @@
     @Override
     public Cursor query(Uri uri, String[] projectionIn, String selection,
                         String[] selectionArgs, String sortOrder) {
-        checkReadPermission();
         if (VDBG) {
             Log.d(TAG, "query:"
                     + " uri=" + uri
@@ -190,29 +204,42 @@
 
         final int match = s_urlMatcher.match(uri);
         switch (match) {
-            case URL_GET_VERSION:
+            case URL_ALL_GET_VERSION:
+                checkReadPermission();
                 final MatrixCursor cursor = new MatrixCursor(new String[] {VERSION_KEY});
                 cursor.addRow(new Object[] {getAppliedVersion()});
                 return cursor;
-            default:
+            case URL_ALL:
+                checkReadPermission();
                 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
                 qb.setTables(CARRIER_ID_TABLE);
 
                 SQLiteDatabase db = getReadableDatabase();
                 return qb.query(db, projectionIn, selection, selectionArgs, null, null, sortOrder);
+            default:
+                return queryCarrierIdForCurrentSubscription(uri, projectionIn);
         }
     }
 
     @Override
     public Uri insert(Uri uri, ContentValues values) {
         checkWritePermission();
-        final long row = getWritableDatabase().insertOrThrow(CARRIER_ID_TABLE, null, values);
-        if (row > 0) {
-            final Uri newUri = ContentUris.withAppendedId(CarrierIdentification.CONTENT_URI, row);
-            getContext().getContentResolver().notifyChange(newUri, null);
-            return newUri;
+        final int match = s_urlMatcher.match(uri);
+        switch (match) {
+            case URL_ALL:
+                final long row = getWritableDatabase().insertOrThrow(CARRIER_ID_TABLE, null,
+                        values);
+                if (row > 0) {
+                    final Uri newUri = ContentUris.withAppendedId(
+                            CarrierIdentification.All.CONTENT_URI, row);
+                    getContext().getContentResolver().notifyChange(
+                            CarrierIdentification.All.CONTENT_URI, null);
+                    return newUri;
+                }
+                return null;
+            default:
+                throw new IllegalArgumentException("Cannot insert that URL: " + uri);
         }
-        return null;
     }
 
     @Override
@@ -225,12 +252,20 @@
                     + " selection=" + selection
                     + " selectionArgs=" + Arrays.toString(selectionArgs));
         }
-        final int count = getWritableDatabase().delete(CARRIER_ID_TABLE, selection, selectionArgs);
-        Log.d(TAG, "  delete.count=" + count);
-        if (count > 0) {
-            getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI, null);
+        final int match = s_urlMatcher.match(uri);
+        switch (match) {
+            case URL_ALL:
+                final int count = getWritableDatabase().delete(CARRIER_ID_TABLE, selection,
+                        selectionArgs);
+                Log.d(TAG, "  delete.count=" + count);
+                if (count > 0) {
+                    getContext().getContentResolver().notifyChange(
+                            CarrierIdentification.All.CONTENT_URI, null);
+                }
+                return count;
+            default:
+                throw new IllegalArgumentException("Cannot delete that URL: " + uri);
         }
-        return count;
     }
 
     @Override
@@ -246,17 +281,20 @@
 
         final int match = s_urlMatcher.match(uri);
         switch (match) {
-            case URL_UPDATE_FROM_PB:
+            case URL_ALL_UPDATE_FROM_PB:
                 return updateDatabaseFromPb(getWritableDatabase());
-            default:
+            case URL_ALL:
                 final int count = getWritableDatabase().update(CARRIER_ID_TABLE, values, selection,
                         selectionArgs);
                 Log.d(TAG, "  update.count=" + count);
                 if (count > 0) {
                     getContext().getContentResolver().notifyChange(
-                            CarrierIdentification.CONTENT_URI, null);
+                            CarrierIdentification.All.CONTENT_URI, null);
                 }
                 return count;
+            default:
+                return updateCarrierIdForCurrentSubscription(uri, values);
+
         }
     }
 
@@ -350,8 +388,8 @@
             Log.d(TAG, "update database from pb. inserted rows = " + rows);
             if (rows > 0) {
                 // Notify listener of DB change
-                getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI,
-                        null);
+                getContext().getContentResolver().notifyChange(
+                        CarrierIdentification.All.CONTENT_URI, null);
             }
             setAppliedVersion(carrierList.version);
             db.setTransactionSuccessful();
@@ -374,65 +412,65 @@
         switch (index) {
             case MCCMNC_INDEX:
                 for (String str : attr.mccmncTuple) {
-                    cv.put(CarrierIdentification.MCCMNC, str);
+                    cv.put(CarrierIdentification.All.MCCMNC, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.MCCMNC);
+                    cv.remove(CarrierIdentification.All.MCCMNC);
                     found = true;
                 }
                 break;
             case IMSI_PREFIX_INDEX:
                 for (String str : attr.imsiPrefixXpattern) {
-                    cv.put(CarrierIdentification.IMSI_PREFIX_XPATTERN, str);
+                    cv.put(CarrierIdentification.All.IMSI_PREFIX_XPATTERN, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.IMSI_PREFIX_XPATTERN);
+                    cv.remove(CarrierIdentification.All.IMSI_PREFIX_XPATTERN);
                     found = true;
                 }
                 break;
             case GID1_INDEX:
                 for (String str : attr.gid1) {
-                    cv.put(CarrierIdentification.GID1, str);
+                    cv.put(CarrierIdentification.All.GID1, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.GID1);
+                    cv.remove(CarrierIdentification.All.GID1);
                     found = true;
                 }
                 break;
             case GID2_INDEX:
                 for (String str : attr.gid2) {
-                    cv.put(CarrierIdentification.GID2, str);
+                    cv.put(CarrierIdentification.All.GID2, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.GID2);
+                    cv.remove(CarrierIdentification.All.GID2);
                     found = true;
                 }
                 break;
             case PLMN_INDEX:
                 for (String str : attr.plmn) {
-                    cv.put(CarrierIdentification.PLMN, str);
+                    cv.put(CarrierIdentification.All.PLMN, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.PLMN);
+                    cv.remove(CarrierIdentification.All.PLMN);
                     found = true;
                 }
                 break;
             case SPN_INDEX:
                 for (String str : attr.spn) {
-                    cv.put(CarrierIdentification.SPN, str);
+                    cv.put(CarrierIdentification.All.SPN, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.SPN);
+                    cv.remove(CarrierIdentification.All.SPN);
                     found = true;
                 }
                 break;
             case APN_INDEX:
                 for (String str : attr.preferredApn) {
-                    cv.put(CarrierIdentification.APN, str);
+                    cv.put(CarrierIdentification.All.APN, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.APN);
+                    cv.remove(CarrierIdentification.All.APN);
                     found = true;
                 }
                 break;
             case ICCID_PREFIX_INDEX:
                 for (String str : attr.iccidPrefix) {
-                    cv.put(CarrierIdentification.ICCID_PREFIX, str);
+                    cv.put(CarrierIdentification.All.ICCID_PREFIX, str);
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
-                    cv.remove(CarrierIdentification.ICCID_PREFIX);
+                    cv.remove(CarrierIdentification.All.ICCID_PREFIX);
                     found = true;
                 }
                 break;
@@ -490,12 +528,14 @@
     }
 
     private int getAppliedVersion() {
-        final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+        final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE,
+                Context.MODE_PRIVATE);
         return sp.getInt(VERSION_KEY, -1);
     }
 
     private void setAppliedVersion(int version) {
-        final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+        final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE,
+                Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = sp.edit();
         editor.putInt(VERSION_KEY, version);
         editor.apply();
@@ -516,6 +556,81 @@
         return buffer.toByteArray();
     }
 
+    private int updateCarrierIdForCurrentSubscription(Uri uri, ContentValues cv) {
+        // Parse the subId
+        int subId;
+        try {
+            subId = Integer.parseInt(uri.getLastPathSegment());
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("invalid subid in provided uri " + uri);
+        }
+        Log.d(TAG, "updateCarrierIdForSubId: " + subId);
+
+        // Handle DEFAULT_SUBSCRIPTION_ID
+        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+            subId = SubscriptionController.getInstance().getDefaultSubId();
+        }
+
+        if (!SubscriptionController.getInstance().isActiveSubId(subId)) {
+            // Remove absent subId from the currentSubscriptionMap.
+            final List activeSubscriptions = Arrays.asList(SubscriptionController.getInstance()
+                    .getActiveSubIdList());
+            int count = 0;
+            for (int subscription : mCurrentSubscriptionMap.keySet()) {
+                if (!activeSubscriptions.contains(subscription)) {
+                    count++;
+                    Log.d(TAG, "updateCarrierIdForSubId: " + subscription);
+                    mCurrentSubscriptionMap.remove(subscription);
+                    getContext().getContentResolver().notifyChange(
+                            CarrierIdentification.CONTENT_URI, null);
+                }
+            }
+            return count;
+        } else {
+            mCurrentSubscriptionMap.put(subId,
+                    new Pair(cv.getAsInteger(CarrierIdentification.CID),
+                    cv.getAsString(CarrierIdentification.NAME)));
+            getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI, null);
+            return 1;
+        }
+    }
+
+    private Cursor queryCarrierIdForCurrentSubscription(Uri uri, String[] projectionIn) {
+        // Parse the subId, using the default subId if subId is not provided
+        int subId = SubscriptionController.getInstance().getDefaultSubId();
+        if (!TextUtils.isEmpty(uri.getLastPathSegment())) {
+            try {
+                subId = Integer.parseInt(uri.getLastPathSegment());
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("invalid subid in provided uri" + uri);
+            }
+        }
+        Log.d(TAG, "queryCarrierIdForSubId: " + subId);
+
+        // Handle DEFAULT_SUBSCRIPTION_ID
+        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+            subId = SubscriptionController.getInstance().getDefaultSubId();
+        }
+
+        if (!mCurrentSubscriptionMap.containsKey(subId)) {
+            // Return an empty cursor if subId is not belonging to current subscriptions.
+            return new MatrixCursor(projectionIn, 0);
+        }
+        final MatrixCursor c = new MatrixCursor(projectionIn, 1);
+        final MatrixCursor.RowBuilder row = c.newRow();
+        for (int i = 0; i < c.getColumnCount(); i++) {
+            final String columnName = c.getColumnName(i);
+            if (CarrierIdentification.CID.equals(columnName)) {
+                row.add(mCurrentSubscriptionMap.get(subId).first);
+            } else if (CarrierIdentification.NAME.equals(columnName)) {
+                row.add(mCurrentSubscriptionMap.get(subId).second);
+            } else {
+                throw new IllegalArgumentException("Invalid column " + projectionIn[i]);
+            }
+        }
+        return c;
+    }
+
     private void checkReadPermission() {
         int status = getContext().checkCallingOrSelfPermission(
                 "android.permission.READ_PRIVILEGED_PHONE_STATE");
diff --git a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
index be600f6..8c3cec5 100644
--- a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
+++ b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentValues;
 import android.content.SharedPreferences;
+import android.content.UriMatcher;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.database.ContentObserver;
@@ -31,10 +32,15 @@
 import android.test.mock.MockContext;
 import android.util.Log;
 
+import com.android.internal.telephony.SubscriptionController;
+
 import junit.framework.TestCase;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Mock;
+
+import java.lang.reflect.Field;
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -72,6 +78,7 @@
     private CarrierIdProviderTestable mCarrierIdProviderTestable;
     private FakeContentObserver mContentObserver;
     private SharedPreferences mSharedPreferences = mock(SharedPreferences.class);
+    private SubscriptionController mSubController = mock(SubscriptionController.class);
 
     private class FakeContentResolver extends MockContentResolver {
         @Override
@@ -146,6 +153,9 @@
         mContext = new MockContextWithProvider(mCarrierIdProviderTestable);
         mContentResolver = mContext.getContentResolver();
         mContentObserver = new FakeContentObserver(null);
+        Field field = SubscriptionController.class.getDeclaredField("sInstance");
+        field.setAccessible(true);
+        field.set(null, mSubController);
     }
 
     @Override
@@ -160,9 +170,9 @@
     @Test
     public void testInsertCarrierInfo() {
         try {
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI,
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI,
                     createCarrierInfoInternal());
-            Cursor countCursor = mContentResolver.query(CarrierIdentification.CONTENT_URI,
+            Cursor countCursor = mContentResolver.query(CarrierIdentification.All.CONTENT_URI,
                     new String[]{"count(*) AS count"},
                     null,
                     null,
@@ -183,8 +193,8 @@
         try {
             //insert same row twice to break uniqueness constraint
             ContentValues contentValues = createCarrierInfoInternal();
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
             Assert.fail("should throw an exception for duplicate carrier info");
         } catch (Exception e) {
             Log.d(TAG, "Error inserting carrier info:" + e);
@@ -199,12 +209,11 @@
         try {
             //insert a row with null mnccmnc to break not null constraint
             ContentValues contentValues = new ContentValues();
-            contentValues.put(CarrierIdentification.GID1, dummy_gid1);
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
+            contentValues.put(CarrierIdentification.All.GID1, dummy_gid1);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
             Assert.fail("should throw an exception for null mccmnc");
-        } catch (Exception e) {
+        } catch (SQLException e) {
             Log.d(TAG, "Error inserting carrier info:" + e);
-            assertTrue(e instanceof SQLException);
             assertFalse(mContentObserver.changed);
         }
     }
@@ -215,16 +224,17 @@
     @Test
     public void testDeleteCarrierInfo() {
         try {
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, createCarrierInfoInternal());
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI,
+                    createCarrierInfoInternal());
         } catch (Exception e) {
             Log.d(TAG, "Error inserting carrier info:" + e);
         }
         int numRowsDeleted = -1;
         try {
-            String whereClause = CarrierIdentification.MCCMNC + "=?";
+            String whereClause = CarrierIdentification.All.MCCMNC + "=?";
             String[] whereArgs = new String[] { dummy_mccmnc };
-            numRowsDeleted = mContentResolver.delete(CarrierIdentification.CONTENT_URI, whereClause,
-                    whereArgs);
+            numRowsDeleted = mContentResolver.delete(CarrierIdentification.All.CONTENT_URI,
+                    whereClause, whereArgs);
         } catch (Exception e) {
             Log.d(TAG, "Error deleting values:" + e);
         }
@@ -241,23 +251,23 @@
         ContentValues contentValues = createCarrierInfoInternal();
 
         try {
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
         } catch (Exception e) {
             Log.d(TAG, "Error inserting carrierInfo:" + e);
         }
 
         try {
             contentValues.put(CarrierIdentification.CID, 1);
-            mContentResolver.update(CarrierIdentification.CONTENT_URI, contentValues,
-                    CarrierIdentification.MCCMNC + "=?", new String[] { dummy_mccmnc });
+            mContentResolver.update(CarrierIdentification.All.CONTENT_URI, contentValues,
+                    CarrierIdentification.All.MCCMNC + "=?", new String[] { dummy_mccmnc });
         } catch (Exception e) {
             Log.d(TAG, "Error updating values:" + e);
         }
 
         try {
-            Cursor findEntry = mContentResolver.query(CarrierIdentification.CONTENT_URI,
+            Cursor findEntry = mContentResolver.query(CarrierIdentification.All.CONTENT_URI,
                     new String[] { CarrierIdentification.CID },
-                    CarrierIdentification.MCCMNC + "=?", new String[] { dummy_mccmnc },
+                    CarrierIdentification.All.MCCMNC + "=?", new String[] { dummy_mccmnc },
                     null);
             findEntry.moveToFirst();
             cid = findEntry.getInt(0);
@@ -274,21 +284,21 @@
 
         try {
             // insert a MVNO
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
             // insert its MNO
             contentValues = new ContentValues();
-            contentValues.put(CarrierIdentification.MCCMNC, dummy_mccmnc);
+            contentValues.put(CarrierIdentification.All.MCCMNC, dummy_mccmnc);
             contentValues.put(CarrierIdentification.CID, 1);
-            mContentResolver.insert(CarrierIdentification.CONTENT_URI, contentValues);
+            mContentResolver.insert(CarrierIdentification.All.CONTENT_URI, contentValues);
         } catch (Exception e) {
             Log.d(TAG, "Error inserting carrierInfo:" + e);
         }
 
         Cursor findEntry = null;
-        String[] columns = {CarrierIdentification.CID, CarrierIdentification.ICCID_PREFIX};
+        String[] columns = {CarrierIdentification.CID, CarrierIdentification.All.ICCID_PREFIX};
         try {
-            findEntry = mContentResolver.query(CarrierIdentification.CONTENT_URI, columns,
-                    CarrierIdentification.MCCMNC + "=?", new String[] { dummy_mccmnc },
+            findEntry = mContentResolver.query(CarrierIdentification.All.CONTENT_URI, columns,
+                    CarrierIdentification.All.MCCMNC + "=?", new String[] { dummy_mccmnc },
                     null);
         } catch (Exception e) {
             Log.d(TAG, "Query failed:" + e);
@@ -297,9 +307,10 @@
 
         try {
             // query based on mccmnc & gid1 & iccid_prefix
-            findEntry = mContentResolver.query(CarrierIdentification.CONTENT_URI, columns,
-                    CarrierIdentification.MCCMNC + "=? and " + CarrierIdentification.GID1 + "=? and "
-                    + CarrierIdentification.ICCID_PREFIX + "=?",
+            findEntry = mContentResolver.query(CarrierIdentification.All.CONTENT_URI, columns,
+                    CarrierIdentification.All.MCCMNC + "=? and "
+                    + CarrierIdentification.All.GID1 + "=? and "
+                    + CarrierIdentification.All.ICCID_PREFIX + "=?",
                     new String[] { dummy_mccmnc, dummy_gid1, dummy_iccid_prefix }, null);
         } catch (Exception e) {
             Log.d(TAG, "Query failed:" + e);
@@ -316,7 +327,7 @@
         int version = 0;
         try {
             Cursor cursor = mContext.getContentResolver().query(
-                    Uri.withAppendedPath(Telephony.CarrierIdentification.CONTENT_URI,
+                    Uri.withAppendedPath(Telephony.CarrierIdentification.All.CONTENT_URI,
                             "get_version"), null, null, null);
             cursor.moveToFirst();
             version = cursor.getInt(0);
@@ -326,16 +337,112 @@
         assertEquals(5, version);
     }
 
+    @Test
+    public void testUpdateCurrentSubscription() {
+        // update carrier id for subId 1
+        try {
+            ContentValues cv = new ContentValues();
+            cv.put(CarrierIdentification.CID, dummy_cid);
+            cv.put(CarrierIdentification.NAME, dummy_name);
+            doReturn(1).when(mSubController).getDefaultSubId();
+            doReturn(true).when(mSubController).isActiveSubId(eq(1));
+            mContext.getContentResolver().update(Uri.withAppendedPath(
+                    CarrierIdentification.CONTENT_URI, "1"), cv, null, null);
+        } catch (Exception e) {
+            Log.d(TAG, "Error updating current subscription: " + e);
+            e.printStackTrace();
+        }
+        int carrierId = -1;
+        String carrierName = null;
+
+        // query carrier id for subId 1
+        try {
+            final Cursor c = mContext.getContentResolver().query(
+                    Uri.withAppendedPath(CarrierIdentification.CONTENT_URI, "1"),
+                    new String[] {CarrierIdentification.CID,
+                    CarrierIdentification.NAME}, null, null);
+            c.moveToFirst();
+            carrierId = c.getInt(0);
+            carrierName = c.getString(1);
+        } catch (Exception e) {
+            Log.d(TAG, "Error query current subscription: " + e);
+        }
+        assertEquals(dummy_cid, carrierId);
+        assertEquals(dummy_name, carrierName);
+
+        // query carrier id for subId 2
+        int count  = -1;
+        try {
+            final Cursor c = mContext.getContentResolver().query(
+                    Uri.withAppendedPath(CarrierIdentification.CONTENT_URI, "2"),
+                    new String[]{CarrierIdentification.CID,
+                            CarrierIdentification.NAME}, null, null);
+            count = c.getCount();
+        } catch (Exception e) {
+            Log.d(TAG, "Error query current subscription: " + e);
+        }
+        assertEquals(0, count);
+
+        // query without subId, expect return carrier id of the default subId
+        try {
+            final Cursor c = mContext.getContentResolver().query(CarrierIdentification.CONTENT_URI,
+                    new String[]{CarrierIdentification.CID,
+                            CarrierIdentification.NAME}, null, null);
+            c.moveToFirst();
+            carrierId = c.getInt(0);
+            carrierName = c.getString(1);
+        } catch (Exception e) {
+            Log.d(TAG, "Error query current subscription: " + e);
+        }
+        assertEquals(dummy_cid, carrierId);
+        assertEquals(dummy_name, carrierName);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testQueryCurrrentSubscription_wrongProjection() {
+        mContext.getContentResolver().query(CarrierIdentification.CONTENT_URI,
+                new String[]{CarrierIdentification.CID,
+                        CarrierIdentification.NAME, CarrierIdentification.All.MCCMNC},
+                null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testQueryWithWrongURI() {
+        try {
+            mContext.getContentResolver().query(Uri.withAppendedPath(
+                    CarrierIdentification.CONTENT_URI, "invalid"),
+                    new String[]{CarrierIdentification.CID, CarrierIdentification.NAME}, null, null);
+            Assert.fail("should throw an exception for wrong uri");
+        } catch (IllegalArgumentException ex) {
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testUpdateCurrentSubscription_WrongURI() {
+        try {
+            ContentValues cv = new ContentValues();
+            cv.put(CarrierIdentification.CID, dummy_cid);
+            cv.put(CarrierIdentification.NAME, dummy_name);
+            doReturn(1).when(mSubController).getDefaultSubId();
+            doReturn(true).when(mSubController).isActiveSubId(eq(1));
+
+            mContext.getContentResolver().update(CarrierIdentification.CONTENT_URI, cv, null, null);
+            Assert.fail("should throw an exception for wrong uri");
+        } catch (IllegalArgumentException ex) {
+            assertFalse(mContentObserver.changed);
+        }
+    }
+
     private static ContentValues createCarrierInfoInternal() {
         ContentValues contentValues = new ContentValues();
-        contentValues.put(CarrierIdentification.MCCMNC, dummy_mccmnc);
-        contentValues.put(CarrierIdentification.GID1, dummy_gid1);
-        contentValues.put(CarrierIdentification.GID2, dummy_gid2);
-        contentValues.put(CarrierIdentification.PLMN, dummy_plmn);
-        contentValues.put(CarrierIdentification.IMSI_PREFIX_XPATTERN, dummy_imsi_prefix);
-        contentValues.put(CarrierIdentification.SPN, dummy_spn);
-        contentValues.put(CarrierIdentification.APN, dummy_apn);
-        contentValues.put(CarrierIdentification.ICCID_PREFIX, dummy_iccid_prefix);
+        contentValues.put(CarrierIdentification.All.MCCMNC, dummy_mccmnc);
+        contentValues.put(CarrierIdentification.All.GID1, dummy_gid1);
+        contentValues.put(CarrierIdentification.All.GID2, dummy_gid2);
+        contentValues.put(CarrierIdentification.All.PLMN, dummy_plmn);
+        contentValues.put(CarrierIdentification.All.IMSI_PREFIX_XPATTERN, dummy_imsi_prefix);
+        contentValues.put(CarrierIdentification.All.SPN, dummy_spn);
+        contentValues.put(CarrierIdentification.All.APN, dummy_apn);
+        contentValues.put(CarrierIdentification.All.ICCID_PREFIX, dummy_iccid_prefix);
         contentValues.put(CarrierIdentification.NAME, dummy_name);
         contentValues.put(CarrierIdentification.CID, dummy_cid);
         return contentValues;