Update ImsManager to also update UT IMS capability

Include UT IMS capability updates in ImsManager as part
of the capability update flow.

Bug: 119896853
Test: atest FrameworksTelephonyTests
Change-Id: I16569822c892a3e4732b13f53b9dcde6d116794a
diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java
index 3df7771..a5d437e 100644
--- a/src/java/com/android/ims/ImsManager.java
+++ b/src/java/com/android/ims/ImsManager.java
@@ -27,6 +27,7 @@
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.telecom.TelecomManager;
@@ -57,6 +58,7 @@
 import com.android.ims.internal.IImsUt;
 import android.telephony.ims.ImsCallSession;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ITelephony;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -74,7 +76,7 @@
  * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
  * the operator's IMS network. This class is the starting point for any IMS actions.
  * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
- * @deprecated use {@link ImsMmTelManager} instead.
+ * For internal use ONLY! Use {@link ImsMmTelManager} instead.
  * @hide
  */
 public class ImsManager {
@@ -233,7 +235,6 @@
                                     status = mImsManager.getImsServiceState();
                                 }
                             }
-                            log("Status Changed: " + status);
                             switch (status) {
                                 case ImsFeature.STATE_READY: {
                                     notifyReady();
@@ -250,7 +251,6 @@
                                 }
                             }
                         } catch (ImsException e) {
-                            loge("notifyStateChanged(): ", e);
                             // Could not get the ImsService, retry!
                             notifyNotReady();
                             retryGetImsService();
@@ -331,13 +331,11 @@
                 mImsManager = null;
             }
             // Exponential backoff during retry, limited to 32 seconds.
-            loge("Connector: Retrying getting ImsService...");
             removeCallbacks(mGetServiceRunnable);
             postDelayed(mGetServiceRunnable, mRetryTimeout.get());
         }
 
         private void getImsService() throws ImsException {
-            if (DBG) log("Connector: getImsService");
             synchronized (mLock) {
                 mImsManager = ImsManager.getInstance(mContext, mPhoneId);
                 // Adding to set, will be safe adding multiple times. If the ImsService is not
@@ -1257,6 +1255,18 @@
                 isGbaValid();
     }
 
+    public boolean isSuppServicesOverUtEnabledByPlatform() {
+        TelephonyManager manager = (TelephonyManager) mContext.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        int cardState = manager.getSimState(mPhoneId);
+        if (cardState != TelephonyManager.SIM_STATE_READY) {
+            // Do not report enabled until we actually have an active subscription.
+            return false;
+        }
+        return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL) &&
+                isGbaValid();
+    }
+
     /**
      * If carrier requires that IMS is only available if GBA capable SIM is used,
      * then this function checks GBA bit in EF IST.
@@ -1290,7 +1300,19 @@
             throw new ImsException("getProvisionedBool failed with error for item: " + item,
                     ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR);
         }
-        return config.getProvisionedValue(item) == ProvisioningManager.PROVISIONING_VALUE_ENABLED;
+        return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED;
+    }
+
+    /**
+     * Will set config value or throw an ImsException if we receive an error from ImsConfig for that
+     * value.
+     */
+    private void setProvisionedBool(ImsConfig config, int item, int value) throws ImsException {
+        int result = config.setConfig(item, value);
+        if (result != ImsConfigImplBase.CONFIG_RESULT_SUCCESS) {
+            throw new ImsException("setProvisionedBool failed with error for item: " + item,
+                    ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR);
+        }
     }
 
     /**
@@ -1302,11 +1324,29 @@
             ImsConfig config = getConfigInterface();
             return getProvisionedBool(config, item);
         } catch (ImsException ex) {
+            Log.w(TAG, "getProvisionedBoolNoException: operation failed for item=" + item
+                    + ". Exception:" + ex.getMessage() + ". Returning false.");
             return false;
         }
     }
 
     /**
+     * Will return with config value or return false if we receive an error from
+     * ImsConfigImplBase implementation for that value.
+     */
+    private boolean setProvisionedBoolNoException(int item, int value) {
+        try {
+            ImsConfig config = getConfigInterface();
+            setProvisionedBool(config, item, value);
+        } catch (ImsException ex) {
+            Log.w(TAG, "setProvisionedBoolNoException: operation failed for item=" + item
+                    + ", value=" + value + ". Exception:" + ex.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Sync carrier config and user settings with ImsConfigImplBase implementation.
      *
      * @param context for the manager object
@@ -1349,6 +1389,10 @@
                 isImsUsed |= updateVideoCallFeatureValue();
                 isImsUsed |= updateRttConfigValue();
 
+                // Supplementary services over UT do not require IMS registration. Do not alter IMS
+                // registration based on UT.
+                updateUtFeatureValue();
+
                 if (isImsUsed || !isTurnOffImsAllowedByPlatform()) {
                     // Turn on IMS if it is used.
                     // Also, if turning off is not allowed for current carrier,
@@ -1450,6 +1494,53 @@
         return isFeatureOn;
     }
 
+
+    private boolean updateUtFeatureValue() throws ImsException {
+        boolean isCarrierSupported = isSuppServicesOverUtEnabledByPlatform();
+        boolean requiresProvisioning = getBooleanCarrierConfig(
+                CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL);
+        // Count as "provisioned" if we do not require provisioning.
+        boolean isProvisioned = true;
+        if (requiresProvisioning) {
+            ITelephony telephony = ITelephony.Stub.asInterface(
+                    ServiceManager.getService(Context.TELEPHONY_SERVICE));
+            // Only track UT over LTE, since we do not differentiate between UT over LTE and IWLAN
+            // currently.
+            try {
+                if (telephony != null) {
+                    isProvisioned = telephony.isMmTelCapabilityProvisionedInCache(getSubId(),
+                            MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                            ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "updateUtFeatureValue: couldn't reach telephony! returning provisioned");
+            }
+        }
+        CapabilityChangeRequest request = new CapabilityChangeRequest();
+        boolean isFeatureOn = isCarrierSupported && isProvisioned;
+
+        log("updateUtFeatureValue: available = " + isCarrierSupported
+                + ", isProvisioned = " + isProvisioned
+                + ", enabled = " + isFeatureOn);
+
+        if (isFeatureOn) {
+            request.addCapabilitiesToEnableForTech(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        } else {
+            request.addCapabilitiesToDisableForTech(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        }
+        try {
+            mMmTelFeatureConnection.changeEnabledCapabilities(request, null);
+        } catch (RemoteException e) {
+            throw new ImsException("updateUtFeatureValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+        }
+        return isFeatureOn;
+    }
+
     /**
      * Do NOT use this directly, instead use {@link #getInstance(Context, int)}.
      */
@@ -1984,6 +2075,8 @@
                         isEnabled ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
                                 : ProvisioningManager.PROVISIONING_VALUE_DISABLED, -1);
             }
+            Log.i(TAG, "changeMmTelCapability: changing capabilities for sub: " + getSubId()
+                    + ", request: " + request);
         } catch (RemoteException e) {
             throw new ImsException("changeMmTelCapability()", e,
                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
@@ -2224,7 +2317,6 @@
      * 2) android.telephony.ims.ImsService implementation through ImsResolver.
      */
     private void createImsService() {
-        Rlog.i(TAG, "Creating ImsService");
         mMmTelFeatureConnection = MmTelFeatureConnection.create(mContext, mPhoneId);
 
         // Forwarding interface to tell mStatusCallbacks that the Proxy is unavailable.
@@ -2550,6 +2642,27 @@
         updateImsServiceConfig(true);
     }
 
+    public void setVolteProvisioned(boolean isProvisioned) {
+        int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED :
+                ProvisioningManager.PROVISIONING_VALUE_DISABLED;
+        setProvisionedBoolNoException(ImsConfig.ConfigConstants.VLT_SETTING_ENABLED,
+                provisionStatus);
+    }
+
+    public void setWfcProvisioned(boolean isProvisioned) {
+        int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED :
+                ProvisioningManager.PROVISIONING_VALUE_DISABLED;
+        setProvisionedBoolNoException(
+                ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED, provisionStatus);
+    }
+
+    public void setVtProvisioned(boolean isProvisioned) {
+        int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED :
+                ProvisioningManager.PROVISIONING_VALUE_DISABLED;
+        setProvisionedBoolNoException(ImsConfig.ConfigConstants.LVC_SETTING_ENABLED,
+                provisionStatus);
+    }
+
     private boolean isDataEnabled() {
         return new TelephonyManager(mContext, getSubId()).isDataCapable();
     }