Merge "Create USCC ERI file"
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 8194c60..15c5780 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -137,9 +137,6 @@
 
     private static final int BIND_TIMEOUT_MILLIS = 30000;
 
-    // Length limit of gid1 for naming config file.
-    private static final int GID1_LENGTH_LIMIT = 20;
-
     // Tags used for saving and restoring XML documents.
     private static final String TAG_DOCUMENT = "carrier_config";
     private static final String TAG_VERSION = "package_version";
@@ -260,7 +257,7 @@
                         mContext.unbindService(conn);
                         break;
                     }
-                    final CarrierIdentifier carrierId = getCarrierIdForPhoneId(phoneId);
+                    final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
                     // ResultReceiver callback will execute in this Handler's thread.
                     final ResultReceiver resultReceiver =
                             new ResultReceiver(this) {
@@ -376,7 +373,7 @@
                         mContext.unbindService(conn);
                         break;
                     }
-                    final CarrierIdentifier carrierId = getCarrierIdForPhoneId(phoneId);
+                    final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
                     // ResultReceiver callback will execute in this Handler's thread.
                     final ResultReceiver resultReceiver =
                             new ResultReceiver(this) {
@@ -537,6 +534,9 @@
             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
         }
         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
+        intent.putExtra(TelephonyManager.EXTRA_PRECISE_CARRIER_ID,
+                getPreciseCarrierIdForPhoneId(phoneId));
+        intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId));
         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
         mHasSentConfigChange[phoneId] = true;
     }
@@ -555,7 +555,7 @@
         }
     }
 
-    private CarrierIdentifier getCarrierIdForPhoneId(int phoneId) {
+    private CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) {
         String mcc = "";
         String mnc = "";
         String imsi = "";
@@ -563,6 +563,8 @@
         String gid2 = "";
         String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
         String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
+        int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+        int preciseCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
         // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
         if (simOperator != null && simOperator.length() >= 3) {
             mcc = simOperator.substring(0, 3);
@@ -573,9 +575,10 @@
             imsi = phone.getSubscriberId();
             gid1 = phone.getGroupIdLevel1();
             gid2 = phone.getGroupIdLevel2();
+            carrierId = phone.getCarrierId();
+            preciseCarrierId = phone.getPreciseCarrierId();
         }
-
-        return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
+        return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2, carrierId, preciseCarrierId);
     }
 
     /** Returns the package name of a priveleged carrier app, or null if there is none. */
@@ -601,27 +604,46 @@
         return phone.getIccSerialNumber();
     }
 
-    private String getGid1ForPhoneId(int phoneId) {
+    /**
+     * Get the sim precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()}
+     */
+    private int getPreciseCarrierIdForPhoneId(int phoneId) {
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
-            return null;
+            return TelephonyManager.UNKNOWN_CARRIER_ID;
         }
         Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone == null) {
-            return null;
+            return TelephonyManager.UNKNOWN_CARRIER_ID;
         }
-        String gid1 = phone.getGroupIdLevel1();
-        if (gid1 == null) {
-            return null;
+        return phone.getPreciseCarrierId();
+    }
+
+    /**
+     * Get the sim carrier id {@link TelephonyManager#getSimCarrierId() }
+     */
+    private int getCarrierIdForPhoneId(int phoneId) {
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
+            return TelephonyManager.UNKNOWN_CARRIER_ID;
         }
-        return gid1.substring(0, Math.min(gid1.length(), GID1_LENGTH_LIMIT));
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone == null) {
+            return TelephonyManager.UNKNOWN_CARRIER_ID;
+        }
+        return phone.getCarrierId();
     }
 
     /**
      * Writes a bundle to an XML file.
      *
-     * The bundle will be written to a file named after the package name and ICCID, so that it can
-     * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
-     * and the current version of the specified package.
+     * The bundle will be written to a file named after the package name, ICCID and
+     * precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()}. the same carrier
+     * should have a single copy of XML file named after carrier id. However, it's still possible
+     * that platform doesn't recognize the current sim carrier, we will use iccid + carrierid as
+     * the canonical file name. carrierid can also handle the cases SIM OTA resolves to different
+     * carrier while iccid remains the same.
+     *
+     * The file can be restored later with {@link @restoreConfigFromXml}. The XML output will
+     * include the bundle and the current version of the specified package.
      *
      * In case of errors or invalid input, no file will be written.
      *
@@ -637,8 +659,7 @@
         }
 
         final String iccid = getIccIdForPhoneId(phoneId);
-        // extras is the first 20 characters of gid1
-        final String extras = getGid1ForPhoneId(phoneId);
+        final int cid = getPreciseCarrierIdForPhoneId(phoneId);
         if (packageName == null || iccid == null) {
             loge("Cannot save config with null packageName or iccid.");
             return;
@@ -661,8 +682,8 @@
         FileOutputStream outFile = null;
         try {
             outFile = new FileOutputStream(
-                    new File(mContext.getFilesDir(), getFilenameForConfig(packageName,
-                            iccid, extras)));
+                    new File(mContext.getFilesDir(),
+                            getFilenameForConfig(packageName, iccid, cid)));
             FastXmlSerializer out = new FastXmlSerializer();
             out.setOutput(outFile, "utf-8");
             out.startDocument("utf-8", true);
@@ -713,8 +734,7 @@
         }
 
         final String iccid = getIccIdForPhoneId(phoneId);
-        // extras is the first 20 characters of gid1
-        final String extras = getGid1ForPhoneId(phoneId);
+        final int cid = getPreciseCarrierIdForPhoneId(phoneId);
         if (packageName == null || iccid == null) {
             loge("Cannot restore config with null packageName or iccid.");
             return null;
@@ -724,8 +744,8 @@
         FileInputStream inFile = null;
         try {
             inFile = new FileInputStream(
-                    new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid,
-                            extras)));
+                    new File(mContext.getFilesDir(),
+                            getFilenameForConfig(packageName, iccid, cid)));
             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
             parser.setInput(inFile, "utf-8");
 
@@ -789,11 +809,12 @@
 
     /** Builds a canonical file name for a config file. */
     private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid,
-            String extras) {
-        if (extras != null) {
-            return "carrierconfig-" + packageName + "-" + iccid + "-" + extras + ".xml";
-        }
-        return "carrierconfig-" + packageName + "-" + iccid + ".xml";
+                                        int cid) {
+        // the same carrier should have a single copy of XML file named after carrier id.
+        // However, it's still possible that platform doesn't recognize the current sim carrier,
+        // we will use iccid + carrierid as the canonical file name. carrierid can also handle the
+        // cases SIM OTA resolves to different carrier while iccid remains the same.
+        return "carrierconfig-" + packageName + "-" + iccid + "-" + cid + ".xml";
     }
 
     /** Return the current version code of a package, or null if the name is not found. */
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index bf0ce15..dfea90c 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -101,6 +101,7 @@
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CarrierInfoManager;
+import com.android.internal.telephony.CarrierResolver;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.DefaultPhoneNotifier;
@@ -2163,6 +2164,20 @@
         }
     }
 
+    @Override
+    public int getCarrierIdFromMccMnc(int slotIndex, String mccmnc) {
+        final Phone phone = PhoneFactory.getPhone(slotIndex);
+        if (phone == null) {
+            return TelephonyManager.UNKNOWN_CARRIER_ID;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return CarrierResolver.getCarrierIdFromMccMnc(phone.getContext(), mccmnc);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     //
     // Internal helper methods.
     //
@@ -2676,12 +2691,9 @@
     }
 
     @Override
-    public void addImsRegistrationCallback(int subId, IImsRegistrationCallback c,
-            String callingPackage) throws RemoteException {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "addImsRegistrationCallback")) {
-            return;
-        }
+    public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
+            throws RemoteException {
+        enforceReadPrivilegedPermission("registerImsRegistrationCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2693,12 +2705,8 @@
     }
 
     @Override
-    public void removeImsRegistrationCallback(int subId, IImsRegistrationCallback c,
-            String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "removeImsRegistrationCallback")) {
-            return;
-        }
+    public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
+        enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         Binder.withCleanCallingIdentity(() ->
                 ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
@@ -2706,12 +2714,9 @@
     }
 
     @Override
-    public void addMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
-            String callingPackage) throws RemoteException {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "addMmTelCapabilityCallback")) {
-            return;
-        }
+    public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
+            throws RemoteException {
+        enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2723,12 +2728,8 @@
     }
 
     @Override
-    public void removeMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
-            String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "removeMmTelCapabilityCallback")) {
-            return;
-        }
+    public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
+        enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         Binder.withCleanCallingIdentity(() ->
                 ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
@@ -2736,11 +2737,8 @@
     }
 
     @Override
-    public boolean isCapable(int subId, int capability, int regTech, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "isCapable")) {
-            return false;
-        }
+    public boolean isCapable(int subId, int capability, int regTech) {
+        enforceReadPrivilegedPermission("isCapable");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2755,11 +2753,8 @@
     }
 
     @Override
-    public boolean isAvailable(int subId, int capability, int regTech, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "isAvailable")) {
-            return false;
-        }
+    public boolean isAvailable(int subId, int capability, int regTech) {
+        enforceReadPrivilegedPermission("isAvailable");
         final long token = Binder.clearCallingIdentity();
         try {
             Phone phone = getPhone(subId);
@@ -2798,11 +2793,8 @@
     }
 
     @Override
-    public boolean isVtSettingEnabled(int subId, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                "isVtSettingEnabled")) {
-            return false;
-        }
+    public boolean isVtSettingEnabled(int subId) {
+        enforceReadPrivilegedPermission("isVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 9ed34e7..a92dea7 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -311,6 +311,10 @@
                 resourceId = R.string.callFailed_unobtainable_number;
                 break;
 
+            case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
+                resourceId = R.string.incall_error_missing_voicemail_number;
+                break;
+
             case android.telephony.DisconnectCause.CALL_PULLED:
                 resourceId = R.string.callEnded_pulled;
                 break;
@@ -666,8 +670,6 @@
                 break;
 
             case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
-                // TODO: Need to bring up the "Missing Voicemail Number" dialog, which
-                // will ultimately take us to the Call Settings.
                 resourceId = R.string.incall_error_missing_voicemail_number;
                 break;
 
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
index ae5b39e..fea2bf8 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -165,7 +165,7 @@
             mImsManager = ImsMmTelManager.createForSubscriptionId(this,
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
             Log.i("ImsCallingActivity", "onResume");
-            mImsManager.addMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
+            mImsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
         } catch (IllegalArgumentException e) {
             Log.w("ImsCallingActivity", "illegal subscription ID.");
         }
@@ -174,7 +174,7 @@
     @Override
     protected void onPause() {
         super.onPause();
-        mImsManager.removeMmTelCapabilityCallback(mCapabilityCallback);
+        mImsManager.unregisterMmTelCapabilityCallback(mCapabilityCallback);
         mImsManager = null;
     }
 
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
index bca8eba..3317ff1 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -179,7 +179,7 @@
         try {
             mImsManager = ImsMmTelManager.createForSubscriptionId(this,
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
-            mImsManager.addImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
+            mImsManager.registerImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
         } catch (IllegalArgumentException e) {
             Log.w("ImsCallingActivity", "illegal subscription ID.");
         }
@@ -219,7 +219,7 @@
     @Override
     protected void onPause() {
         super.onPause();
-        mImsManager.removeImsRegistrationCallback(mRegistrationCallback);
+        mImsManager.unregisterImsRegistrationCallback(mRegistrationCallback);
         mImsManager = null;
     }