When the associated subId indication comes in, do not destroy UCE

When the associated subid indication comes in for the same subId,
this means that the carrier configuration may have changed. Do not
tear down and bring down the enture UCE stack for this indication,
instead, handle the carrier config changed indication properly and
notify all controllers of the change.

Bug: 181258463
Test: atest ImsCommonTests
Change-Id: If6233e59b49ca305d0720c18d0c25ae9e1494c5f
diff --git a/src/java/com/android/ims/RcsFeatureManager.java b/src/java/com/android/ims/RcsFeatureManager.java
index c58dd28..aeec1a0 100644
--- a/src/java/com/android/ims/RcsFeatureManager.java
+++ b/src/java/com/android/ims/RcsFeatureManager.java
@@ -206,12 +206,12 @@
     /**
      * Update the capabilities for this RcsFeature.
      */
-    public void updateCapabilities() throws android.telephony.ims.ImsException {
-        boolean optionsSupport = isOptionsSupported();
-        boolean presenceSupported = isPresenceSupported();
+    public void updateCapabilities(int newSubId) throws android.telephony.ims.ImsException {
+        boolean optionsSupport = isOptionsSupported(newSubId);
+        boolean presenceSupported = isPresenceSupported(newSubId);
 
-        logi("Update capabilities for slot " + mSlotId + ": options=" + optionsSupport
-                + ", presence=" + presenceSupported);
+        logi("Update capabilities for slot " + mSlotId + " and sub " + newSubId + ": options="
+                + optionsSupport+ ", presence=" + presenceSupported);
 
         if (optionsSupport || presenceSupported) {
             CapabilityChangeRequest request = new CapabilityChangeRequest();
@@ -458,36 +458,35 @@
         }
     }
 
-    private boolean isOptionsSupported() {
-        return isCapabilityTypeSupported(mContext, mSlotId, CAPABILITY_OPTIONS);
+    private boolean isOptionsSupported(int subId) {
+        return isCapabilityTypeSupported(mContext, subId, CAPABILITY_OPTIONS);
     }
 
-    private boolean isPresenceSupported() {
-        return isCapabilityTypeSupported(mContext, mSlotId, CAPABILITY_PRESENCE);
+    private boolean isPresenceSupported(int subId) {
+        return isCapabilityTypeSupported(mContext, subId, CAPABILITY_PRESENCE);
     }
 
     /*
      * Check if the given type of capability is supported.
      */
     private static boolean isCapabilityTypeSupported(
-        Context context, int slotId, int capabilityType) {
+        Context context, int subId, int capabilityType) {
 
-        int subId = sSubscriptionManagerProxy.getSubId(slotId);
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            Log.e(TAG, "isCapabilityTypeSupported: Getting subIds is failure! slotId=" + slotId);
+            Log.e(TAG, "isCapabilityTypeSupported: Invalid subId=" + subId);
             return false;
         }
 
         CarrierConfigManager configManager =
             (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) {
-            Log.e(TAG, "isCapabilityTypeSupported: CarrierConfigManager is null, " + slotId);
+            Log.e(TAG, "isCapabilityTypeSupported: CarrierConfigManager is null, " + subId);
             return false;
         }
 
         PersistableBundle b = configManager.getConfigForSubId(subId);
         if (b == null) {
-            Log.e(TAG, "isCapabilityTypeSupported: PersistableBundle is null, " + slotId);
+            Log.e(TAG, "isCapabilityTypeSupported: PersistableBundle is null, " + subId);
             return false;
         }
 
diff --git a/src/java/com/android/ims/rcs/uce/ControllerBase.java b/src/java/com/android/ims/rcs/uce/ControllerBase.java
index cb45f44..57f0fc7 100644
--- a/src/java/com/android/ims/rcs/uce/ControllerBase.java
+++ b/src/java/com/android/ims/rcs/uce/ControllerBase.java
@@ -36,4 +36,9 @@
      * Notify to destroy this instance. The UceController instance is unusable after destroyed.
      */
     void onDestroy();
+
+    /**
+     * Notify the controller that the Carrier Config has changed.
+     */
+    void onCarrierConfigChanged();
 }
diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java
index 6d8c53b..1494738 100644
--- a/src/java/com/android/ims/rcs/uce/UceController.java
+++ b/src/java/com/android/ims/rcs/uce/UceController.java
@@ -301,6 +301,16 @@
         mLooper.quit();
     }
 
+    /**
+     * Notify all associated classes that the carrier configuration has changed for the subId.
+     */
+    public void onCarrierConfigChanged() {
+        mEabController.onCarrierConfigChanged();
+        mPublishController.onCarrierConfigChanged();
+        mSubscribeController.onCarrierConfigChanged();
+        mOptionsController.onCarrierConfigChanged();
+    }
+
     /*
      * The implementation of the interface UceControllerCallback. These methods are called by other
      * controllers.
diff --git a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
index aada33b..2c31557 100644
--- a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
+++ b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
@@ -113,6 +113,13 @@
         mEabBulkCapabilityUpdater.onDestroy();
     }
 
+    @Override
+    public void onCarrierConfigChanged() {
+        // Pick up changes to CarrierConfig and run any applicable cleanup tasks associated with
+        // that configuration.
+        mCapabilityCleanupRunnable.run();
+    }
+
     /**
      * Set the callback for sending the request to UceController.
      */
diff --git a/src/java/com/android/ims/rcs/uce/options/OptionsControllerImpl.java b/src/java/com/android/ims/rcs/uce/options/OptionsControllerImpl.java
index 4c5996b..abb8b1d 100644
--- a/src/java/com/android/ims/rcs/uce/options/OptionsControllerImpl.java
+++ b/src/java/com/android/ims/rcs/uce/options/OptionsControllerImpl.java
@@ -63,6 +63,11 @@
     }
 
     @Override
+    public void onCarrierConfigChanged() {
+        // Nothing required here.
+    }
+
+    @Override
     public void sendCapabilitiesRequest(Uri contactUri, @NonNull List<String> deviceFeatureTags,
             IOptionsResponseCallback c) throws RemoteException {
 
diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java
index 1316823..f9dc211 100644
--- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java
+++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java
@@ -51,9 +51,6 @@
 
     private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE);
 
-    // Tracks capability status based on the IMS registration.
-    private final PublishServiceDescTracker mServiceCapRegTracker;
-
     // FT overrides to add to the IMS registration, which will be added to the existing
     // capabilities.
     private final Set<String> mOverrideAddFeatureTags = new ArraySet<>();
@@ -62,6 +59,9 @@
     // capabilities.
     private final Set<String> mOverrideRemoveFeatureTags = new ArraySet<>();
 
+    // Tracks capability status based on the IMS registration.
+    private PublishServiceDescTracker mServiceCapRegTracker;
+
     // The feature tags associated with the last IMS registration update.
     private Set<String> mLastRegistrationFeatureTags = Collections.emptySet();
     // The feature tags associated with the last IMS registration update, which also include
@@ -114,6 +114,20 @@
         mMmTelCapabilities = new MmTelCapabilities();
     }
 
+    /**
+     * Update the capability registration tracker feature tag override mapping.
+     * @return if true, this has caused a change in the Feature Tags associated with the device
+     * and a new PUBLISH should be generated.
+     */
+    public synchronized boolean updateCapabilityRegistrationTrackerMap(String[] newMap) {
+        Set<String> oldTags = mServiceCapRegTracker.copyRegistrationFeatureTags();
+        mServiceCapRegTracker = PublishServiceDescTracker.fromCarrierConfig(newMap);
+        mServiceCapRegTracker.updateImsRegistration(mLastRegistrationOverrideFeatureTags);
+        boolean changed = !oldTags.equals(mServiceCapRegTracker.copyRegistrationFeatureTags());
+        if (changed) logi("Carrier Config Change resulted in associated FT list change");
+        return changed;
+    }
+
     public synchronized boolean isImsRegistered() {
         return mMmtelRegistered;
     }
diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java
index 1ad04c4..1f9cba9 100644
--- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java
+++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java
@@ -75,6 +75,9 @@
     /**The caps have been overridden for a test*/
     int PUBLISH_TRIGGER_OVERRIDE_CAPS = 13;
 
+    /** The Carrier Config for the subscription has Changed **/
+    int PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED = 14;
+
     @IntDef(value = {
             PUBLISH_TRIGGER_SERVICE,
             PUBLISH_TRIGGER_RETRY,
@@ -88,7 +91,8 @@
             PUBLISH_TRIGGER_RCS_REGISTERED,
             PUBLISH_TRIGGER_RCS_UNREGISTERED,
             PUBLISH_TRIGGER_PROVISIONING_CHANGE,
-            PUBLISH_TRIGGER_OVERRIDE_CAPS
+            PUBLISH_TRIGGER_OVERRIDE_CAPS,
+            PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED
     }, prefix="PUBLISH_TRIGGER_")
     @Retention(RetentionPolicy.SOURCE)
     @interface PublishTriggerType {}
diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java
index 9b73815..3776d42 100644
--- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java
+++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java
@@ -163,12 +163,7 @@
 
         mPublishHandler = new PublishHandler(this, looper);
 
-        CarrierConfigManager manager = mContext.getSystemService(CarrierConfigManager.class);
-        PersistableBundle bundle = manager != null ? manager.getConfigForSubId(mSubId) :
-                CarrierConfigManager.getDefaultConfig();
-        String[] serviceDescFeatureTagMap = bundle.getStringArray(
-                CarrierConfigManager.Ims.
-                        KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY);
+        String[] serviceDescFeatureTagMap = getCarrierServiceDescriptionFeatureTagMap();
         mDeviceCapabilityInfo = new DeviceCapabilityInfo(mSubId, serviceDescFeatureTagMap);
 
         initPublishProcessor();
@@ -201,6 +196,7 @@
     public void onRcsDisconnected() {
         logd("onRcsDisconnected");
         mRcsFeatureManager = null;
+        onUnpublish();
         mDeviceCapabilityInfo.updatePresenceCapable(false);
         mDeviceCapListener.onRcsDisconnected();
         mPublishProcessor.onRcsDisconnected();
@@ -221,6 +217,15 @@
     }
 
     @Override
+    public void onCarrierConfigChanged() {
+        String[] newMap = getCarrierServiceDescriptionFeatureTagMap();
+        if (mDeviceCapabilityInfo.updateCapabilityRegistrationTrackerMap(newMap)) {
+            mPublishHandler.requestPublish(
+                    PublishController.PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED);
+        }
+    }
+
+    @Override
     public int getUcePublishState() {
         synchronized (mPublishStateLock) {
             return (!mIsDestroyedFlag) ? mPublishState : RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
@@ -291,6 +296,14 @@
         }
     }
 
+    private String[] getCarrierServiceDescriptionFeatureTagMap() {
+        CarrierConfigManager manager = mContext.getSystemService(CarrierConfigManager.class);
+        PersistableBundle bundle = manager != null ? manager.getConfigForSubId(mSubId) :
+                CarrierConfigManager.getDefaultConfig();
+        return bundle.getStringArray(CarrierConfigManager.Ims.
+                KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY);
+    }
+
     // Clear all the publish state callbacks since the publish controller instance is destroyed.
     private void clearPublishStateCallbacks() {
         synchronized (mPublishStateLock) {
diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java
index c1cbf4e..8bc9b66 100644
--- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java
+++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java
@@ -91,6 +91,7 @@
         mLocalLog.log("onRcsDisconnected");
         logi("onRcsDisconnected");
         mRcsFeatureManager = null;
+        mProcessorState.onRcsDisconnected();
     }
 
     /**
diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java
index 0d43530..40d901f 100644
--- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java
+++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java
@@ -95,6 +95,9 @@
         // for the next publish allowed time.
         private int mRetryCount;
 
+        // The subscription ID associated with this throttle helper.
+        private int mSubId;
+
         // The time when the last PUBLISH request is success. It is one of the calculation
         // conditions for the next publish allowed time.
         private Optional<Instant> mLastPublishedTime;
@@ -103,10 +106,8 @@
         private Optional<Instant> mPublishAllowedTime;
 
         public PublishThrottle(int subId) {
-            mLastPublishedTime = Optional.empty();
-            mPublishAllowedTime = Optional.empty();
-            mRcsPublishThrottle = UceUtils.getRcsPublishThrottle(subId);
-            Log.d(LOG_TAG, "RcsPublishThrottle=" + mRcsPublishThrottle);
+            mSubId = subId;
+            resetState();
         }
 
         // Set the time of the last successful PUBLISH request.
@@ -130,6 +131,15 @@
             calcLatestPublishAllowedTime();
         }
 
+        // In the case that the ImsService is disconnected, reset state for when the service
+        // reconnects
+        public void resetState() {
+            mLastPublishedTime = Optional.empty();
+            mPublishAllowedTime = Optional.empty();
+            mRcsPublishThrottle = UceUtils.getRcsPublishThrottle(mSubId);
+            Log.d(LOG_TAG, "RcsPublishThrottle=" + mRcsPublishThrottle);
+        }
+
         // Check if it has reached the maximum retries.
         public boolean isReachMaximumRetries() {
             return (mRetryCount >= PUBLISH_MAXIMUM_NUM_RETRIES) ? true : false;
@@ -378,4 +388,12 @@
             mPublishThrottle.updatePublishThrottle(publishThrottle);
         }
     }
+
+    public void onRcsDisconnected() {
+        synchronized (mLock) {
+            setPublishingFlag(false /*isPublishing*/);
+            clearPendingRequest();
+            mPublishThrottle.resetState();
+        }
+    }
 }
diff --git a/src/java/com/android/ims/rcs/uce/presence/subscribe/SubscribeControllerImpl.java b/src/java/com/android/ims/rcs/uce/presence/subscribe/SubscribeControllerImpl.java
index f87e830..be4bd74 100644
--- a/src/java/com/android/ims/rcs/uce/presence/subscribe/SubscribeControllerImpl.java
+++ b/src/java/com/android/ims/rcs/uce/presence/subscribe/SubscribeControllerImpl.java
@@ -61,6 +61,11 @@
     }
 
     @Override
+    public void onCarrierConfigChanged() {
+        // Nothing Required Here.
+    }
+
+    @Override
     public void requestCapabilities(List<Uri> contactUris, ISubscribeResponseCallback c)
             throws RemoteException {