Test App for ImsService

A test application that tests the ImsService APIs.

Currently only used to test the integration of the
ImsRegistration APIs.

Bug: 63987047
Test: Install app
Change-Id: I54ea68887bc2ebbc17520a625d1f64e763cbf995
diff --git a/testapps/ImsTestService/Android.mk b/testapps/ImsTestService/Android.mk
new file mode 100644
index 0000000..6f73238
--- /dev/null
+++ b/testapps/ImsTestService/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+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..a0172eb
--- /dev/null
+++ b/testapps/ImsTestService/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?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" />
+
+        <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..968dcf1
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_calling.xml
@@ -0,0 +1,60 @@
+<?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" />
+</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..35c6ae2
--- /dev/null
+++ b/testapps/ImsTestService/res/layout/activity_main.xml
@@ -0,0 +1,98 @@
+<?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"/>
+        </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/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..e6db1b8
--- /dev/null
+++ b/testapps/ImsTestService/res/values/donottranslate_strings.xml
@@ -0,0 +1,40 @@
+<?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 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..d8d56fd
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -0,0 +1,80 @@
+/*
+ * 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.internal.feature.MmTelFeature;
+import android.widget.Button;
+import android.widget.CheckBox;
+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;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_calling);
+
+        TestMmTelFeatureImpl.getInstance().setContext(this);
+
+        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);
+        Button capChangedButton = findViewById(R.id.call_cap_change);
+        capChangedButton.setOnClickListener((v) -> onCapabilitiesChangedClicked());
+    }
+
+    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/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
new file mode 100644
index 0000000..6391e53
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -0,0 +1,155 @@
+/*
+ * 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 com.android.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..89c50e9
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsTestServiceApp.java
@@ -0,0 +1,59 @@
+/*
+ * 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());
+
+        // 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);
+    }
+}
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..0010af4
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsConfigImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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.os.RemoteException;
+import android.telephony.ims.stub.ImsConfigImplBase;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsConfigListener;
+
+public class TestImsConfigImpl extends ImsConfigImplBase {
+
+    @Override
+    public int getProvisionedValue(int item) throws RemoteException {
+        return ImsConfig.FeatureValueConstants.ON;
+    }
+
+    @Override
+    public String getProvisionedStringValue(int item) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public int setProvisionedValue(int item, int value) throws RemoteException {
+        return ImsConfig.OperationStatusConstants.SUCCESS;
+    }
+
+    @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);
+    }
+}
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..71357bd
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestImsService.java
@@ -0,0 +1,75 @@
+/*
+ * 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.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 static TestImsService getInstance() {
+        return mInstance;
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(LOG_TAG, "TestImsService: onCreate");
+        mImsRegistration = TestImsRegistrationImpl.getInstance();
+        mTestMmTelFeature = TestMmTelFeatureImpl.getInstance();
+        mTestRcsFeature = new TestRcsFeatureImpl();
+
+        mInstance = this;
+    }
+
+    @Override
+    public MMTelFeature onCreateEmergencyMMTelImsFeature(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) {
+        return mTestRcsFeature;
+    }
+
+    @Override
+    public ImsRegistrationImplBase getRegistration(int slotId) {
+        Log.i(LOG_TAG, "TestImsService: getRegistration");
+        return mImsRegistration;
+    }
+}
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..b112485
--- /dev/null
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/TestMmTelFeatureImpl.java
@@ -0,0 +1,163 @@
+/*
+ * 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.PendingIntent;
+import android.os.RemoteException;
+import android.telephony.ims.feature.MMTelFeature;
+import android.telephony.ims.internal.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsRegistrationListener;
+
+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 static TestMmTelFeatureImpl sTestMmTelFeatureImpl;
+    private boolean mIsReady = false;
+    private PendingIntent mIncomingCallIntent;
+    private List<IImsRegistrationListener> mRegistrationListeners = new ArrayList<>();
+    private TestImsConfigImpl mConfig = new TestImsConfigImpl();
+
+    public TestMmTelFeatureImpl() {
+        setFeatureState(STATE_READY);
+    }
+
+    public static TestMmTelFeatureImpl getInstance() {
+        if (sTestMmTelFeatureImpl == null) {
+            sTestMmTelFeatureImpl = new TestMmTelFeatureImpl();
+        }
+        return sTestMmTelFeatureImpl;
+    }
+
+    public boolean isReady() {
+        return mIsReady;
+    }
+
+    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.LENGTH_LONG).show();
+        mRegistrationListeners.forEach((l) -> {
+            try {
+                l.registrationFeatureCapabilityChanged(1 /*ImsServiceClass.MMTel*/,
+                        enabledCapabilities,
+                        disabledCapabilities);
+            } catch (RemoteException e) {
+                // ignore
+            }
+        });
+    }
+
+    @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;
+    }
+
+    @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;
+    }
+}