Add FocusChange Test
Verify that the focused activity loses focus when the Assistant is shown.

Bug: 21668302

Change-Id: Iead210619b0a613c1ea43600a3e839ab36d63ef8
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index f15f6b0..99d1d42 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -306,9 +306,10 @@
 {
   description: "New assist tests that do not yet have a track record.",
   names: [
-    "android.assist.cts.ScreenshotTest",
+    "android.assist.cts.AssistantContentViewTest",
     "android.assist.cts.ExtraAssistDataTest",
-    "android.assist.cts.AssistantContentViewTest"
+    "android.assist.cts.FocusChangeTest",
+    "android.assist.cts.ScreenshotTest"
   ],
   bug: 21668302
 }
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index cc45dbd..77d7c9e 100644
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -54,6 +54,10 @@
     public static final String LIFECYCLE_ONSTOP = LIFECYCLE_PREFIX + "onstop";
     public static final String LIFECYCLE_ONDESTROY = LIFECYCLE_PREFIX + "ondestroy";
 
+    /** Focus Change Test intent constants */
+    public static final String GAINED_FOCUS = ACTION_PREFIX + "focus_changed";
+    public static final String LOST_FOCUS = ACTION_PREFIX + "lost_focus";
+
     /** Flag Secure Test intent constants */
     public static final String FLAG_SECURE_HASRESUMED = ACTION_PREFIX + "flag_secure_hasResumed";
     public static final String APP_3P_HASRESUMED = ACTION_PREFIX + "screenshot_hasResumed";
@@ -80,6 +84,7 @@
     public static final String SCREENSHOT = "SCREENSHOT";
     public static final String EXTRA_ASSIST = "EXTRA_ASSIST";
     public static final String VERIFY_CONTENT_VIEW = "VERIFY_CONTENT_VIEW";
+    public static final String FOCUS_CHANGE = "FOCUS_CHANGE";
 
     /** Session intent constants */
     public static final String HIDE_SESSION = "android.intent.action.hide_session";
@@ -135,6 +140,7 @@
             case SCREENSHOT:
             case EXTRA_ASSIST:
             case VERIFY_CONTENT_VIEW:
+            case FOCUS_CHANGE:
                 return "service.DelayedAssistantActivity";
             default:
                 return "";
@@ -162,6 +168,9 @@
             case EXTRA_ASSIST:
                 return new ComponentName(
                         "android.assist.testapp", "android.assist.testapp.ExtraAssistDataActivity");
+            case FOCUS_CHANGE:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.FocusChangeActivity");
             default:
                 return new ComponentName("","");
         }
diff --git a/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
new file mode 100644
index 0000000..f6b90b9
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.cts.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test that triggering the Assistant causes the underlying Activity to lose focus **/
+
+public class FocusChangeTest extends AssistTestBase {
+    private static final String TAG = "FocusChangeTest";
+    private static final String TEST_CASE_TYPE = Utils.FOCUS_CHANGE;
+
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasGainedFocusLatch = new CountDownLatch(1);
+    private CountDownLatch mHasLostFocusLatch = new CountDownLatch(1);
+    private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(TEST_CASE_TYPE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new FocusChangeTestReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.GAINED_FOCUS);
+        filter.addAction(Utils.LOST_FOCUS);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitToGainFocus() throws Exception {
+        Log.i(TAG, "Waiting for the underlying activity to gain focus before continuing.");
+        if (!mHasGainedFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to gain focus in " + Utils.TIMEOUT_MS + "msec.");
+        }
+    }
+
+    private void waitToLoseFocus() throws Exception {
+        Log.i(TAG, "Waiting for the underlying activity to lose focus.");
+        if (!mHasLostFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity maintained focus despite the Assistant Firing"
+                 + Utils.TIMEOUT_MS + "msec.");
+        }
+    }
+
+    public void testLayerCausesUnderlyingActivityToLoseFocus() throws Exception {
+        mTestActivity.startTest(Utils.FOCUS_CHANGE);
+        waitForAssistantToBeReady(mReadyLatch);
+        mTestActivity.start3pApp(Utils.FOCUS_CHANGE);
+        waitToGainFocus();
+        startSession();
+        waitToLoseFocus();
+    }
+
+    private class FocusChangeTestReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.GAINED_FOCUS) && mHasGainedFocusLatch != null) {
+                mHasGainedFocusLatch.countDown();
+            } else if (action.equals(Utils.LOST_FOCUS) && mHasLostFocusLatch != null) {
+                mHasLostFocusLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                if (mReadyLatch != null) {
+                    mReadyLatch.countDown();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
index ecfafd6..ab7bb29 100644
--- a/tests/tests/assist/testapp/AndroidManifest.xml
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -72,5 +72,13 @@
                 <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
+        <activity android:name="FocusChangeActivity"
+            android:label="Focus Change Test Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_FOCUS_CHANGE" />
+                <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/FocusChangeActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
new file mode 100644
index 0000000..4ab24ed
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.assist.common.Utils;
+import android.content.Intent;
+import android.util.Log;
+
+public class FocusChangeActivity extends Activity {
+    private static final String TAG = "FocusChangeActivity";
+    private boolean mGainedFocus = false;
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        if (hasFocus && !mGainedFocus) {
+            mGainedFocus = true;
+            Log.i(TAG, "gained focus");
+            sendBroadcast(new Intent(Utils.GAINED_FOCUS));
+        } else if (!hasFocus && mGainedFocus) {
+            Log.i(TAG, "lost focus");
+            sendBroadcast(new Intent(Utils.LOST_FOCUS));
+        }
+    }
+}
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index adb6a4e..5032911 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -474,6 +474,7 @@
           'android.assist.cts.ExtraAssistDataTest',
           'android.assist.cts.AssistantContentViewTest',
           'android.assist.cts.ScreenshotTest',
+          'android.assist.cts.FocusChangeTest',
       ],
       'android.calllog' : [
           'android.calllog.cts.CallLogBackupTest#testSingleCallBackup',