Merge "Import translations. DO NOT MERGE"
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 3031d72..fe525b0 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -52,11 +52,11 @@
 import android.os.WorkSource;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
-import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoWcdma;
@@ -130,6 +130,7 @@
 import com.android.internal.telephony.SmsApplication.SmsApplicationData;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.euicc.EuiccConnector;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
@@ -153,9 +154,11 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Implementation of the ITelephony interface.
@@ -840,10 +843,10 @@
 
                 case CMD_SET_ALLOWED_CARRIERS:
                     request = (MainThreadRequest) msg.obj;
+                    CarrierRestrictionRules argument =
+                            (CarrierRestrictionRules) request.argument;
                     onCompleted = obtainMessage(EVENT_SET_ALLOWED_CARRIERS_DONE, request);
-                    defaultPhone.setAllowedCarriers(
-                            (List<CarrierIdentifier>) request.argument,
-                            onCompleted, request.workSource);
+                    defaultPhone.setAllowedCarriers(argument, onCompleted, request.workSource);
                     break;
 
                 case EVENT_SET_ALLOWED_CARRIERS_DONE:
@@ -852,19 +855,19 @@
                     if (ar.exception == null && ar.result != null) {
                         request.result = ar.result;
                     } else {
-                        if (ar.result == null) {
-                            loge("setAllowedCarriers: Empty response");
-                        } else if (ar.exception instanceof CommandException) {
-                            loge("setAllowedCarriers: CommandException: " +
-                                    ar.exception);
+                        request.result = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR;
+                        if (ar.exception instanceof CommandException) {
+                            loge("setAllowedCarriers: CommandException: " + ar.exception);
+                            CommandException.Error error =
+                                    ((CommandException) (ar.exception)).getCommandError();
+                            if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                                request.result =
+                                        TelephonyManager.SET_CARRIER_RESTRICTION_NOT_SUPPORTED;
+                            }
                         } else {
                             loge("setAllowedCarriers: Unknown exception");
                         }
                     }
-                    // Result cannot be null. Return -1 on error.
-                    if (request.result == null) {
-                        request.result = new int[]{-1};
-                    }
                     notifyRequester(request);
                     break;
 
@@ -880,6 +883,8 @@
                     if (ar.exception == null && ar.result != null) {
                         request.result = ar.result;
                     } else {
+                        request.result = new IllegalStateException(
+                            "Failed to get carrier restrictions");
                         if (ar.result == null) {
                             loge("getAllowedCarriers: Empty response");
                         } else if (ar.exception instanceof CommandException) {
@@ -889,10 +894,6 @@
                             loge("getAllowedCarriers: Unknown exception");
                         }
                     }
-                    // Result cannot be null. Return empty list of CarrierIdentifier.
-                    if (request.result == null) {
-                        request.result = new ArrayList<CarrierIdentifier>(0);
-                    }
                     notifyRequester(request);
                     break;
 
@@ -2720,9 +2721,9 @@
     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 {
+            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .addRegistrationCallbackForSubscription(c, subId);
         } finally {
@@ -2733,10 +2734,21 @@
     @Override
     public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
         enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
-        // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-        Binder.withCleanCallingIdentity(() ->
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+        }
+        Binder.withCleanCallingIdentity(() -> {
+            try {
+                // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
                 ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                        .removeRegistrationCallbackForSubscription(c, subId));
+                        .removeRegistrationCallbackForSubscription(c, subId);
+            } catch (IllegalArgumentException e) {
+                Log.i(LOG_TAG, "unregisterImsRegistrationCallback: " + subId
+                        + "is inactive, ignoring unregister.");
+                // If the subscription is no longer active, just return, since the callback
+                // will already have been removed internally.
+            }
+        });
     }
 
     @Override
@@ -2756,10 +2768,22 @@
     @Override
     public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
         enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
-        // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-        Binder.withCleanCallingIdentity(() ->
+
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+        }
+        Binder.withCleanCallingIdentity(() -> {
+            try {
+                // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
                 ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                        .removeCapabilitiesCallbackForSubscription(c, subId));
+                        .removeCapabilitiesCallbackForSubscription(c, subId);
+            } catch (IllegalArgumentException e) {
+                Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
+                        + "is inactive, ignoring unregister.");
+                // If the subscription is no longer active, just return, since the callback
+                // will already have been removed internally.
+            }
+        });
     }
 
     @Override
@@ -2999,9 +3023,7 @@
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .getConfigInterface().addConfigCallback(callback);
-        } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+                    .addProvisioningCallbackForSubscription(callback, subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3011,12 +3033,18 @@
     public void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback) {
         enforceReadPrivilegedPermission("unregisterImsProvisioningChangedCallback");
         final long identity = Binder.clearCallingIdentity();
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+        }
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .getConfigInterface().removeConfigCallback(callback);
-        } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+                    .removeProvisioningCallbackForSubscription(callback, subId);
+        } catch (IllegalArgumentException e) {
+            Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
+                    + "is inactive, ignoring unregister.");
+            // If the subscription is no longer active, just return, since the callback will already
+            // have been removed internally.
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5236,27 +5264,26 @@
 
     /**
      * {@hide}
-     * Set the allowed carrier list for slotIndex
+     * Set the allowed carrier list and the excluded carrier list, indicating the priority between
+     * the two lists.
      * Require system privileges. In the future we may add this to carrier APIs.
      *
-     * @return The number of carriers set successfully, should match length of carriers
+     * @return Integer with the result of the operation, as defined in {@link TelephonyManager}.
      */
     @Override
-    public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
+    @TelephonyManager.SetCarrierRestrictionResult
+    public int setAllowedCarriers(CarrierRestrictionRules carrierRestrictionRules) {
         enforceModifyPermission();
         WorkSource workSource = getWorkSource(Binder.getCallingUid());
 
-        if (carriers == null) {
-            throw new NullPointerException("carriers cannot be null");
+        if (carrierRestrictionRules == null) {
+            throw new NullPointerException("carrier restriction cannot be null");
         }
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            int[] subIds = SubscriptionManager.getSubId(slotIndex);
-            int subId = (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            int[] retVal = (int[]) sendRequest(CMD_SET_ALLOWED_CARRIERS, carriers, subId,
+            return (int) sendRequest(CMD_SET_ALLOWED_CARRIERS, carrierRestrictionRules,
                     workSource);
-            return retVal[0];
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5264,23 +5291,29 @@
 
     /**
      * {@hide}
-     * Get the allowed carrier list for slotIndex.
+     * Get the allowed carrier list and the excluded carrier list, including the priority between
+     * the two lists.
      * Require system privileges. In the future we may add this to carrier APIs.
      *
-     * @return List of {@link android.service.telephony.CarrierIdentifier}; empty list
-     * means all carriers are allowed.
+     * @return {@link android.telephony.CarrierRestrictionRules}
      */
     @Override
-    public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) {
+    public CarrierRestrictionRules getAllowedCarriers() {
         enforceReadPrivilegedPermission("getAllowedCarriers");
         WorkSource workSource = getWorkSource(Binder.getCallingUid());
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            int[] subIds = SubscriptionManager.getSubId(slotIndex);
-            int subId = (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            return (List<CarrierIdentifier>) sendRequest(CMD_GET_ALLOWED_CARRIERS, null, subId,
-                    workSource);
+            Object response = sendRequest(CMD_GET_ALLOWED_CARRIERS, null, workSource);
+            if (response instanceof CarrierRestrictionRules) {
+                return (CarrierRestrictionRules) response;
+            }
+            // Response is an Exception of some kind,
+            // which is signalled to the user as a NULL retval
+            return null;
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "getAllowedCarriers. Exception ex=" + e);
+            return null;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6061,6 +6094,52 @@
         }
     }
 
+    /**
+     * Update emergency number list for test mode.
+     */
+    @Override
+    public void updateEmergencyNumberListTestMode(int action, EmergencyNumber num) {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "updateEmergencyNumberListTestMode");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    tracker.executeEmergencyNumberTestModeCommand(action, num);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get the full emergency number list for test mode.
+     */
+    @Override
+    public List<String> getEmergencyNumberListTestMode() {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "getEmergencyNumberListTestMode");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Set<String> emergencyNumbers = new HashSet<>();
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    for (EmergencyNumber num : tracker.getEmergencyNumberList()) {
+                        emergencyNumbers.add(num.getNumber());
+                    }
+                }
+            }
+            return new ArrayList<>(emergencyNumbers);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public List<String> getCertsFromCarrierPrivilegeAccessRules(int subId) {
         enforceReadPrivilegedPermission("getCertsFromCarrierPrivilegeAccessRules");
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 9250118..956e0e2 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -22,11 +22,14 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.telephony.SubscriptionManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.util.Log;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 /**
  * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
@@ -44,6 +47,7 @@
     private static final String IMS_SUBCOMMAND = "ims";
     private static final String SMS_SUBCOMMAND = "sms";
     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
+    private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
 
     private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
@@ -79,6 +83,8 @@
             }
             case NUMBER_VERIFICATION_SUBCOMMAND:
                 return handleNumberVerificationCommand();
+            case EMERGENCY_NUMBER_TEST_MODE:
+                return handleEmergencyNumberTestModeCommand();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -95,8 +101,11 @@
         pw.println("    IMS Commands.");
         pw.println("  sms");
         pw.println("    SMS Commands.");
+        pw.println("  emergency-number-test-mode");
+        pw.println("    Emergency Number Test Mode Commands.");
         onHelpIms();
         onHelpSms();
+        onHelpEmergencyNumber();
     }
 
     private void onHelpIms() {
@@ -147,6 +156,20 @@
         pw.println("    1 if the call would have been intercepted, 0 otherwise.");
     }
 
+    private void onHelpEmergencyNumber() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Emergency Number Test Mode Commands:");
+        pw.println("  emergency-number-test-mode ");
+        pw.println("    Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
+                + " the test mode");
+        pw.println("      -a <emergency number address>: add an emergency number address for the"
+                + " test mode, only allows '0'-'9', '*', or '#'.");
+        pw.println("      -c: clear the emergency number list in the test mode.");
+        pw.println("      -r <emergency number address>: remove an existing emergency number"
+                + " address added by the test mode, only allows '0'-'9', '*', or '#'.");
+        pw.println("      -p: get the full emergency number list in the test mode.");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -172,6 +195,91 @@
         return -1;
     }
 
+    private int handleEmergencyNumberTestModeCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+        String opt = getNextOption();
+        if (opt == null) {
+            onHelpEmergencyNumber();
+            return 0;
+        }
+
+        switch (opt) {
+            case "-a": {
+                String emergencyNumberCmd = getNextArgRequired();
+                if (emergencyNumberCmd == null
+                        || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
+                    errPw.println("An emergency number (only allow '0'-'9', '*', or '#') needs"
+                            + " to be specified after -a in the command ");
+                    return -1;
+                }
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
+                            new EmergencyNumber(emergencyNumberCmd, "", "",
+                                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                                    new ArrayList<String>(),
+                                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
+                                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
+                            + ", error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-c": {
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-r": {
+                String emergencyNumberCmd = getNextArgRequired();
+                if (emergencyNumberCmd == null
+                        || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
+                    errPw.println("An emergency number (only allow '0'-'9', '*', or '#') needs"
+                            + " to be specified after -r in the command ");
+                    return -1;
+                }
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
+                            new EmergencyNumber(emergencyNumberCmd, "", "",
+                                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                                    new ArrayList<String>(),
+                                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
+                                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
+                            + ", error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-p": {
+                try {
+                    getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            default:
+                onHelpEmergencyNumber();
+                break;
+        }
+        return 0;
+    }
+
     private int handleNumberVerificationCommand() {
         String arg = getNextArg();
         if (arg == null) {
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 228eed1..c267835 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -84,6 +84,7 @@
         private boolean mIsRttCapable;
         private MmTelFeature.MmTelCapabilities mMmTelCapabilities;
         private ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback;
+        private ImsMmTelManager mMmTelManager;
         private final boolean mIsDummy;
         private boolean mIsVideoCapable;
         private boolean mIsVideoPresenceSupported;
@@ -106,51 +107,54 @@
             mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((Phone) mPhone,
                     this);
 
-            if (!mIsDummy) {
-                ImsMmTelManager manager;
-                try {
-                    manager = ImsMmTelManager.createForSubscriptionId(mContext, getSubId());
-                } catch (IllegalArgumentException e) {
-                    Log.i(this, "Not registering Mmtel listener because the subid is invalid");
-                    return;
-                }
-
-                boolean isImsVoiceCapable = manager.isCapable(
-                        ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
-                        MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE)
-                        || manager.isCapable(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
-                        MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
-
-                if (!isImsVoiceCapable) {
-                    Log.i(this, "Not registering MmTel listener because"
-                            + " voice over IMS isn't supported");
-                    return;
-                }
-
-                mMmtelCapabilityCallback =
-                        new ImsMmTelManager.CapabilityCallback() {
-                            @Override
-                            public void onCapabilitiesStatusChanged(
-                                    MmTelFeature.MmTelCapabilities capabilities) {
-                                mMmTelCapabilities = capabilities;
-                                updateRttCapability();
-                            }
-                        };
-                manager.registerMmTelCapabilityCallback(mContext.getMainExecutor(),
-                                mMmtelCapabilityCallback);
+            if (mIsDummy || isEmergency) {
+                // For dummy and emergency entries, there is no sub ID that can be assigned, so do
+                // not register for capabilities callbacks.
+                return;
             }
+
+            try {
+                mMmTelManager = ImsMmTelManager.createForSubscriptionId(mContext, getSubId());
+            } catch (IllegalArgumentException e) {
+                Log.i(this, "Not registering MmTel capabilities listener because the subid '"
+                        + getSubId() + "' is invalid");
+                return;
+            }
+
+            mMmtelCapabilityCallback = new ImsMmTelManager.CapabilityCallback() {
+                @Override
+                public void onCapabilitiesStatusChanged(
+                        MmTelFeature.MmTelCapabilities capabilities) {
+                    mMmTelCapabilities = capabilities;
+                    updateRttCapability();
+                }
+            };
+
+            registerMmTelCapabilityCallback();
         }
 
         void teardown() {
             mIncomingCallNotifier.teardown();
             mPhoneCapabilitiesNotifier.teardown();
-            if (mMmtelCapabilityCallback != null) {
-                try {
-                    ImsMmTelManager.createForSubscriptionId(mContext, getSubId())
-                            .unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
-                } catch (IllegalArgumentException e) {
-                    // TODO (breadley): Tearing down may fail if the sim has been removed.
-                }
+            if (mMmTelManager != null && mMmtelCapabilityCallback != null) {
+                mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
+            }
+        }
+
+        private void registerMmTelCapabilityCallback() {
+            if (mMmTelManager == null || mMmtelCapabilityCallback == null) {
+                // The subscription id associated with this account is invalid or not associated
+                // with a subscription. Do not register in this case.
+                return;
+            }
+
+            try {
+                mMmTelManager.registerMmTelCapabilityCallback(mContext.getMainExecutor(),
+                        mMmtelCapabilityCallback);
+            } catch (IllegalStateException e) {
+                Log.w(this, "registerMmTelCapabilityCallback: registration failed, no ImsService"
+                        + " available.");
+                return;
             }
         }
 
@@ -575,21 +579,14 @@
         }
 
         public void updateRttCapability() {
-            // In the rare case that mMmTelCapabilities hasn't been set yet, try fetching it
-            // directly.
-            boolean hasVoiceAvailability;
-            if (mMmTelCapabilities != null) {
-                hasVoiceAvailability = mMmTelCapabilities.isCapable(
-                        MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
-            } else {
-                hasVoiceAvailability = isImsVoiceAvailable();
-            }
+            boolean hasVoiceAvailability = isImsVoiceAvailable();
 
             boolean isRttSupported = PhoneGlobals.getInstance().phoneMgr
                     .isRttEnabled(mPhone.getSubId());
 
             boolean isRttEnabled = hasVoiceAvailability && isRttSupported;
             if (isRttEnabled != mIsRttCapable) {
+                Log.i(this, "updateRttCapability - changed, new value: " + isRttEnabled);
                 mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
             }
         }
@@ -659,11 +656,17 @@
                         MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
             }
 
-            ImsMmTelManager manager = ImsMmTelManager.createForSubscriptionId(
-                    mContext, getSubId());
-            return manager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+            if (mMmTelManager == null) {
+                // The Subscription is invalid, so IMS is unavailable.
+                return false;
+            }
+
+            // In the rare case that mMmTelCapabilities hasn't been set, try fetching it
+            // directly and register callback.
+            registerMmTelCapabilityCallback();
+            return mMmTelManager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE)
-                    || manager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                    || mMmTelManager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
         }
     }