Integrate MMTel API into the framework

1) Futher integration of the ImsSerice
Test App for verification.

2) Changes some classes to integrate with the
new ImsService API.

3) Adds enable/DisableIms API and some more
misc. piping into telephony from
TelephonyManager.

Bug: 63987047
Test: Run ImsService Test App
Merged-In: Id34823fcaa9975968e2fd223f53f756a46da24bd
Change-Id: Id34823fcaa9975968e2fd223f53f756a46da24bd
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index a3b0892..5a228a8 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -349,7 +349,7 @@
         }
 
         try {
-            if (mImsMgr.getImsServiceStatus() != ImsFeature.STATE_READY) {
+            if (mImsMgr.getImsServiceState() != ImsFeature.STATE_READY) {
                 log("Feature state not ready so remove vt and wfc settings for "
                         + " phone =" + mPhone.getPhoneId());
                 prefSet.removePreference(wifiCallingSettings);
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index c061fbc..96309ad 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -1671,7 +1671,7 @@
 
             try {
                 if ((mImsMgr == null
-                        || mImsMgr.getImsServiceStatus() != ImsFeature.STATE_READY
+                        || mImsMgr.getImsServiceState() != ImsFeature.STATE_READY
                         || !mImsMgr.isVolteEnabledByPlatform()
                         || !mImsMgr.isVolteProvisionedOnDevice()
                         || carrierConfig.getBoolean(
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index e1e4303..4933ed8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -71,6 +71,10 @@
 import android.telephony.UiccSlotInfo;
 import android.telephony.UssdResponse;
 import android.telephony.VisualVoicemailSmsFilterSettings;
+import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IImsMmTelFeature;
+import android.telephony.ims.aidl.IImsRcsFeature;
+import android.telephony.ims.aidl.IImsRegistration;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -78,9 +82,6 @@
 import android.util.Slog;
 
 import com.android.ims.ImsManager;
-import com.android.ims.internal.IImsMMTelFeature;
-import com.android.ims.internal.IImsRcsFeature;
-import com.android.ims.internal.IImsRegistration;
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
@@ -2622,26 +2623,32 @@
     }
 
     /**
-     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id for the MMTel
-     * feature or {@link null} if the service is not available. If the feature is available, the
-     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
+     * Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability
+     * status updates, if not already enabled.
      */
-    public IImsMMTelFeature getMMTelFeatureAndListen(int slotId,
-            IImsServiceFeatureCallback callback) {
+    public void enableIms(int slotId) {
         enforceModifyPermission();
-        return PhoneFactory.getImsResolver().getMMTelFeatureAndListen(slotId, callback);
+        PhoneFactory.getImsResolver().enableIms(slotId);
     }
 
     /**
-     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id for the MMTel
-     * feature during emergency calling or {@link null} if the service is not available. If the
-     * feature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
-     * listener for feature updates.
+     * Disables IMS for the framework. This will trigger IMS de-registration and trigger ImsFeature
+     * status updates to disabled.
      */
-    public IImsMMTelFeature getEmergencyMMTelFeatureAndListen(int slotId,
+    public void disableIms(int slotId) {
+        enforceModifyPermission();
+        PhoneFactory.getImsResolver().disableIms(slotId);
+    }
+
+    /**
+     * Returns the {@link IImsMmTelFeature} that corresponds to the given slot Id for the MMTel
+     * feature or {@link null} if the service is not available. If the feature is available, the
+     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
+     */
+    public IImsMmTelFeature getMmTelFeatureAndListen(int slotId,
             IImsServiceFeatureCallback callback) {
         enforceModifyPermission();
-        return PhoneFactory.getImsResolver().getEmergencyMMTelFeatureAndListen(slotId, callback);
+        return PhoneFactory.getImsResolver().getMmTelFeatureAndListen(slotId, callback);
     }
 
     /**
@@ -2664,6 +2671,15 @@
         return PhoneFactory.getImsResolver().getImsRegistration(slotId, feature);
     }
 
+    /**
+     * Returns the {@link IImsConfig} structure associated with the slotId and feature
+     * specified.
+     */
+    public IImsConfig getImsConfig(int slotId, int feature) throws RemoteException {
+        enforceModifyPermission();
+        return PhoneFactory.getImsResolver().getImsConfig(slotId, feature);
+    }
+
     public void setImsRegistrationState(boolean registered) {
         enforceModifyPermission();
         mPhone.setImsRegistrationState(registered);
diff --git a/testapps/ImsTestService/Android.mk b/testapps/ImsTestService/Android.mk
index 6f73238..6afb3d5 100644
--- a/testapps/ImsTestService/Android.mk
+++ b/testapps/ImsTestService/Android.mk
@@ -2,6 +2,8 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := optional
+
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     android-support-v4 \
     android-support-v7-appcompat \
diff --git a/testapps/ImsTestService/AndroidManifest.xml b/testapps/ImsTestService/AndroidManifest.xml
index a0172eb..4d81ffd 100644
--- a/testapps/ImsTestService/AndroidManifest.xml
+++ b/testapps/ImsTestService/AndroidManifest.xml
@@ -33,6 +33,7 @@
 
         <activity android:name=".ImsRegistrationActivity" android:label="IMS Registration" />
         <activity android:name=".ImsCallingActivity" android:label="IMS Calling" />
+        <activity android:name=".ImsConfigActivity" android:label="IMS Config" />
 
         <service android:name=".TestImsService"
                  android:exported="true"
diff --git a/testapps/ImsTestService/res/layout/activity_calling.xml b/testapps/ImsTestService/res/layout/activity_calling.xml
index 968dcf1..c1d6993 100644
--- a/testapps/ImsTestService/res/layout/activity_calling.xml
+++ b/testapps/ImsTestService/res/layout/activity_calling.xml
@@ -57,4 +57,21 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/calling_cap_change_button" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?android:attr/listDivider"
+        android:paddingRight="4dp"/>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" android:text="@string/calling_cap_enabled_text"
+        android:textStyle="bold"/>
+    <TextView
+        android:id="@+id/call_cap_enabled_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" android:text=""/>
+
+
 </LinearLayout>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/layout/activity_config.xml b/testapps/ImsTestService/res/layout/activity_config.xml
new file mode 100644
index 0000000..636bc2d
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_config.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingLeft="4dp">
+
+    <TextView
+        android:id="@+id/textView2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="bold"
+        android:text="Set Configuration Value"/>
+
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingLeft="4dp">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_weight="0"
+            android:text="Item"/>
+
+        <EditText
+            android:id="@+id/set_config_item"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:inputType="number" android:text="0"/>
+    </LinearLayout>
+
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingLeft="4dp">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_weight="0"
+            android:text="Value"/>
+
+        <EditText
+            android:id="@+id/set_config_value"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:inputType="number" android:text="0"/>
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/config_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="Set"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height= "1dp"
+        android:paddingRight="4dp"
+        android:background="?android:attr/listDivider" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="bold"
+        android:text="Cached Config Values"/>
+
+    <ListView
+        android:id="@+id/config_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/layout/activity_main.xml b/testapps/ImsTestService/res/layout/activity_main.xml
index 35c6ae2..a45bd40 100644
--- a/testapps/ImsTestService/res/layout/activity_main.xml
+++ b/testapps/ImsTestService/res/layout/activity_main.xml
@@ -81,6 +81,12 @@
                 android:layout_height="wrap_content"
                 android:paddingRight="4dp"
                 android:text="Calling"/>
+            <Button
+                android:id="@+id/control_launch_config"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingRight="4dp"
+                android:text="Config"/>
         </LinearLayout>
     </LinearLayout>
 
diff --git a/testapps/ImsTestService/res/layout/config_item.xml b/testapps/ImsTestService/res/layout/config_item.xml
new file mode 100644
index 0000000..796a741
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/config_item.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/configItem"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1" android:text="Item" android:textAlignment="viewStart"/>
+
+    <TextView
+        android:id="@+id/configValue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1" android:text="Value"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/values/donottranslate_strings.xml b/testapps/ImsTestService/res/values/donottranslate_strings.xml
index e6db1b8..68da69e 100644
--- a/testapps/ImsTestService/res/values/donottranslate_strings.xml
+++ b/testapps/ImsTestService/res/values/donottranslate_strings.xml
@@ -36,5 +36,6 @@
     <string name="calling_cap_video">Video</string>
     <string name="calling_cap_ut">UT</string>
     <string name="calling_cap_sms">SMS</string>
-    <string name="calling_cap_change_button">Change Capabilities</string>
+    <string name="calling_cap_change_button">Change Capability Status</string>
+    <string name="calling_cap_enabled_text">Enabled Capabilities</string>
 </resources>
\ No newline at end of file
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
index d8d56fd..48944e4 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -18,9 +18,12 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.telephony.ims.internal.feature.MmTelFeature;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.SparseArray;
 import android.widget.Button;
 import android.widget.CheckBox;
+import android.widget.TextView;
 import android.widget.Toast;
 
 public class ImsCallingActivity extends Activity {
@@ -31,20 +34,50 @@
     private CheckBox mCapUtAvailBox;
     private CheckBox mCapSmsAvailBox;
 
+    private TextView mCapEnabledText;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.activity_calling);
 
-        TestMmTelFeatureImpl.getInstance().setContext(this);
+        TestMmTelFeatureImpl.getInstance().initialize(this, 0);
 
         mCapVoiceAvailBox = findViewById(R.id.call_cap_voice);
         mCapVideoAvailBox = findViewById(R.id.call_cap_video);
         mCapUtAvailBox = findViewById(R.id.call_cap_ut);
         mCapSmsAvailBox = findViewById(R.id.call_cap_sms);
+        mCapEnabledText = findViewById(R.id.call_cap_enabled_text);
         Button capChangedButton = findViewById(R.id.call_cap_change);
         capChangedButton.setOnClickListener((v) -> onCapabilitiesChangedClicked());
+
+        TestMmTelFeatureImpl.getInstance().addUpdateCallback(
+                new TestMmTelFeatureImpl.MmTelUpdateCallback() {
+                    @Override
+                    void onEnabledCapabilityChanged() {
+                        mmTelCapabilityChanged();
+                    }
+                });
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mmTelCapabilityChanged();
+    }
+
+    private void mmTelCapabilityChanged() {
+        SparseArray<MmTelFeature.MmTelCapabilities> caps =
+                TestMmTelFeatureImpl.getInstance().getEnabledCapabilities();
+        StringBuilder sb = new StringBuilder("LTE: ");
+        sb.append("{");
+        sb.append(caps.get(ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+        sb.append("}, \nIWLAN: ");
+        sb.append("{");
+        sb.append(caps.get(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN));
+        sb.append("}");
+        mCapEnabledText.setText(sb.toString());
     }
 
     private void onCapabilitiesChangedClicked() {
@@ -72,7 +105,8 @@
 
     private boolean isFrameworkConnected() {
         if (!TestMmTelFeatureImpl.getInstance().isReady()) {
-            Toast.makeText(this, "Connection to Framework Unavailable", Toast.LENGTH_SHORT).show();
+            Toast.makeText(this, "Connection to Framework Unavailable",
+                    Toast.LENGTH_SHORT).show();
             return false;
         }
         return true;
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsConfigActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsConfigActivity.java
new file mode 100644
index 0000000..1f8e1c3
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsConfigActivity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.imstestapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+public class ImsConfigActivity extends Activity {
+
+    private static final String PREFIX_ITEM = "Item: ";
+    private static final String PREFIX_VALUE = "Value: ";
+
+    public static class ConfigItemAdapter extends ArrayAdapter<TestImsConfigImpl.ConfigItem> {
+        public ConfigItemAdapter(Context context, ArrayList<TestImsConfigImpl.ConfigItem> configs) {
+            super(context, 0, configs);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TestImsConfigImpl.ConfigItem configItem = getItem(position);
+
+            if (convertView == null) {
+                convertView = LayoutInflater.from(getContext()).inflate(R.layout.config_item,
+                        parent, false);
+            }
+
+            TextView textItem = (TextView) convertView.findViewById(R.id.configItem);
+            TextView textValue = (TextView) convertView.findViewById(R.id.configValue);
+
+            textItem.setText(PREFIX_ITEM + configItem.item);
+            if (configItem.valueString != null) {
+                textValue.setText(PREFIX_VALUE + configItem.valueString);
+            } else {
+                textValue.setText(PREFIX_VALUE + configItem.value);
+            }
+
+            return convertView;
+        }
+    }
+
+    private final TestImsConfigImpl.ImsConfigListener mConfigListener =
+            new TestImsConfigImpl.ImsConfigListener() {
+                @Override
+                public void notifyConfigChanged() {
+                    Log.i("ImsConfigActivity", "notifyConfigChanged");
+                    mConfigItemAdapter.notifyDataSetChanged();
+                }
+            };
+
+    ConfigItemAdapter mConfigItemAdapter;
+    ListView mListView;
+
+    EditText mConfigItemText;
+    EditText mConfigValueText;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_config);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        mConfigItemAdapter = new ConfigItemAdapter(this,
+                TestImsConfigImpl.getInstance().getConfigList());
+
+        mListView = (ListView) findViewById(R.id.config_list);
+        mListView.setAdapter(mConfigItemAdapter);
+
+        TestImsConfigImpl.getInstance().setConfigListener(mConfigListener);
+
+        Button setConfigButton = findViewById(R.id.config_button);
+        setConfigButton.setOnClickListener((v) -> onSetConfigClicked());
+
+        mConfigItemText = findViewById(R.id.set_config_item);
+        mConfigValueText = findViewById(R.id.set_config_value);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        TestImsConfigImpl.getInstance().setConfigListener(null);
+    }
+
+    private void onSetConfigClicked() {
+        String configItem = mConfigItemText.getText().toString();
+        String configValue = mConfigValueText.getText().toString();
+        TestImsConfigImpl.getInstance().setConfigValue(Integer.parseInt(configItem),
+                Integer.parseInt(configValue));
+    }
+}
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
index 89c50e9..6b78a30 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
@@ -42,6 +42,9 @@
         ((Button) findViewById(R.id.control_launch_calling)).setOnClickListener(
                 (view) -> launchCallingActivity());
 
+        ((Button) findViewById(R.id.control_launch_config)).setOnClickListener(
+                (view) -> launchConfigActivity());
+
         // Adds Card view for testing
         mConnections = findViewById(R.id.connections_list);
         mConnections.addView(getLayoutInflater().inflate(R.layout.ims_connection, null, false));
@@ -56,4 +59,9 @@
         Intent intent = new Intent(this, ImsCallingActivity.class);
         startActivity(intent);
     }
+
+    private void launchConfigActivity() {
+        Intent intent = new Intent(this, ImsConfigActivity.class);
+        startActivity(intent);
+    }
 }
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java
index 0010af4..4b8842a 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java
@@ -16,45 +16,91 @@
 
 package com.android.phone.testapps.imstestapp;
 
-import android.os.RemoteException;
 import android.telephony.ims.stub.ImsConfigImplBase;
 
 import com.android.ims.ImsConfig;
-import com.android.ims.ImsConfigListener;
+
+import java.util.ArrayList;
 
 public class TestImsConfigImpl extends ImsConfigImplBase {
 
+    public static class ConfigItem {
+        public int item;
+        public int value;
+        public String valueString;
+
+        public ConfigItem(int item, int value) {
+            this.item = item;
+            this.value = value;
+        }
+
+        public ConfigItem(int item, String value) {
+            this.item = item;
+            valueString = value;
+        }
+    }
+
+    public interface ImsConfigListener {
+        void notifyConfigChanged();
+    }
+
+    private static TestImsConfigImpl sTestImsConfigImpl;
+    private ImsConfigListener mListener;
+    private ArrayList<ConfigItem> mArrayOfConfigs = new ArrayList<>();
+
+    public static TestImsConfigImpl getInstance() {
+        if (sTestImsConfigImpl == null) {
+            sTestImsConfigImpl = new TestImsConfigImpl();
+        }
+        return sTestImsConfigImpl;
+    }
+
+    public void setConfigListener(ImsConfigListener listener) {
+        mListener = listener;
+    }
+
+    public ArrayList<ConfigItem> getConfigList() {
+        return mArrayOfConfigs;
+    }
+
     @Override
-    public int getProvisionedValue(int item) throws RemoteException {
+    public int setConfig(int item, int value) {
+        replaceConfig(new ConfigItem(item, value));
+        return ImsConfig.OperationStatusConstants.SUCCESS;
+    }
+
+    @Override
+    public int setConfig(int item, String value) {
+        replaceConfig(new ConfigItem(item, value));
+        return ImsConfig.OperationStatusConstants.SUCCESS;
+    }
+
+    @Override
+    public int getConfigInt(int item) {
+        replaceConfig(new ConfigItem(item, ImsConfig.FeatureValueConstants.ON));
         return ImsConfig.FeatureValueConstants.ON;
     }
 
     @Override
-    public String getProvisionedStringValue(int item) throws RemoteException {
+    public String getConfigString(int item) {
         return null;
     }
 
-    @Override
-    public int setProvisionedValue(int item, int value) throws RemoteException {
-        return ImsConfig.OperationStatusConstants.SUCCESS;
+    public void setConfigValue(int item, int value) {
+        replaceConfig(new ConfigItem(item, value));
+        notifyProvisionedValueChanged(item, value);
     }
 
-    @Override
-    public int setProvisionedStringValue(int item, String value) throws RemoteException {
-        return ImsConfig.OperationStatusConstants.SUCCESS;
-    }
-
-    @Override
-    public void getFeatureValue(int feature, int network, ImsConfigListener listener)
-            throws RemoteException {
-        listener.onGetFeatureResponse(feature, network, ImsConfig.FeatureValueConstants.ON,
-                ImsConfig.OperationStatusConstants.SUCCESS);
-    }
-
-    @Override
-    public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
-            throws RemoteException {
-        listener.onSetFeatureResponse(feature, network, value,
-                ImsConfig.OperationStatusConstants.SUCCESS);
+    public void replaceConfig(ConfigItem configItem) {
+        ConfigItem config = mArrayOfConfigs.stream()
+                .filter(configElem -> configElem.item == configItem.item)
+                .findFirst().orElse(null);
+        if (config != null) {
+            mArrayOfConfigs.remove(config);
+        }
+        mArrayOfConfigs.add(configItem);
+        if (mListener != null) {
+            mListener.notifyConfigChanged();
+        }
     }
 }
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
index 71357bd..434cdb5 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
@@ -17,8 +17,9 @@
 package com.android.phone.testapps.imstestapp;
 
 import android.telephony.ims.ImsService;
-import android.telephony.ims.feature.MMTelFeature;
+import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
@@ -35,6 +36,7 @@
     public TestImsRegistrationImpl mImsRegistration;
     public TestMmTelFeatureImpl mTestMmTelFeature;
     public TestRcsFeatureImpl mTestRcsFeature;
+    public TestImsConfigImpl mTestImsConfig;
 
     public static TestImsService getInstance() {
         return mInstance;
@@ -46,24 +48,19 @@
         mImsRegistration = TestImsRegistrationImpl.getInstance();
         mTestMmTelFeature = TestMmTelFeatureImpl.getInstance();
         mTestRcsFeature = new TestRcsFeatureImpl();
+        mTestImsConfig = TestImsConfigImpl.getInstance();
 
         mInstance = this;
     }
 
     @Override
-    public MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
+    public MmTelFeature createMmTelFeature(int slotId) {
         Log.i(LOG_TAG, "TestImsService: onCreateEmergencyMMTelImsFeature");
         return mTestMmTelFeature;
     }
 
     @Override
-    public MMTelFeature onCreateMMTelImsFeature(int slotId) {
-        Log.i(LOG_TAG, "TestImsService: onCreateMMTelImsFeature");
-        return mTestMmTelFeature;
-    }
-
-    @Override
-    public RcsFeature onCreateRcsFeature(int slotId) {
+    public RcsFeature createRcsFeature(int slotId) {
         return mTestRcsFeature;
     }
 
@@ -72,4 +69,9 @@
         Log.i(LOG_TAG, "TestImsService: getRegistration");
         return mImsRegistration;
     }
+
+    @Override
+    public ImsConfigImplBase getConfig(int slotId) {
+        return mTestImsConfig;
+    }
 }
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java
index b112485..2a0463d 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java
@@ -16,34 +16,33 @@
 
 package com.android.phone.testapps.imstestapp;
 
-import android.app.PendingIntent;
-import android.os.RemoteException;
-import android.telephony.ims.feature.MMTelFeature;
-import android.telephony.ims.internal.feature.MmTelFeature;
+import android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.util.Log;
+import android.util.ArraySet;
+import android.util.SparseArray;
 import android.widget.Toast;
 
-import com.android.ims.ImsConfig;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsRegistrationListener;
+import java.util.Set;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class TestMmTelFeatureImpl extends MMTelFeature {
-
-    private final String[] mImsFeatureStrings = {"VoLTE", "ViLTE", "VoWiFi", "ViWiFi",
-            "UTLTE", "UTWiFi"};
+public class TestMmTelFeatureImpl extends MmTelFeature {
 
     public static TestMmTelFeatureImpl sTestMmTelFeatureImpl;
     private boolean mIsReady = false;
-    private PendingIntent mIncomingCallIntent;
-    private List<IImsRegistrationListener> mRegistrationListeners = new ArrayList<>();
-    private TestImsConfigImpl mConfig = new TestImsConfigImpl();
+    // Enabled Capabilities - not status
+    private SparseArray<MmTelCapabilities> mEnabledCapabilities = new SparseArray<>();
+    private final Set<MmTelUpdateCallback> mCallbacks = new ArraySet<>();
+
+    static class MmTelUpdateCallback {
+        void onEnabledCapabilityChanged() {
+        }
+    }
 
     public TestMmTelFeatureImpl() {
+        mEnabledCapabilities.append(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+                new MmTelCapabilities());
+        mEnabledCapabilities.append(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                new MmTelCapabilities());
         setFeatureState(STATE_READY);
     }
 
@@ -54,106 +53,45 @@
         return sTestMmTelFeatureImpl;
     }
 
+    public void addUpdateCallback(MmTelUpdateCallback callback) {
+        mCallbacks.add(callback);
+    }
+
     public boolean isReady() {
         return mIsReady;
     }
 
+    @Override
+    public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+        return mEnabledCapabilities.get(radioTech).isCapable(capability);
+    }
+
+    @Override
+    public void changeEnabledCapabilities(CapabilityChangeRequest request,
+            CapabilityCallbackProxy c) {
+        for (CapabilityChangeRequest.CapabilityPair pair : request.getCapabilitiesToEnable()) {
+            mEnabledCapabilities.get(pair.getRadioTech()).addCapabilities(pair.getCapability());
+        }
+        for (CapabilityChangeRequest.CapabilityPair pair : request.getCapabilitiesToDisable()) {
+            mEnabledCapabilities.get(pair.getRadioTech()).removeCapabilities(pair.getCapability());
+        }
+        mCallbacks.forEach(callback->callback.onEnabledCapabilityChanged());
+    }
+
+    @Override
+    public void onFeatureRemoved() {
+        super.onFeatureRemoved();
+    }
+
     public void sendCapabilitiesUpdate(MmTelFeature.MmTelCapabilities c) {
-        // Size of ImsConfig.FeatureConstants
-        int[] enabledCapabilities = new int[6];
-        // Apparently means disabled...?
-        Arrays.fill(enabledCapabilities, ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN);
-        int[] disabledCapabilities = new int[6];
-        Arrays.fill(disabledCapabilities, ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN);
-        int radioTech = TestImsRegistrationImpl.getInstance().getConnectionType();
-        StringBuilder sb = new StringBuilder(120);
-        // populate enabledCapabilities
-        switch (radioTech) {
-            case ImsRegistrationImplBase.REGISTRATION_TECH_LTE: {
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE)) {
-                    // enabled means equal to its own integer value.
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE]);
-                    sb.append(" ");
-                }
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO)) {
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE]);
-                    sb.append(" ");
-                }
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT)) {
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_LTE] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_LTE;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_LTE]);
-                }
-                break;
-            }
-            case ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN: {
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE)) {
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI]);
-                    sb.append(" ");
-                }
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO)) {
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI]);
-                    sb.append(" ");
-                }
-                if (c.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT)) {
-                    enabledCapabilities[ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI] =
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI;
-                    sb.append(mImsFeatureStrings[
-                            ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI]);
-                }
-                break;
-            }
-        }
-        // make disabledCapabilities  the opposite of enabledCapabilities
-        for (int i = 0; i < enabledCapabilities.length; i++) {
-            if (enabledCapabilities[i] != i) {
-                disabledCapabilities[i] = i;
-            }
-        }
-        Toast.makeText(mContext, "Sending Capabilities:{" + sb.toString() + "}",
+        Toast.makeText(mContext, "Sending Capabilities:{" + c + "}",
                 Toast.LENGTH_LONG).show();
-        mRegistrationListeners.forEach((l) -> {
-            try {
-                l.registrationFeatureCapabilityChanged(1 /*ImsServiceClass.MMTel*/,
-                        enabledCapabilities,
-                        disabledCapabilities);
-            } catch (RemoteException e) {
-                // ignore
-            }
-        });
+
+        notifyCapabilitiesStatusChanged(c);
     }
 
-    @Override
-    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
-        Log.i(TestImsService.LOG_TAG,
-                "startSession Called: pi=" + incomingCallIntent + " listener: " + listener);
-        mIncomingCallIntent = incomingCallIntent;
-        mRegistrationListeners.add(listener);
-        return super.startSession(incomingCallIntent, listener);
-    }
-
-    @Override
-    public void addRegistrationListener(IImsRegistrationListener listener) {
-        Log.i(TestImsService.LOG_TAG, "addRegistrationListener: " + listener);
-        mRegistrationListeners.add(listener);
-    }
-
-    @Override
-    public IImsConfig getConfigInterface() {
-        return mConfig;
+    public SparseArray<MmTelCapabilities> getEnabledCapabilities() {
+        return mEnabledCapabilities;
     }
 
     @Override