blob: 061218a015e445be4aa0ea91e87d82c4cac7d4bc [file] [log] [blame]
/*
* 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.graphics.Rect
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.UiObject2
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.testapp.Components
import com.android.wm.shell.flicker.wait
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
/**
* Test Pip Menu on TV.
* To run this test: `atest WMShellFlickerTests:TvPipMenuTests`
*/
@RequiresDevice
class TvPipMenuTests : TvPipTestBase() {
private val systemUiResources =
packageManager.getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME)
private val pipBoundsWhileInMenu: Rect = systemUiResources.run {
val bounds = getString(getIdentifier("pip_menu_bounds", "string",
SYSTEM_UI_PACKAGE_NAME))
Rect.unflattenFromString(bounds) ?: error("Could not retrieve PiP menu bounds")
}
private val playButtonDescription = systemUiResources.run {
getString(getIdentifier("pip_play", "string",
SYSTEM_UI_PACKAGE_NAME))
}
private val pauseButtonDescription = systemUiResources.run {
getString(getIdentifier("pip_pause", "string",
SYSTEM_UI_PACKAGE_NAME))
}
@Before
fun tvPipMenuTestsTestUp() {
// Launch the app and go to PiP
testApp.launchViaIntent()
}
@Test
fun pipMenu_correctPosition() {
enterPip_openMenu_assertShown()
// Make sure the PiP task is positioned where it should be.
val activityBounds: Rect = testApp.ui?.visibleBounds
?: error("Could not retrieve Pip Activity bounds")
assertTrue("Pip Activity is positioned correctly while Pip menu is shown",
pipBoundsWhileInMenu == activityBounds)
// Make sure the Pip Menu Actions are positioned correctly.
uiDevice.findTvPipMenuControls()?.visibleBounds?.run {
assertTrue("Pip Menu Actions should be positioned below the Activity in Pip",
top >= activityBounds.bottom)
assertTrue("Pip Menu Actions should be positioned central horizontally",
centerX() == uiDevice.displayWidth / 2)
assertTrue("Pip Menu Actions should be fully shown on the screen",
left >= 0 && right <= uiDevice.displayWidth && bottom <= uiDevice.displayHeight)
} ?: error("Could not retrieve Pip Menu Actions bounds")
testApp.closePipWindow()
}
@Test
fun pipMenu_backButton() {
enterPip_openMenu_assertShown()
// Pressing the Back key should close the Pip menu
uiDevice.pressBack()
assertTrue("Pip menu should have closed", uiDevice.waitForTvPipMenuToClose())
testApp.closePipWindow()
}
@Test
fun pipMenu_homeButton() {
enterPip_openMenu_assertShown()
// Pressing the Home key should close the Pip menu
uiDevice.pressHome()
assertTrue("Pip menu should have closed", uiDevice.waitForTvPipMenuToClose())
testApp.closePipWindow()
}
@Test
fun pipMenu_closeButton() {
enterPip_openMenu_assertShown()
// PiP menu should contain the Close button
uiDevice.findTvPipMenuCloseButton()
?: fail("\"Close PIP\" button should be shown in Pip menu")
// Clicking on the Close button should close the app
uiDevice.clickTvPipMenuCloseButton()
assertTrue("\"Close PIP\" button should close the PiP", testApp.waitUntilClosed())
}
@Test
fun pipMenu_fullscreenButton() {
enterPip_openMenu_assertShown()
// PiP menu should contain the Fullscreen button
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 the app to go fullscreen
uiDevice.clickTvPipMenuFullscreenButton()
assertTrue("\"Full screen\" button should open the app fullscreen",
wait { testApp.ui?.isFullscreen(uiDevice) ?: false })
// Close the app
uiDevice.pressBack()
testApp.waitUntilClosed()
}
@Test
fun pipMenu_mediaPlayPauseButtons() {
// Start media session before entering PiP
testApp.clickStartMediaSessionButton()
enterPip_openMenu_assertShown()
assertFullscreenAndCloseButtonsAreShown()
// PiP menu should contain the Pause button
uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription)
?: fail("\"Pause\" button should be shown in Pip menu if there is an active " +
"playing media session.")
// When we pause media, the button should change from Pause to Play
uiDevice.clickTvPipMenuElementWithDescription(pauseButtonDescription)
assertFullscreenAndCloseButtonsAreShown()
// PiP menu should contain the Play button now
uiDevice.waitForTvPipMenuElementWithDescription(playButtonDescription)
?: fail("\"Play\" button should be shown in Pip menu if there is an active " +
"paused media session.")
testApp.closePipWindow()
}
@Test
fun pipMenu_withCustomActions() {
// Enter PiP with custom actions.
testApp.checkWithCustomActionsCheckbox()
enterPip_openMenu_assertShown()
// PiP menu should contain "No-Op", "Off" and "Clear" buttons...
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_NO_OP)
?: fail("\"No-Op\" button should be shown in Pip menu")
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_OFF)
?: fail("\"Off\" button should be shown in Pip menu")
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_CLEAR)
?: fail("\"Clear\" button should be shown in Pip menu")
// ... and should also contain the "Full screen" and "Close" buttons.
assertFullscreenAndCloseButtonsAreShown()
uiDevice.clickTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_OFF)
// Invoking the "Off" action should replace it with the "On" action/button and should
// remove the "No-Op" action/button. "Clear" action/button should remain in the menu ...
uiDevice.waitForTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_ON)
?: fail("\"On\" button should be shown in Pip for a corresponding custom action")
assertNull("\"No-Op\" button should not be shown in Pip menu",
uiDevice.findTvPipMenuElementWithDescription(
Components.PipActivity.MENU_ACTION_NO_OP))
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_CLEAR)
?: fail("\"Clear\" button should be shown in Pip menu")
// ... as well as the "Full screen" and "Close" buttons.
assertFullscreenAndCloseButtonsAreShown()
uiDevice.clickTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_CLEAR)
// Invoking the "Clear" action should remove all the custom actions and their corresponding
// buttons, ...
uiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(
Components.PipActivity.MENU_ACTION_ON)?.also {
isGone -> if (!isGone) fail("\"On\" button should not be shown in Pip menu")
}
assertNull("\"Off\" button should not be shown in Pip menu",
uiDevice.findTvPipMenuElementWithDescription(
Components.PipActivity.MENU_ACTION_OFF))
assertNull("\"Clear\" button should not be shown in Pip menu",
uiDevice.findTvPipMenuElementWithDescription(
Components.PipActivity.MENU_ACTION_CLEAR))
assertNull("\"No-Op\" button should not be shown in Pip menu",
uiDevice.findTvPipMenuElementWithDescription(
Components.PipActivity.MENU_ACTION_NO_OP))
// ... but the menu should still contain the "Full screen" and "Close" buttons.
assertFullscreenAndCloseButtonsAreShown()
testApp.closePipWindow()
}
@Test
fun pipMenu_customActions_override_mediaControls() {
// Start media session before entering PiP with custom actions.
testApp.checkWithCustomActionsCheckbox()
testApp.clickStartMediaSessionButton()
enterPip_openMenu_assertShown()
// PiP menu should contain "No-Op", "Off" and "Clear" buttons for the custom actions...
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_NO_OP)
?: fail("\"No-Op\" button should be shown in Pip menu")
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_OFF)
?: fail("\"Off\" button should be shown in Pip menu")
uiDevice.findTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_CLEAR)
?: fail("\"Clear\" button should be shown in Pip menu")
// ... should also contain the "Full screen" and "Close" buttons, ...
assertFullscreenAndCloseButtonsAreShown()
// ... but should not contain media buttons.
assertNull("\"Play\" button should not be shown in menu when there are custom actions",
uiDevice.findTvPipMenuElementWithDescription(playButtonDescription))
assertNull("\"Pause\" button should not be shown in menu when there are custom actions",
uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription))
uiDevice.clickTvPipMenuElementWithDescription(Components.PipActivity.MENU_ACTION_CLEAR)
// Invoking the "Clear" action should remove all the custom actions, which should bring up
// media buttons...
uiDevice.waitForTvPipMenuElementWithDescription(pauseButtonDescription)
?: fail("\"Pause\" button should be shown in Pip menu if there is an active " +
"playing media session.")
// ... while the "Full screen" and "Close" buttons should remain in the menu.
assertFullscreenAndCloseButtonsAreShown()
testApp.closePipWindow()
}
private fun enterPip_openMenu_assertShown(): UiObject2 {
testApp.clickEnterPipButton()
// Pressing the Window key should bring up Pip menu
uiDevice.pressWindowKey()
return uiDevice.waitForTvPipMenu() ?: fail("Pip menu should have been shown")
}
private fun assertFullscreenAndCloseButtonsAreShown() {
uiDevice.findTvPipMenuCloseButton()
?: fail("\"Close PIP\" button should be shown in Pip menu")
uiDevice.findTvPipMenuFullscreenButton()
?: fail("\"Full screen\" button should be shown in Pip menu")
}
}