Merge changes from topic "ims_apis"

* changes:
  Modify ImsService API namespaces
  Integrate MMTel API into the framework
  Test App for ImsService
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/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index cb9ecbd..ff06005 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -36,10 +36,10 @@
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsCallProfile;
 import android.util.Pair;
 
 import com.android.ims.ImsCall;
-import com.android.ims.ImsCallProfile;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.CallStateException;
diff --git a/testapps/ImsTestService/Android.mk b/testapps/ImsTestService/Android.mk
new file mode 100644
index 0000000..6afb3d5
--- /dev/null
+++ b/testapps/ImsTestService/Android.mk
@@ -0,0 +1,26 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview \
+    android-support-v7-cardview
+
+LOCAL_USE_AAPT2 := true
+
+src_dirs := src
+res_dirs := res
+
+LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
+
+LOCAL_PACKAGE_NAME := ImsTestApp
+
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/testapps/ImsTestService/AndroidManifest.xml b/testapps/ImsTestService/AndroidManifest.xml
new file mode 100644
index 0000000..4d81ffd
--- /dev/null
+++ b/testapps/ImsTestService/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          coreApp="true"
+          package="com.android.phone.testapps.imstestapp">
+    <application
+        android:label="ImsTestService"
+        android:directBootAware="true">
+        <activity
+            android:name=".ImsTestServiceApp"
+            android:label="ImsTestService">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <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"
+                 android:enabled="true"
+                 android:persistent="true"
+                 android:permission="android.permission.BIND_IMS_SERVICE">
+            <meta-data android:name="android.telephony.ims.MMTEL_FEATURE" android:value="true"/>
+            <!--meta-data android:name="android.telephony.ims.EMERGENCY_MMTEL_FEATURE"
+                       android:value="true" /-->
+            <intent-filter>
+                <action android:name="android.telephony.ims.ImsService" />
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
+
diff --git a/testapps/ImsTestService/res/layout/activity_calling.xml b/testapps/ImsTestService/res/layout/activity_calling.xml
new file mode 100644
index 0000000..c1d6993
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_calling.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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">
+
+    <GridLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:columnCount="2" android:rowCount="2">
+
+        <CheckBox
+            android:id="@+id/call_cap_voice"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_column="0"
+            android:layout_gravity="center" android:layout_row="0"
+            android:text="@string/calling_cap_voice"/>
+        <CheckBox
+            android:id="@+id/call_cap_video"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_column="1"
+            android:layout_gravity="center" android:layout_row="0"
+            android:text="@string/calling_cap_video"/>
+        <CheckBox
+            android:id="@+id/call_cap_ut"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_column="0"
+            android:layout_gravity="center" android:layout_row="1"
+            android:text="@string/calling_cap_ut"/>
+        <CheckBox
+            android:id="@+id/call_cap_sms"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_column="1"
+            android:layout_gravity="center" android:layout_row="1"
+            android:text="@string/calling_cap_sms"/>
+    </GridLayout>
+    <Button
+        android:id="@+id/call_cap_change"
+        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
new file mode 100644
index 0000000..a45bd40
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_main.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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="wrap_content"
+    android:orientation="vertical"
+    android:paddingLeft="4dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
+
+        <TextView
+            android:id="@+id/features_main_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/features_main_text"/>
+        <CheckBox
+            android:id="@+id/features_check_mmtel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/features_check_mmtel"/>
+        <CheckBox
+            android:id="@+id/features_check_rcs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/features_check_rcs"/>
+        <Button
+            android:id="@+id/features_change_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/features_change_button"/>
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height= "1dp"
+        android:paddingRight="4dp"
+        android:background="?android:attr/listDivider" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="ImsService Controls"/>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <Button
+                android:id="@+id/control_launch_reg"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingRight="4dp"
+                android:text="Registration"/>
+            <Button
+                android:id="@+id/control_launch_calling"
+                android:layout_width="match_parent"
+                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>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height= "1dp"
+        android:paddingRight="4dp"
+        android:background="?android:attr/listDivider" />
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/connections_list"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/layout/activity_registration.xml b/testapps/ImsTestService/res/layout/activity_registration.xml
new file mode 100644
index 0000000..2e381eb
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_registration.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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="wrap_content"
+    android:orientation="vertical"
+    android:paddingLeft="4dp">
+
+    <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:text="@string/reg_text_reg_tech"/>
+        <Spinner
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/reg_tech_selector"/>
+    </LinearLayout>
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/reg_registered_button"
+        android:id="@+id/reg_registered_button"/>
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/reg_registering_button"
+        android:id="@+id/reg_registering_button"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height= "1dp"
+        android:paddingRight="4dp"
+        android:background="?android:attr/listDivider" />
+
+    <include layout="@layout/construct_imsreasoninfo"
+             android:id="@+id/deregistered_imsreasoninfo" />
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/reg_deregistered_button"
+        android:id="@+id/reg_deregistered_button"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height= "1dp"
+        android:paddingRight="4dp"
+        android:background="?android:attr/listDivider" />
+
+    <include layout="@layout/construct_imsreasoninfo"
+             android:id="@+id/regchangefail_imsreasoninfo" />
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/reg_changefailed_button"
+        android:id="@+id/reg_changefailed_button"/>
+</LinearLayout>
\ No newline at end of file
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/layout/construct_imsreasoninfo.xml b/testapps/ImsTestService/res/layout/construct_imsreasoninfo.xml
new file mode 100644
index 0000000..dd32ca3
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/construct_imsreasoninfo.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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="wrap_content"
+    android:orientation="vertical" >
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/imsreasoninfo_text"/>
+        
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_weight="0"
+            android:maxLines="1" android:minEms="2" android:paddingRight="4dp"
+            android:text="@string/imsreasoninfo_errorcode"/>
+        <EditText
+            android:id="@+id/imsreasoninfo_error"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ems="3"
+            android:inputType="number" android:text="0"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_weight="0"
+            android:autoText="true" android:maxLines="1" android:paddingRight="4dp"
+            android:text="@string/imsreasoninfo_extracode"/>
+        <EditText
+            android:id="@+id/imsreasoninfo_extra"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ems="3"
+            android:inputType="number" android:text="0"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1" android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:layout_weight="0"
+            android:paddingRight="4dp" android:text="@string/imsreasoninfo_message"/>
+        <EditText
+            android:id="@+id/imsreasoninfo_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ems="10"
+            android:inputType="text"/>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/layout/ims_connection.xml b/testapps/ImsTestService/res/layout/ims_connection.xml
new file mode 100644
index 0000000..4c08082
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/ims_connection.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+<android.support.v7.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    android:layout_gravity="center"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:id="@+id/connection_info"
+    card_view:cardCornerRadius="4dp"
+    card_view:cardElevation="4dp"
+    card_view:cardUseCompatPadding="true">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+        <TextView
+            android:id="@+id/reg_main_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" android:text="@string/features_main_text"/>
+        <CheckBox
+            android:id="@+id/reg_check_mmtel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" android:text="@string/features_check_mmtel"/>
+        <CheckBox
+            android:id="@+id/reg_check_rcs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" android:text="@string/features_check_rcs"/>
+        </LinearLayout>
+</android.support.v7.widget.CardView>
\ No newline at end of file
diff --git a/testapps/ImsTestService/res/values/donottranslate_strings.xml b/testapps/ImsTestService/res/values/donottranslate_strings.xml
new file mode 100644
index 0000000..68da69e
--- /dev/null
+++ b/testapps/ImsTestService/res/values/donottranslate_strings.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<resources>
+    <string name="features_main_text">Registration Configuration</string>
+    <string name="features_check_mmtel">MmTel Feature</string>
+    <string name="features_check_rcs">RCS Feature</string>
+    <string name="features_change_button">Change Features</string>
+
+    <string name="reg_text_reg_tech">Registration Technology</string>
+    <string name="reg_registered_button">Send Registered</string>
+    <string name="reg_registering_button">Send Registering</string>
+    <string name="reg_deregistered_button">Send Deregistered Using Reason Above</string>
+    <string name="reg_changefailed_button">Reg Change Failed Using Reason Above</string>
+
+    <string name="imsreasoninfo_text">Construct ImsReasonInfo</string>
+    <string name="imsreasoninfo_errorcode">Error Code</string>
+    <string name="imsreasoninfo_extracode">Extra Code</string>
+    <string name="imsreasoninfo_message">Message</string>
+
+    <string name="calling_cap_voice">Voice</string>
+    <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 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
new file mode 100644
index 0000000..48944e4
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 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.os.Bundle;
+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 {
+
+    //Capabilities available by service
+    private CheckBox mCapVoiceAvailBox;
+    private CheckBox mCapVideoAvailBox;
+    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().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() {
+        if (!isFrameworkConnected()) {
+            return;
+        }
+        boolean isVoiceAvail = mCapVoiceAvailBox.isChecked();
+        boolean isVideoAvail = mCapVideoAvailBox.isChecked();
+        boolean isUtAvail = mCapUtAvailBox.isChecked();
+        // Not used yet
+        boolean isSmsAvail = mCapSmsAvailBox.isChecked();
+
+        MmTelFeature.MmTelCapabilities capabilities = new MmTelFeature.MmTelCapabilities();
+        if (isVoiceAvail) {
+            capabilities.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
+        }
+        if (isVideoAvail) {
+            capabilities.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
+        }
+        if (isUtAvail) {
+            capabilities.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT);
+        }
+        TestMmTelFeatureImpl.getInstance().sendCapabilitiesUpdate(capabilities);
+    }
+
+    private boolean isFrameworkConnected() {
+        if (!TestMmTelFeatureImpl.getInstance().isReady()) {
+            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/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
new file mode 100644
index 0000000..7e27371
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 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.os.Bundle;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArrayMap;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Toast;
+import android.telephony.ims.ImsReasonInfo;
+
+import java.util.Map;
+
+public class ImsRegistrationActivity extends Activity {
+
+    private int mSelectedRegTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+
+    private static final Map<String, Integer> REG_TECH = new ArrayMap<>(2);
+    static {
+        REG_TECH.put("LTE", ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        REG_TECH.put("IWLAN", ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+    }
+
+    private View mDeregisteredReason;
+    private View mRegChangeFailedReason;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_registration);
+
+        //Set up registration tech spinner
+        Spinner regTechDropDown = findViewById(R.id.reg_tech_selector);
+        regTechDropDown.setAdapter(new ArrayAdapter<>(this,
+                android.R.layout.simple_spinner_dropdown_item,
+                REG_TECH.keySet().toArray(new String[REG_TECH.size()])));
+        regTechDropDown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                onTechDropDownChanged((String) parent.getItemAtPosition(position));
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                // Don't change selection
+            }
+        });
+
+        // Map buttons to onClick listeners
+        Button registeredButton = findViewById(R.id.reg_registered_button);
+        registeredButton.setOnClickListener((v)->onRegisteredClicked());
+        Button registeringButton = findViewById(R.id.reg_registering_button);
+        registeringButton.setOnClickListener((v)->onRegisteringClicked());
+        Button deregisteredButton = findViewById(R.id.reg_deregistered_button);
+        deregisteredButton.setOnClickListener((v)->onDeregisteredClicked());
+        Button regChangeFailedButton = findViewById(R.id.reg_changefailed_button);
+        regChangeFailedButton.setOnClickListener((v)->onRegChangeFailedClicked());
+
+        mDeregisteredReason = findViewById(R.id.deregistered_imsreasoninfo);
+        mRegChangeFailedReason = findViewById(R.id.regchangefail_imsreasoninfo);
+    }
+
+    private void onRegisteredClicked() {
+        if (!isFrameworkConnected()) {
+            return;
+        }
+        TestImsRegistrationImpl.getInstance().onRegistered(mSelectedRegTech);
+    }
+
+    private void onRegisteringClicked() {
+        if (!isFrameworkConnected()) {
+            return;
+        }
+        TestImsRegistrationImpl.getInstance().onRegistering(mSelectedRegTech);
+    }
+
+    private void onDeregisteredClicked() {
+        if (!isFrameworkConnected()) {
+            return;
+        }
+        TestImsRegistrationImpl.getInstance().onDeregistered(getReasonInfo(mDeregisteredReason));
+    }
+
+    private void onRegChangeFailedClicked() {
+        if (!isFrameworkConnected()) {
+            return;
+        }
+        TestImsRegistrationImpl.getInstance().onTechnologyChangeFailed(mSelectedRegTech,
+                getReasonInfo(mRegChangeFailedReason));
+    }
+
+    private void onTechDropDownChanged(String item) {
+        mSelectedRegTech = REG_TECH.get(item);
+    }
+
+    private ImsReasonInfo getReasonInfo(View reasonView) {
+        EditText errorCodeText = reasonView.findViewById(R.id.imsreasoninfo_error);
+        EditText extraCodeText = reasonView.findViewById(R.id.imsreasoninfo_extra);
+        EditText messageText = reasonView.findViewById(R.id.imsreasoninfo_message);
+
+        int errorCode = ImsReasonInfo.CODE_UNSPECIFIED;
+        try {
+            errorCode = Integer.parseInt(errorCodeText.getText().toString());
+        } catch (NumberFormatException e) {
+            Toast.makeText(this, "Couldn't parse reason, defaulting to Unspecified.",
+                    Toast.LENGTH_SHORT).show();
+        }
+
+        int extraCode = ImsReasonInfo.CODE_UNSPECIFIED;
+        try {
+            extraCode = Integer.parseInt(extraCodeText.getText().toString());
+        } catch (NumberFormatException e) {
+            Toast.makeText(this, "Couldn't parse reason, defaulting to Unspecified.",
+                    Toast.LENGTH_SHORT).show();
+        }
+
+        String message = messageText.getText().toString();
+
+        ImsReasonInfo result = new ImsReasonInfo(errorCode, extraCode, message);
+        Toast.makeText(this, "getReasonInfo: " + result, Toast.LENGTH_SHORT).show();
+        return result;
+    }
+
+    private boolean isFrameworkConnected() {
+        if (TestImsRegistrationImpl.getInstance() == null) {
+            Toast.makeText(this, "Connection to Framework Unavailable!",
+                    Toast.LENGTH_LONG).show();
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
new file mode 100644
index 0000000..6b78a30
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.Intent;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * Main activity for Test ImsService Application.
+ */
+
+public class ImsTestServiceApp extends Activity {
+
+    private LinearLayout mConnections;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_main);
+
+        ((Button) findViewById(R.id.control_launch_reg)).setOnClickListener(
+                (view) -> launchRegistrationActivity());
+
+        ((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));
+    }
+
+    private void launchRegistrationActivity() {
+        Intent intent = new Intent(this, ImsRegistrationActivity.class);
+        startActivity(intent);
+    }
+
+    private void launchCallingActivity() {
+        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
new file mode 100644
index 0000000..4b8842a
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub.ImsConfigImplBase;
+
+import com.android.ims.ImsConfig;
+
+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 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 getConfigString(int item) {
+        return null;
+    }
+
+    public void setConfigValue(int item, int value) {
+        replaceConfig(new ConfigItem(item, value));
+        notifyProvisionedValueChanged(item, value);
+    }
+
+    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/TestImsRegistrationImpl.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsRegistrationImpl.java
new file mode 100644
index 0000000..50bf5d4
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsRegistrationImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub.ImsRegistrationImplBase;
+
+public class TestImsRegistrationImpl extends ImsRegistrationImplBase {
+
+    private static TestImsRegistrationImpl sInstance;
+
+    public static TestImsRegistrationImpl getInstance() {
+        if (sInstance == null) {
+            sInstance = new TestImsRegistrationImpl();
+        }
+        return sInstance;
+    }
+}
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
new file mode 100644
index 0000000..434cdb5
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.ImsService;
+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;
+
+/**
+ * Creates a test ImsService, which is used for testing framework IMS.
+ */
+
+public class TestImsService extends ImsService {
+
+    public static final String LOG_TAG = "ImsTestApp";
+
+    public static TestImsService mInstance;
+
+    public TestImsRegistrationImpl mImsRegistration;
+    public TestMmTelFeatureImpl mTestMmTelFeature;
+    public TestRcsFeatureImpl mTestRcsFeature;
+    public TestImsConfigImpl mTestImsConfig;
+
+    public static TestImsService getInstance() {
+        return mInstance;
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(LOG_TAG, "TestImsService: onCreate");
+        mImsRegistration = TestImsRegistrationImpl.getInstance();
+        mTestMmTelFeature = TestMmTelFeatureImpl.getInstance();
+        mTestRcsFeature = new TestRcsFeatureImpl();
+        mTestImsConfig = TestImsConfigImpl.getInstance();
+
+        mInstance = this;
+    }
+
+    @Override
+    public MmTelFeature createMmTelFeature(int slotId) {
+        Log.i(LOG_TAG, "TestImsService: onCreateEmergencyMMTelImsFeature");
+        return mTestMmTelFeature;
+    }
+
+    @Override
+    public RcsFeature createRcsFeature(int slotId) {
+        return mTestRcsFeature;
+    }
+
+    @Override
+    public ImsRegistrationImplBase getRegistration(int slotId) {
+        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
new file mode 100644
index 0000000..2a0463d
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.widget.Toast;
+
+import java.util.Set;
+
+public class TestMmTelFeatureImpl extends MmTelFeature {
+
+    public static TestMmTelFeatureImpl sTestMmTelFeatureImpl;
+    private boolean mIsReady = false;
+    // 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);
+    }
+
+    public static TestMmTelFeatureImpl getInstance() {
+        if (sTestMmTelFeatureImpl == null) {
+            sTestMmTelFeatureImpl = new TestMmTelFeatureImpl();
+        }
+        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) {
+        Toast.makeText(mContext, "Sending Capabilities:{" + c + "}",
+                Toast.LENGTH_LONG).show();
+
+        notifyCapabilitiesStatusChanged(c);
+    }
+
+    public SparseArray<MmTelCapabilities> getEnabledCapabilities() {
+        return mEnabledCapabilities;
+    }
+
+    @Override
+    public void onFeatureReady() {
+        mIsReady = true;
+    }
+}
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestRcsFeatureImpl.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestRcsFeatureImpl.java
new file mode 100644
index 0000000..996a569
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestRcsFeatureImpl.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.feature.RcsFeature;
+
+public class TestRcsFeatureImpl extends RcsFeature {
+
+    private boolean mIsReady = false;
+
+
+    public boolean isReady() {
+        return mIsReady;
+    }
+
+    @Override
+    public void onFeatureReady() {
+        mIsReady = true;
+    }
+}