Make CDMA Call Options UT aware

Introduce the ability for CDMA call options to detect when SS
over UT becomes available or unavailable and integrate the SS
over CDMA fallback carrier config for situations where SS over
UT becomes unavailable.

1) In the case where SS over CDMA is configured, never disable the
supp service settings, because there will always be an avenue to
set the settings.
2) In the  case where SS over UT is available, but SS over CDMA is
not, take into account the availability of SS over UT when the
settings are loaded and enable/disable the preference based on that
state. If the device moves from SS over UT capable -> unavailable
during this time, the setting will be disabled. If it happens while
a pending request is already being serviced, the framework will
throw an exception causing the UX to handle this and show an error
as well as gray out the Preference.
3) in the case that neither SS over CDMA or UT is available, just
gray out the settings that require either one be available.

Bug: 191057045
Test: manual
Change-Id: Ie03cce86da911571f3b3b6c3563a2882861818d2
diff --git a/src/com/android/phone/CdmaCallOptions.java b/src/com/android/phone/CdmaCallOptions.java
index 40e3517..6145870 100644
--- a/src/com/android/phone/CdmaCallOptions.java
+++ b/src/com/android/phone/CdmaCallOptions.java
@@ -21,18 +21,37 @@
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.feature.MmTelFeature;
+import android.util.Log;
 import android.view.MenuItem;
 
 import com.android.internal.telephony.PhoneConstants;
 
 public class CdmaCallOptions extends TimeConsumingPreferenceActivity {
     private static final String LOG_TAG = "CdmaCallOptions";
-    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String BUTTON_VP_KEY = "button_voice_privacy_key";
     private static final String CALL_FORWARDING_KEY = "call_forwarding_key";
     private static final String CALL_WAITING_KEY = "call_waiting_key";
 
+    private class UtCallback extends ImsMmTelManager.CapabilityCallback {
+        @Override
+        public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) {
+            boolean isUtAvailable = capabilities.isCapable(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT);
+            updatePreferencesEnabled(isUtAvailable);
+        }
+    }
+
+    private Preference mCallForwardingPref;
+    private CdmaCallWaitingPreference mCallWaitingPref;
+    private UtCallback mUtCallback;
+    private ImsMmTelManager mMmTelManager;
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -47,33 +66,107 @@
                 (CdmaVoicePrivacySwitchPreference) findPreference(BUTTON_VP_KEY);
         buttonVoicePrivacy.setPhone(subInfoHelper.getPhone());
         PersistableBundle carrierConfig;
+        int subId;
         if (subInfoHelper.hasSubId()) {
-            carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
-                    subInfoHelper.getSubId());
+            subId = subInfoHelper.getSubId();
         } else {
-            carrierConfig = PhoneGlobals.getInstance().getCarrierConfig();
+            subId = SubscriptionManager.getDefaultSubscriptionId();
         }
+        carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(subId);
         if (subInfoHelper.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
                 || carrierConfig.getBoolean(CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) {
             buttonVoicePrivacy.setEnabled(false);
         }
 
-        Preference callForwardingPref = getPreferenceScreen().findPreference(CALL_FORWARDING_KEY);
+        mCallForwardingPref = getPreferenceScreen().findPreference(CALL_FORWARDING_KEY);
         if (carrierConfig != null && carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_CALL_FORWARDING_VISIBILITY_BOOL)) {
-            callForwardingPref.setIntent(
+            mCallForwardingPref.setIntent(
                     subInfoHelper.getIntent(CdmaCallForwardOptions.class));
         } else {
-            getPreferenceScreen().removePreference(callForwardingPref);
+            getPreferenceScreen().removePreference(mCallForwardingPref);
+            mCallForwardingPref = null;
         }
 
-        CdmaCallWaitingPreference callWaitingPref = (CdmaCallWaitingPreference)getPreferenceScreen()
-                                                     .findPreference(CALL_WAITING_KEY);
-        if (carrierConfig != null && carrierConfig.getBoolean(
+        mCallWaitingPref = (CdmaCallWaitingPreference) getPreferenceScreen()
+                .findPreference(CALL_WAITING_KEY);
+        if (carrierConfig == null || !carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL)) {
-            callWaitingPref.init(this, subInfoHelper.getPhone());
+            getPreferenceScreen().removePreference(mCallWaitingPref);
+            mCallWaitingPref = null;
+        }
+        // Do not go further if the preferences are removed.
+        if (mCallForwardingPref == null && mCallWaitingPref == null) return;
+
+        boolean isSsOverCdmaEnabled = carrierConfig != null && carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_SUPPORT_SS_OVER_CDMA_BOOL);
+        boolean isSsOverUtEnabled = carrierConfig != null && carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL);
+
+        if (isSsOverCdmaEnabled && mCallWaitingPref != null) {
+            // If SS over CDMA is enabled, then the preference will always be enabled,
+            // independent of SS over UT status. Initialize it now.
+            mCallWaitingPref.init(this, subInfoHelper.getPhone());
+            return;
+        }
+        // Since SS over UT availability can change, first disable the preferences that rely on it
+        // and only enable it if UT is available.
+        updatePreferencesEnabled(false);
+        if (isSsOverUtEnabled) {
+            // Register a callback to listen to SS over UT state. This will enable the preferences
+            // once the callback notifies settings that UT is enabled.
+            registerMmTelCapsCallback(subId);
         } else {
-            getPreferenceScreen().removePreference(callWaitingPref);
+            Log.w(LOG_TAG, "SS over UT and CDMA disabled, but preferences are visible.");
+        }
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        unregisterMmTelCapsCallback();
+    }
+
+    private void unregisterMmTelCapsCallback() {
+        if (mMmTelManager == null || mUtCallback == null) return;
+        mMmTelManager.unregisterMmTelCapabilityCallback(mUtCallback);
+        mUtCallback = null;
+        Log.d(LOG_TAG, "unregisterMmTelCapsCallback: UT availability callback unregistered");
+    }
+
+    private void registerMmTelCapsCallback(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) return;
+        ImsManager imsManager = getSystemService(ImsManager.class);
+        try {
+            if (imsManager != null) {
+                mUtCallback = new UtCallback();
+                mMmTelManager = imsManager.getImsMmTelManager(subId);
+                // Callback will call back with the state as soon as it is available.
+                mMmTelManager.registerMmTelCapabilityCallback(getMainExecutor(), mUtCallback);
+                Log.d(LOG_TAG, "registerMmTelCapsCallback: UT availability callback "
+                        + "registered");
+            } else {
+                Log.w(LOG_TAG, "registerMmTelCapsCallback: couldn't get ImsManager, assuming "
+                        + "UT is not available: ");
+                updatePreferencesEnabled(false);
+            }
+        } catch (IllegalArgumentException | ImsException e) {
+            Log.w(LOG_TAG, "registerMmTelCapsCallback: couldn't register callback, assuming "
+                    + "UT is not available: " + e);
+            updatePreferencesEnabled(false);
+        }
+    }
+
+    private void updatePreferencesEnabled(boolean isEnabled) {
+        Log.d(LOG_TAG, "updatePreferencesEnabled: " + isEnabled);
+        if (mCallForwardingPref != null) mCallForwardingPref.setEnabled(isEnabled);
+
+        if (mCallWaitingPref == null || mCallWaitingPref.isEnabled() == isEnabled) return;
+        mCallWaitingPref.setActionAvailable(isEnabled);
+        if (isEnabled) {
+            SubscriptionInfoHelper subInfoHelper = new SubscriptionInfoHelper(this, getIntent());
+            // kick off the normal process to populate the Call Waiting status.
+            mCallWaitingPref.init(this, subInfoHelper.getPhone());
         }
     }
 
diff --git a/src/com/android/phone/CdmaCallWaitingPreference.java b/src/com/android/phone/CdmaCallWaitingPreference.java
index 4cda7ba..3713b19 100644
--- a/src/com/android/phone/CdmaCallWaitingPreference.java
+++ b/src/com/android/phone/CdmaCallWaitingPreference.java
@@ -16,32 +16,29 @@
 
 package com.android.phone;
 
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.Phone;
-
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.TypedArray;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.preference.Preference;
-import android.preference.PreferenceActivity;
 import android.util.AttributeSet;
 import android.util.Log;
 
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+
 public class CdmaCallWaitingPreference extends Preference {
     private static final String LOG_TAG = "CdmaCallWaitingPreference";
     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
-    private int mButtonClicked;
     private Context mContext;
     private Phone mPhone;
-    private SubscriptionInfoHelper mSubscriptionInfoHelper;
     private TimeConsumingPreferenceListener mTcpListener;
     private MyHandler mHandler = new MyHandler();
+    private boolean mIsActionAvailable = true;
 
     public CdmaCallWaitingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -67,6 +64,16 @@
         }
     }
 
+    /**
+     * Enables this preference if Call waiting is available in the platform. If not, this will
+     * override all attempts to enable the preference from the associated
+     * TimeConsumingPreferenceActivity.
+     */
+    public void setActionAvailable(boolean isAvailable) {
+        mIsActionAvailable = isAvailable;
+        super.setEnabled(mIsActionAvailable);
+    }
+
     @Override
     public void onClick() {
         super.onClick();
@@ -95,6 +102,14 @@
         builder.create().show();
     }
 
+    @Override
+    public void setEnabled(boolean enabled) {
+        // If this action is currently disabled due to configuration changes, do not allow anything
+        // to enable it.
+        if (!mIsActionAvailable) return;
+        super.setEnabled(enabled);
+    }
+
     private class MyHandler extends Handler {
         static final int MESSAGE_GET_CALL_WAITING = 0;
         static final int MESSAGE_SET_CALL_WAITING = 1;