Use Better Exception handling in IMS APIs

Throw more expressive expressions when something bad happens.

Bug: 122742715
Bug: 122480210
Test: atest FrameworksTelephonyTests
Change-Id: I93569395453a07203c84a47b449acf4dbe7d0ddf
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 7b7eb0f..8a4c3d3 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2721,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 {
@@ -2734,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
@@ -2757,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
@@ -3000,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);
         }
@@ -3012,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);
         }
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);
         }
     }