Merge "Add TvPipMenuTests"
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index d8474b8..0d684e8 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -15,6 +15,7 @@
     limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/tv_pip_menu"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:orientation="horizontal"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 55796da..4ab5c6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -26,6 +26,7 @@
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
@@ -60,6 +61,9 @@
             getApplicationLabel(getApplicationInfo(packageName, 0)).toString()
         }
 
+    val ui: UiObject2?
+        get() = uiDevice.findObject(appSelector)
+
     fun launchViaIntent() {
         context.startActivity(openAppIntent)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
new file mode 100644
index 0000000..33b6902
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.flicker.pip.tv
+
+import android.os.SystemClock
+import androidx.test.filters.RequiresDevice
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Menu on TV.
+ * To run this test: `atest WMShellFlickerTests:TvPipMenuTests`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+class TvPipMenuTests(rotationName: String, rotation: Int)
+    : TvPipTestBase(rotationName, rotation) {
+
+    @Before
+    override fun setUp() {
+        super.setUp()
+        // Launch the app and go to PiP
+        testApp.launchViaIntent()
+        testApp.clickEnterPipButton()
+    }
+
+    @Test
+    fun pipMenu_open() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        val pipMenu = uiDevice.waitForTvPipMenu()
+                ?: fail("Pip notification should have been dismissed")
+
+        assertTrue("Pip menu should be shown fullscreen", pipMenu.isFullscreen(uiDevice))
+
+        testApp.closePipWindow()
+    }
+
+    @Test
+    fun pipMenu_backButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // Pressing the Back key should close the Pip menu
+        uiDevice.pressBack()
+        assertTrue("Pip notification should have closed", uiDevice.waitForTvPipMenuToClose())
+
+        testApp.closePipWindow()
+    }
+
+    @Test
+    fun pipMenu_closeButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // PiP menu should contain the Close button
+        val closeButton = uiDevice.findTvPipMenuCloseButton()
+                ?: fail("\"Close PIP\" button should be shown in Pip menu")
+
+        // Clicking on the Close button should close the app
+        closeButton.click()
+        assertTrue("\"Close PIP\" button should close the PiP", testApp.waitUntilClosed())
+    }
+
+    @Test
+    fun pipMenu_fullscreenButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // PiP menu should contain the Fullscreen button
+        val fullscreenButton = uiDevice.findTvPipMenuFullscreenButton()
+                ?: fail("\"Full screen\" button should be shown in Pip menu")
+
+        // Clicking on the fullscreen button should return app to the fullscreen mode.
+        // Click, wait for 3 seconds, check the app is fullscreen
+        fullscreenButton.click()
+        SystemClock.sleep(3_000L)
+        assertTrue("\"Full screen\" button should open the app fullscreen",
+                testApp.ui?.isFullscreen(uiDevice) ?: false)
+
+        // Close the app
+        uiDevice.pressBack()
+        testApp.waitUntilClosed()
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> = rotationParams
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
index 1d44658..7a9b33b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -20,7 +20,6 @@
 import android.app.PendingIntent
 import android.os.Bundle
 import android.service.notification.StatusBarNotification
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.NotificationListener.Companion.findNotification
 import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
@@ -32,10 +31,8 @@
 import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Before
-import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
 /**
@@ -44,7 +41,6 @@
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class TvPipNotificationTests(rotationName: String, rotation: Int)
     : TvPipTestBase(rotationName, rotation) {
 
@@ -60,7 +56,6 @@
     @After
     override fun tearDown() {
         stopNotificationListener()
-        testApp.forceStop()
         super.tearDown()
     }
 
@@ -108,7 +103,7 @@
         notification.contentIntent?.send()
             ?: fail("Pip notification should contain `content_intent`")
 
-        assertTrue("Pip menu should have been shown after sending `content_intent`",
+        assertNotNull("Pip menu should have been shown after sending `content_intent`",
                 uiDevice.waitForTvPipMenu())
 
         uiDevice.pressBack()
@@ -156,18 +151,13 @@
         testApp.closePipWindow()
     }
 
-    private fun fail(message: String): Nothing = throw AssertionError(message)
-
     companion object {
         private const val TITLE_MEDIA_SESSION_PLAYING = "TestApp media is playing"
         private const val TITLE_MEDIA_SESSION_PAUSED = "TestApp media is paused"
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<Array<Any>> {
-            val supportedRotations = intArrayOf(Surface.ROTATION_0)
-            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
-        }
+        fun getParams(): Collection<Array<Any>> = rotationParams
     }
 }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 104248c..05f4b0b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -18,6 +18,8 @@
 
 import android.content.pm.PackageManager.FEATURE_LEANBACK
 import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.view.Surface.ROTATION_0
+import android.view.Surface.rotationToString
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.pip.PipTestBase
 import org.junit.After
@@ -40,5 +42,14 @@
 
     @After
     open fun tearDown() {
+        testApp.forceStop()
+    }
+
+    protected fun fail(message: String): Nothing = throw AssertionError(message)
+
+    companion object {
+        @JvmStatic
+        protected val rotationParams: Collection<Array<Any>> =
+                listOf(arrayOf(rotationToString(ROTATION_0), ROTATION_0))
     }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index ac9ab13..d9e6ff3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -16,11 +16,35 @@
 
 package com.android.wm.shell.flicker.pip.tv
 
+import android.view.KeyEvent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
 import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
 
-fun UiDevice.waitForTvPipMenu(): Boolean {
-    return wait(Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "pip_controls")), 3_000) != null
+/** Id of the root view in the com.android.wm.shell.pip.tv.PipMenuActivity */
+private const val TV_PIP_MENU_ROOT_ID = "tv_pip_menu"
+private const val TV_PIP_MENU_CLOSE_BUTTON_ID = "close_button"
+private const val TV_PIP_MENU_FULLSCREEN_BUTTON_ID = "full_button"
+
+private const val WAIT_TIME_MS = 3_000L
+
+private val tvPipMenuSelector = By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_ROOT_ID)
+
+fun UiDevice.pressWindowKey() = pressKeyCode(KeyEvent.KEYCODE_WINDOW)
+
+fun UiDevice.waitForTvPipMenu(): UiObject2? =
+        wait(Until.findObject(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.waitForTvPipMenuToClose(): Boolean = wait(Until.gone(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.findTvPipMenuCloseButton(): UiObject2? = findObject(
+        By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_CLOSE_BUTTON_ID))
+
+fun UiDevice.findTvPipMenuFullscreenButton(): UiObject2? = findObject(
+        By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_FULLSCREEN_BUTTON_ID))
+
+fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
+    height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
 }
\ No newline at end of file