Merge "Check to ensure an ImsService can handle an IMS request" into sc-dev
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 2e4ee94..64e93a5 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -49,7 +49,6 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.telephony.ims.ImsResolver;
-import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.services.telephony.rcs.RcsFeatureController;
 import com.android.services.telephony.rcs.SipTransportController;
 import com.android.services.telephony.rcs.TelephonyRcsService;
@@ -214,6 +213,8 @@
         final long token = Binder.clearCallingIdentity();
         try {
             getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "unregisterRcsAvailabilityCallback: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -338,12 +339,16 @@
     public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
             Set<String> featureTags) throws ImsException {
         // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.addUceRegistrationOverride(featureTags);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.addUceRegistrationOverride(featureTags);
     }
 
     /**
@@ -353,12 +358,16 @@
     public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
             Set<String> featureTags) throws ImsException {
         // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.removeUceRegistrationOverride(featureTags);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.removeUceRegistrationOverride(featureTags);
     }
 
     /**
@@ -367,13 +376,17 @@
     // Used for SHELL command only right now.
     public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId)
             throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.clearUceRegistrationOverride();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.clearUceRegistrationOverride();
     }
 
     /**
@@ -382,13 +395,17 @@
     // Used for SHELL command only right now.
     public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId)
             throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.getLatestRcsContactUceCapability();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.getLatestRcsContactUceCapability();
     }
 
     /**
@@ -397,14 +414,18 @@
      */
     // Used for SHELL command only right now.
     public String getLastUcePidfXmlShell(int subId) throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            String pidfXml = uceCtrlManager.getLastPidfXml();
+            return pidfXml == null ? "none" : pidfXml;
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        String pidfXml = uceCtrlManager.getLastPidfXml();
-        return pidfXml == null ? "none" : pidfXml;
     }
 
     /**
@@ -413,12 +434,16 @@
      */
     // Used for SHELL command only right now.
     public boolean removeUceRequestDisallowedStatus(int subId) throws ImsException {
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return false;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return false;
+            }
+            return uceCtrlManager.removeUceRequestDisallowedStatus();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.removeUceRequestDisallowedStatus();
     }
 
     /**
@@ -426,12 +451,16 @@
      */
     // Used for SHELL command only right now.
     public boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfter) throws ImsException {
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return false;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return false;
+            }
+            return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
     }
 
     @Override
@@ -465,6 +494,8 @@
                         "This subscription does not support UCE.");
             }
             uceCtrlManager.unregisterPublishStateCallback(c);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "unregisterUcePublishStateCallback: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -580,6 +611,8 @@
                 return;
             }
             transport.destroySipDelegate(subId, connection, reason);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "destroySipDelegate: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -598,6 +631,8 @@
                 return;
             }
             transport.triggerFullNetworkRegistration(subId, connection, sipCode, sipReason);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "triggerNetworkRegistration: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -688,31 +723,6 @@
     }
 
     /**
-     * Retrieve ImsPhone instance.
-     *
-     * @param subId the subscription ID
-     * @return The ImsPhone instance
-     * @throws ServiceSpecificException if getting ImsPhone instance failed.
-     */
-    private ImsPhone getImsPhone(int subId) {
-        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS is not available on device.");
-        }
-        Phone phone = PhoneGlobals.getPhone(subId);
-        if (phone == null) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
-                    "Invalid subscription Id: " + subId);
-        }
-        ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
-        if (imsPhone == null) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
-                    "Cannot find ImsPhone instance: " + subId);
-        }
-        return imsPhone;
-    }
-
-    /**
      * Retrieve RcsFeatureManager instance.
      *
      * @param subId the subscription ID
@@ -734,6 +744,7 @@
                     "Invalid subscription Id: " + subId);
         }
         int slotId = phone.getPhoneId();
+        verifyImsRcsConfiguredOrThrow(slotId);
         RcsFeatureController c = mRcsService.getFeatureController(slotId);
         if (c == null) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -742,6 +753,20 @@
         return c;
     }
 
+    /**
+     * Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
+     * for the given slot ID or no ImsResolver instance has been created.
+     * @param slotId The slot ID that the IMS service is created for.
+     * @throws ServiceSpecificException If there is no ImsService configured for this slot.
+     */
+    private void verifyImsRcsConfiguredOrThrow(int slotId) {
+        if (mImsResolver == null
+                || !mImsResolver.isImsServiceConfiguredForFeature(slotId, ImsFeature.FEATURE_RCS)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "This subscription does not support RCS");
+        }
+    }
+
     private boolean isImsSingleRegistrationSupportedOnDevice() {
         return mSingleRegistrationOverride != null ? mSingleRegistrationOverride
                 : mApp.getPackageManager().hasSystemFeature(
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index ba3d138..906d4c3 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -3845,9 +3845,9 @@
         }
         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);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).addRegistrationCallbackForSubscription(c, subId);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -3869,7 +3869,6 @@
         }
         final long token = Binder.clearCallingIdentity();
         try {
-            // TODO(b/159910732): Remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .removeRegistrationCallbackForSubscription(c, subId);
         } catch (ImsException e) {
@@ -3965,11 +3964,11 @@
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
         }
-        // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .addCapabilitiesCallbackForSubscription(c, subId);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).addCapabilitiesCallbackForSubscription(c, subId);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -3992,7 +3991,6 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            // TODO(b/159910732): Remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                         .removeCapabilitiesCallbackForSubscription(c, subId);
         } catch (ImsException e) {
@@ -4008,11 +4006,11 @@
     @Override
     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 {
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).queryMmTelCapability(capability, regTech);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).queryMmTelCapability(capability, regTech);
         } catch (com.android.ims.ImsException e) {
             Log.w(LOG_TAG, "IMS isCapable - service unavailable: " + e.getMessage());
             return false;
@@ -4064,6 +4062,7 @@
                         + subId + "'");
                 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
             }
+            verifyImsMmTelConfiguredOrThrow(slotId);
             ImsManager.getInstance(mApp, slotId).isSupported(capability,
                     transportType, aBoolean -> {
                         try {
@@ -4073,6 +4072,8 @@
                                     + "running. Ignore");
                         }
                     });
+        } catch (ImsException e) {
+            throw new ServiceSpecificException(e.getCode());
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -4087,11 +4088,11 @@
         TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
                 mApp, subId, "isAdvancedCallingSettingEnabled");
 
-        // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).isEnhanced4gLteModeSettingEnabledByUser();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isEnhanced4gLteModeSettingEnabledByUser();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4105,9 +4106,9 @@
                 "setAdvancedCallingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setEnhanced4gLteModeSetting(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setEnhanced4gLteModeSetting(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4125,8 +4126,9 @@
                 mApp, subId, "isVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).isVtEnabledByUser();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isVtEnabledByUser();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4140,8 +4142,9 @@
                 "setVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).setVtSetting(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setVtSetting(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4159,9 +4162,9 @@
                 mApp, subId, "isVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).isWfcEnabledByUser();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isWfcEnabledByUser();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4175,8 +4178,9 @@
                 "setVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).setWfcSetting(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setWfcSetting(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4195,9 +4199,9 @@
                 mApp, subId, "isCrossSimCallingEnabledByUser");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).isCrossSimCallingEnabledByUser();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isCrossSimCallingEnabledByUser();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4218,9 +4222,9 @@
                 "setCrossSimCallingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .setCrossSimCallingEnabled(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setCrossSimCallingEnabled(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4239,9 +4243,9 @@
                 mApp, subId, "isVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).isWfcRoamingEnabledByUser();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isWfcRoamingEnabledByUser();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4255,9 +4259,9 @@
                 "setVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setWfcRoamingSetting(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setWfcRoamingSetting(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4271,9 +4275,9 @@
                 "setVoWiFiNonPersistent");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setWfcNonPersistent(isCapable, mode);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setWfcNonPersistent(isCapable, mode);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4291,9 +4295,9 @@
                 mApp, subId, "getVoWiFiModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getWfcMode(false /*isRoaming*/);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).getWfcMode(false /*isRoaming*/);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4307,9 +4311,9 @@
                 "setVoWiFiModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setWfcMode(mode, false /*isRoaming*/);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setWfcMode(mode, false /*isRoaming*/);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4322,9 +4326,9 @@
         enforceReadPrivilegedPermission("getVoWiFiRoamingModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getWfcMode(true /*isRoaming*/);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).getWfcMode(true /*isRoaming*/);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4338,9 +4342,9 @@
                 "setVoWiFiRoamingModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setWfcMode(mode, true /*isRoaming*/);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setWfcMode(mode, true /*isRoaming*/);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4354,8 +4358,9 @@
                 "setRttCapabilityEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).setRttEnabled(isEnabled);
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId).setRttEnabled(isEnabled);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4373,9 +4378,9 @@
                 mApp, subId, "isTtyOverVolteEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).isTtyOnVoLteCapable();
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            return ImsManager.getInstance(mApp, slotId).isTtyOnVoLteCapable();
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4392,8 +4397,9 @@
                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                         "IMS not available on device.");
             }
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
+            int slotId = getSlotIndexOrException(subId);
+            verifyImsMmTelConfiguredOrThrow(slotId);
+            ImsManager.getInstance(mApp, slotId)
                     .addProvisioningCallbackForSubscription(callback, subId);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
@@ -4410,7 +4416,6 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         try {
-            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .removeProvisioningCallbackForSubscription(callback, subId);
         } catch (ImsException e) {
@@ -4857,6 +4862,20 @@
         }
     }
 
+    /**
+     * Throw an ImsException if the IMS resolver does not have an ImsService configured for MMTEL
+     * for the given slot ID or no ImsResolver instance has been created.
+     * @param slotId The slot ID that the IMS service is created for.
+     * @throws ImsException If there is no ImsService configured for this slot.
+     */
+    private void verifyImsMmTelConfiguredOrThrow(int slotId) throws ImsException {
+        if (mImsResolver == null || !mImsResolver.isImsServiceConfiguredForFeature(slotId,
+                ImsFeature.FEATURE_MMTEL)) {
+            throw new ImsException("This subscription does not support MMTEL over IMS",
+                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+        }
+    }
+
     private int getSlotIndexOrException(int subId) throws ImsException {
         int slotId = SubscriptionManager.getSlotIndex(subId);
         if (!SubscriptionManager.isValidSlotIndex(slotId)) {
@@ -5817,6 +5836,7 @@
                         + subId + "'");
                 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
             }
+            verifyImsMmTelConfiguredOrThrow(slotId);
             ImsManager.getInstance(mApp, slotId).getImsServiceState(anInteger -> {
                 try {
                     callback.accept(anInteger == null ? ImsFeature.STATE_UNAVAILABLE : anInteger);
@@ -5825,6 +5845,8 @@
                             + "Ignore");
                 }
             });
+        } catch (ImsException e) {
+            throw new ServiceSpecificException(e.getCode());
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -10079,8 +10101,8 @@
         try {
             if (!RcsProvisioningMonitor.getInstance()
                     .registerRcsProvisioningCallback(subId, callback)) {
-                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                        "Service not available for the subscription.");
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
+                        "Active subscription not found.");
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -10161,11 +10183,15 @@
             IImsConfig configBinder = getImsConfig(getSlotIndex(subId), ImsFeature.FEATURE_RCS);
             if (configBinder == null) {
                 Rlog.e(LOG_TAG, "null result for setRcsClientConfiguration");
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
+                        "could not find the requested subscription");
             } else {
                 configBinder.setRcsClientConfiguration(rcc);
             }
         } catch (RemoteException e) {
             Rlog.e(LOG_TAG, "fail to setRcsClientConfiguration " + e.getMessage());
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+                    "service is temporarily unavailable.");
         } finally {
             Binder.restoreCallingIdentity(identity);
         }