Assist CTS test

Change-Id: Ifa85a78e50e915a66610cc54fe815ef111c2764c
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 5042a74..54baacb 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -72,6 +72,8 @@
     CtsAccelerationTestStubs \
     CtsAlarmClockService \
     CtsAppTestStubs \
+    CtsAssistService \
+    CtsAssistApp \
     CtsAtraceTestApp \
     CtsCertInstallerApp \
     CtsDeviceAdmin \
@@ -136,6 +138,7 @@
     CtsAnimationTestCases \
     CtsAppTestCases \
     CtsAppWidgetTestCases \
+    CtsAssistTestCases \
     CtsBluetoothTestCases \
     CtsCalendarcommon2TestCases \
     CtsCallLogTestCases \
diff --git a/tests/tests/assist/Android.mk b/tests/tests/assist/Android.mk
new file mode 100644
index 0000000..89d2c49
--- /dev/null
+++ b/tests/tests/assist/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner ctsdeviceutil
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAssistTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/assist/AndroidManifest.xml b/tests/tests/assist/AndroidManifest.xml
new file mode 100644
index 0000000..c5772ad
--- /dev/null
+++ b/tests/tests/assist/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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"
+    package="android.assist.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
+
+    <application>
+      <uses-library android:name="android.test.runner" />
+      <activity android:name="android.assist.TestStartActivity"
+                android:label="Assist Target">
+          <intent-filter>
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_ASSIST_STRUCTURE" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_DISABLE_CONTEXT" />
+              <category android:name="android.intent.category.LAUNCHER" />
+              <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+      </activity>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.assist.cts"
+                     android:label="CTS tests of android.assist">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
+
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
new file mode 100644
index 0000000..f7c56ad
--- /dev/null
+++ b/tests/tests/assist/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<configuration description="Test module config for Assist">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAssistService.apk" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAssistApp.apk" />
+    <option name="run-command:run-command"
+         value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
+    <option name="run-command:teardown-command"
+         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAssistTestCases.apk" />
+</configuration>
diff --git a/tests/tests/assist/common/Android.mk b/tests/tests/assist/common/Android.mk
new file mode 100644
index 0000000..88c90ee
--- /dev/null
+++ b/tests/tests/assist/common/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := CtsAssistCommon
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java b/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
new file mode 100644
index 0000000..b9fb7cf
--- /dev/null
+++ b/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 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 android.assist.common;
+
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+
+public class Utils {
+    public enum TestCaseType {
+        ASSIST_STRUCTURE,
+        DISABLE_CONTEXT,
+    }
+    public static final String TESTCASE_TYPE = "testcase_type";
+    public static final String TESTINFO = "testinfo";
+    public static final String BROADCAST_INTENT = "android.intent.action.ASSIST_TESTAPP";
+    public static final String BROADCAST_ASSIST_DATA_INTENT = "android.intent.action.ASSIST_DATA";
+    public static final String TEST_ERROR = "Error In Test:";
+
+    public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
+    public static final String ASSIST_CONTENT_KEY = "assist_content";
+    public static final String ASSIST_BUNDLE = "assist_bundle";
+
+    public static final int TIMEOUT_MS = 2 * 1000; // TODO(awlee): what is the timeout
+
+    public static final String getTestActivity(String testCaseType) {
+        if (testCaseType.equals("ASSIST_STRUCTURE")) {
+            return "service.AssistStructureActivity";
+        } else if (testCaseType.equals("DISABLE_CONTEXT")) {
+            return "service.DisableContextActivity";
+        }
+        return "";
+    }
+
+    public static final String toBundleString(Bundle bundle) {
+        if (bundle == null) {
+            return "*** Bundle is null ****";
+        }
+        StringBuffer buf = new StringBuffer("Bundle is: ");
+        String testType = bundle.getString(TESTCASE_TYPE);
+        if (testType != null) {
+            buf.append("testcase type = " + testType);
+        }
+        ArrayList<String> info = bundle.getStringArrayList(TESTINFO);
+        if (info != null) {
+            for (String s : info) {
+                buf.append(s + "\n\t\t");
+            }
+        }
+        return buf.toString();
+    }
+
+    public static final String toOptionsString(Option[] options) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        for (int i = 0; i < options.length; i++) {
+            if (i >= 1) {
+                sb.append(", ");
+            }
+            sb.append(options[i].getLabel());
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public static final void addErrorResult(final Bundle testinfo, final String msg) {
+        testinfo.getStringArrayList(testinfo.getString(Utils.TESTCASE_TYPE))
+            .add(TEST_ERROR + " " + msg);
+    }
+}
diff --git a/tests/tests/assist/res/xml/interaction_service.xml b/tests/tests/assist/res/xml/interaction_service.xml
new file mode 100644
index 0000000..c968795
--- /dev/null
+++ b/tests/tests/assist/res/xml/interaction_service.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:sessionService="android.assist.service.MainInteractionSessionService"
+    android:recognitionService="android.assist.service.MainRecognitionService"
+    android:settingsActivity="android.assist.service.SettingsActivity"
+    android:supportsAssist="false" />
diff --git a/tests/tests/assist/service/Android.mk b/tests/tests/assist/service/Android.mk
new file mode 100644
index 0000000..07dc228
--- /dev/null
+++ b/tests/tests/assist/service/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner ctsdeviceutil
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAssistService
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/assist/service/AndroidManifest.xml b/tests/tests/assist/service/AndroidManifest.xml
new file mode 100644
index 0000000..543568d
--- /dev/null
+++ b/tests/tests/assist/service/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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"
+    package="android.assist.service">
+
+    <application>
+      <uses-library android:name="android.test.runner" />
+      <service android:name=".MainInteractionService"
+              android:label="CTS test voice interaction service"
+              android:permission="android.permission.BIND_VOICE_INTERACTION"
+              android:process=":interactor"
+              android:exported="true">
+          <meta-data android:name="android.voice_interaction"
+                     android:resource="@xml/interaction_service" />
+          <intent-filter>
+              <action android:name="android.service.voice.VoiceInteractionService" />
+          </intent-filter>
+      </service>
+      <activity android:name=".AssistStructureActivity" >
+          <intent-filter>
+              <action android:name="android.intent.action.START_TEST_ASSIST_STRUCTURE" />
+              <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+      </activity>
+      <activity android:name=".DisableContextActivity"
+                android:label="Disabled Context Activity">
+          <intent-filter>
+              <action android:name="android.intent.action.START_TEST_DISABLE_CONTEXT" />
+              <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+      </activity>
+      <service android:name=".MainInteractionSessionService"
+              android:permission="android.permission.BIND_VOICE_INTERACTION"
+              android:process=":session">
+      </service>
+      <service android:name=".MainRecognitionService"
+              android:label="CTS Voice Recognition Service">
+          <intent-filter>
+              <action android:name="android.speech.RecognitionService" />
+              <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+          <meta-data android:name="android.speech" android:resource="@xml/recognition_service" />
+      </service>
+    </application>
+</manifest>
+
diff --git a/tests/tests/assist/service/res/layout/voice_interaction_main.xml b/tests/tests/assist/service/res/layout/voice_interaction_main.xml
new file mode 100644
index 0000000..9169a37
--- /dev/null
+++ b/tests/tests/assist/service/res/layout/voice_interaction_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/welcome" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/service/res/values/strings.xml b/tests/tests/assist/service/res/values/strings.xml
new file mode 100644
index 0000000..a245b36
--- /dev/null
+++ b/tests/tests/assist/service/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="welcome">Hello there!</string>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/assist/service/res/xml/interaction_service.xml b/tests/tests/assist/service/res/xml/interaction_service.xml
new file mode 100644
index 0000000..3ca7161
--- /dev/null
+++ b/tests/tests/assist/service/res/xml/interaction_service.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:sessionService="android.assist.service.MainInteractionSessionService"
+    android:recognitionService="android.assist.service.MainRecognitionService"
+    android:settingsActivity="android.assist.service.SettingsActivity"
+    android:supportsAssist="true" />
diff --git a/tests/tests/assist/service/res/xml/recognition_service.xml b/tests/tests/assist/service/res/xml/recognition_service.xml
new file mode 100644
index 0000000..3f763b1
--- /dev/null
+++ b/tests/tests/assist/service/res/xml/recognition_service.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<recognition-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:settingsActivity="android.assist.service.SettingsActivity" />
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
new file mode 100644
index 0000000..8b63b25
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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 android.assist.service;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.util.Log;
+
+public class AssistStructureActivity extends Activity {
+    static final String TAG = "VoiceInteractionMain";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(this, MainInteractionService.class));
+        ComponentName serviceName = startService(intent);
+        Log.i(TAG, "Started service: " + serviceName);
+        getLayoutInflater().inflate(R.layout.voice_interaction_main, null);
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java
new file mode 100644
index 0000000..0db7ec1
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 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 android.assist.service;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * TODO(awlee): Change context on/off settings and test
+ */
+public class DisableContextActivity extends Activity {
+    static final String TAG = "DisableContextActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(this, MainInteractionService.class));
+        ComponentName serviceName = startService(intent);
+        Log.i(TAG, "Started service: " + serviceName);
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
new file mode 100644
index 0000000..56017ce
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 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 android.assist.service;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionService;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Log;
+
+public class MainInteractionService extends VoiceInteractionService {
+    static final String TAG = "MainInteractionService";
+    private Intent mIntent;
+    private boolean mReady = false;
+
+    @Override
+    public void onReady() {
+        super.onReady();
+        mReady = true;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "onStartCommand received");
+        mIntent = intent;
+        maybeStart();
+        return START_NOT_STICKY;
+    }
+
+    private void maybeStart() {
+       if (mIntent == null || !mReady) {
+            Log.wtf(TAG, "Can't start session because either intent is null or onReady() "
+                    + "has not been called yet. mIntent = " + mIntent + ", mReady = " + mReady);
+        } else {
+            Log.i(TAG, "Yay! about to start session with TestApp");
+            if (isActiveService(this, new ComponentName(this, getClass()))) {
+                Bundle args = new Bundle();
+                Intent intent = new Intent();
+                intent.setComponent(new ComponentName("android.assist.testapp",
+                        "android.assist.testapp.TestApp"));
+                args.putParcelable("intent", intent);
+                showSession(args, VoiceInteractionSession.SHOW_WITH_ASSIST |
+                        VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
+            } else {
+                Log.wtf(TAG, "**** Not starting MainInteractionService because" +
+                    " it is not set as the current voice interaction service");
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
new file mode 100644
index 0000000..d19c6f8
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 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 android.assist.service;
+
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.Prompt;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSession.ConfirmationRequest;
+import android.service.voice.VoiceInteractionSession.PickOptionRequest;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.assist.common.Utils;
+import android.webkit.URLUtil;
+
+public class MainInteractionSession extends VoiceInteractionSession {
+    static final String TAG = "MainInteractionSession";
+
+    Intent mStartIntent;
+    Context mContext;
+    Bundle mAssistData = new Bundle();
+
+    MainInteractionSession(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "onDestroy()");
+        super.onDestroy();
+    }
+
+    @Override
+    public void onShow(Bundle args, int showFlags) {
+        // set some content view.
+        // TODO: check that the view takes up the whole screen.
+        mStartIntent = args.getParcelable("intent");
+        startVoiceActivity(mStartIntent); // remove
+        // check that interactor mode is for assist
+        if ((showFlags & SHOW_WITH_ASSIST) == 0) {
+            return;
+        }
+        super.onShow(args, showFlags);
+    }
+
+
+    @Override
+    public void onHandleAssist(/*@Nullable */Bundle data, /*@Nullable*/ AssistStructure structure,
+        /*@Nullable*/ AssistContent content) {
+        Log.i(TAG, "onHandleAssist");
+        Log.i(TAG, String.format("Bundle: %s, Structure: %s, Content: %s", data, structure, content));
+        super.onHandleAssist(data, structure, content);
+
+        // send to test to verify that this is accurate.
+        mAssistData.putParcelable(Utils.ASSIST_STRUCTURE_KEY, structure);
+        mAssistData.putParcelable(Utils.ASSIST_CONTENT_KEY, content);
+        mAssistData.putBundle(Utils.ASSIST_BUNDLE, data);
+        broadcastResults();
+    }
+
+    @Override
+    public void onHandleScreenshot(/*@Nullable*/ Bitmap screenshot) {
+        super.onHandleScreenshot(screenshot);
+        // add this to mAssistData?
+    }
+
+    private void broadcastResults() {
+        Intent intent = new Intent(Utils.BROADCAST_ASSIST_DATA_INTENT);
+        intent.putExtras(mAssistData);
+        Log.i(TAG, "broadcasting: " + intent.toString() + ", Bundle = " + mAssistData.toString());
+        mContext.sendBroadcast(intent);
+    }
+
+    class DoneReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.i(TAG, "Done_broadcast " + intent.getAction());
+        }
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSessionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSessionService.java
new file mode 100644
index 0000000..ad356a6
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSessionService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 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 android.assist.service;
+
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSessionService;
+
+public class MainInteractionSessionService extends VoiceInteractionSessionService {
+    @Override
+    public VoiceInteractionSession onNewSession(Bundle args) {
+        return new MainInteractionSession(this);
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainRecognitionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainRecognitionService.java
new file mode 100644
index 0000000..520f913
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainRecognitionService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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 android.assist.service;
+
+import android.content.Intent;
+import android.speech.RecognitionService;
+import android.util.Log;
+
+/**
+ * Stub recognition service needed to be a complete voice interactor.
+ */
+public class MainRecognitionService extends RecognitionService {
+    private static final String TAG = "MainRecognitionService";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "onCreate");
+    }
+
+    @Override
+    protected void onStartListening(Intent recognizerIntent, Callback listener) {
+        Log.i(TAG, "onStartListening");
+    }
+
+    @Override
+    protected void onCancel(Callback listener) {
+        Log.i(TAG, "onCancel");
+    }
+
+    @Override
+    protected void onStopListening(Callback listener) {
+        Log.i(TAG, "onStopListening");
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "onDestroy");
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/TestStartActivity.java b/tests/tests/assist/src/android/assist/TestStartActivity.java
new file mode 100644
index 0000000..06bf5aa
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/TestStartActivity.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 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 android.assist;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import android.assist.common.Utils;
+
+public class TestStartActivity extends Activity {
+    static final String TAG = "TestStartActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, " in onCreate");
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Log.i(TAG, " in onResume");
+    }
+
+    public void startTest(String testCaseType) {
+        Log.i(TAG, "Starting test activity for TestCaseType = " + testCaseType);
+        Intent intent = new Intent();
+        intent.putExtra(Utils.TESTCASE_TYPE, testCaseType);
+        intent.setAction("android.intent.action.START_TEST_" + testCaseType);
+        intent.setComponent(new ComponentName("android.assist.service",
+                "android.assist." + Utils.getTestActivity(testCaseType)));
+        startActivity(intent);
+    }
+
+    @Override protected void onPause() {
+        Log.i(TAG, " in onPause");
+        super.onPause();
+    }
+
+    @Override protected void onStart() {
+        super.onStart();
+        Log.i(TAG, " in onStart");
+    }
+
+    @Override protected void onRestart() {
+        super.onRestart();
+        Log.i(TAG, " in onRestart");
+    }
+
+    @Override protected void onStop() {
+        Log.i(TAG, " in onStop");
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.i(TAG, " in onDestroy");
+        super.onDestroy();
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
new file mode 100644
index 0000000..3c93c8a
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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 android.assist.cts;
+
+import android.assist.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Exception;
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *  Test that the AssistStructure returned is properly formatted.
+ */
+
+public class AssistStructureTest extends AssistTestBase {
+    static final String TAG = "AssistStructureTest";
+
+    private static final String TEST_CASE_TYPE = "ASSIST_STRUCTURE";
+
+    public AssistStructureTest() {
+        super();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        startTestActivity(TEST_CASE_TYPE);
+        waitForBroadcast(Utils.TestCaseType.ASSIST_STRUCTURE);
+    }
+
+    public void testAssistStructure() throws Exception {
+        // verify assist data contains what we want.
+        // go through all things in the bundle, verify not null, verify contains what we want.
+
+        // TODO(awlee): verify that the context is not off by default.
+        if (mAssistContent == null || mAssistBundle == null) {
+            fail("Received null assistBundle or assistContent.");
+            return;
+        }
+
+        if (mAssistStructure == null) {
+            fail("Received null assistStructure");
+            return;
+        } else {
+            verifyAssistStructure(new ComponentName("android.assist.service",
+                    "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
+        }
+    }
+
+    private void verifyAssistStructure(ComponentName backgroundApp,
+            boolean isSecureWindow) {
+        // Check component name matches
+        assertEquals(backgroundApp.flattenToString(),
+                mAssistStructure.getActivityComponent().flattenToString());
+
+        int numWindows = mAssistStructure.getWindowNodeCount();
+        assertEquals(1, numWindows);
+        for (int i = 0; i < numWindows; i++) {
+            AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTest.java b/tests/tests/assist/src/android/assist/cts/AssistTest.java
new file mode 100644
index 0000000..5241c4e
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/AssistTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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 android.assist.cts;
+
+import android.assist.TestStartActivity;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.assist.common.Utils;
+
+public class AssistTest extends ActivityInstrumentationTestCase2<TestStartActivity> {
+    static final String TAG = "AssistTest";
+    private static final int TIMEOUT_MS = 2 * 1000;
+
+    public AssistTest() {
+        super(TestStartActivity.class);
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
new file mode 100644
index 0000000..a4f4cbc
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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 android.assist.cts;
+
+import android.assist.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class AssistTestBase extends ActivityInstrumentationTestCase2<TestStartActivity> {
+    static final String TAG = "AssistTestBase";
+
+    protected TestStartActivity mTestActivity;
+    protected AssistContent mAssistContent;
+    protected AssistStructure mAssistStructure;
+    protected BroadcastReceiver mReceiver;
+    protected Bundle mAssistBundle;
+    protected Context mContext;
+    protected CountDownLatch mLatch;
+    protected Utils.TestCaseType mTestCaseType;
+    private String mTestName;
+
+    public AssistTestBase() {
+        super(TestStartActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getTargetContext();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mContext.unregisterReceiver(mReceiver);
+        mTestActivity.finish();
+        super.tearDown();
+    }
+
+    protected void startTestActivity(String testName) {
+        Intent intent = new Intent();
+        mTestName = testName;
+        intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + testName);
+        intent.setComponent(new ComponentName(getInstrumentation().getContext(),
+                TestStartActivity.class));
+        setActivityIntent(intent);
+        mTestActivity = getActivity();
+    }
+
+    /**
+     * Called after startTestActivity
+     */
+    protected boolean waitForBroadcast(Utils.TestCaseType testCaseType) throws Exception {
+        mTestCaseType = testCaseType;
+        mLatch = new CountDownLatch(1);
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new TestResultsReceiver();
+        mContext.registerReceiver(mReceiver,
+                new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
+
+        mTestActivity.startTest(mTestName);
+        if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
+            return false;
+        }
+        return true;
+    }
+
+    class TestResultsReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equalsIgnoreCase(Utils.BROADCAST_ASSIST_DATA_INTENT)) { // not necessary?
+                Log.i(TAG, "received broadcast with results ");
+                Bundle assistData = intent.getExtras();
+                AssistTestBase.this.mAssistStructure = assistData.getParcelable(
+                        Utils.ASSIST_STRUCTURE_KEY);
+                AssistTestBase.this.mAssistBundle = assistData.getBundle(Utils.ASSIST_BUNDLE);
+                AssistTestBase.this.mAssistContent = assistData.getParcelable(
+                        Utils.ASSIST_CONTENT_KEY);
+
+                if (mLatch != null) {
+                    mLatch.countDown();
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
new file mode 100644
index 0000000..f3da32b
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 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 android.assist.cts;
+
+import android.assist.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+
+/** Test we receive proper assist data when context is disabled or enabled */
+
+public class DisableContextTest extends AssistTestBase {
+    static final String TAG = "DisableContextTest";
+
+    private static final String TEST_CASE_TYPE = "DISABLE_CONTEXT";
+
+    public DisableContextTest() {
+        super();
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        // need to set action/component/activityintent for the test activity?
+        startTestActivity(TEST_CASE_TYPE);
+        waitForBroadcast(Utils.TestCaseType.DISABLE_CONTEXT);
+    }
+
+    public void testContextOnAndOff() throws Exception {
+        // filler
+
+
+        // verify assist data contains what we want.
+        // go through all things in the bundle, verify not null, verify contains what we want.
+
+        // TODO(awlee): verify that the context is not off by default.
+        if (mAssistContent == null || mAssistBundle == null) {
+            fail("Received null assistBundle or assistContent.");
+            return;
+        }
+
+        if (mAssistStructure == null) {
+            fail("Received null assistStructure");
+            return;
+        } else {
+            verifyAssistStructure(new ComponentName("android.assist.service",
+                    "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
+        }
+    }
+
+    private void verifyAssistStructure(ComponentName backgroundApp,
+            boolean isSecureWindow) {
+        // Check component name matches
+        assertEquals(backgroundApp.flattenToString(),
+                mAssistStructure.getActivityComponent().flattenToString());
+
+        int numWindows = mAssistStructure.getWindowNodeCount();
+        assertEquals(1, numWindows);
+        for (int i = 0; i < numWindows; i++) {
+            AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/Android.mk b/tests/tests/assist/testapp/Android.mk
new file mode 100644
index 0000000..68297ef
--- /dev/null
+++ b/tests/tests/assist/testapp/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAssistApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
new file mode 100644
index 0000000..5b16ed7
--- /dev/null
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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"
+    package="android.assist.testapp">
+
+    <application>
+      <uses-library android:name="android.test.runner" />
+
+      <activity android:name="TestApp"
+                android:label="Assist Test App"
+                android:theme="@android:style/Theme.Material.Light">
+          <intent-filter>
+              <action android:name="android.intent.action.TEST_APP" />
+              <category android:name="android.intent.category.DEFAULT" />
+              <category android:name="android.intent.category.VOICE" />
+          </intent-filter>
+      </activity>
+    </application>
+</manifest>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
new file mode 100644
index 0000000..9083cda
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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 android.assist.testapp;
+
+import android.app.Activity;
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.AbortVoiceRequest;
+import android.app.VoiceInteractor.CommandRequest;
+import android.app.VoiceInteractor.CompleteVoiceRequest;
+import android.app.VoiceInteractor.ConfirmationRequest;
+import android.app.VoiceInteractor.PickOptionRequest;
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import android.app.VoiceInteractor.Prompt;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionService;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+import android.assist.common.Utils;
+
+public class TestApp extends Activity {
+
+}