Merge changes I6a3e2fb9,Icc102a51

* changes:
  Introduce .wm.flicker.pip.tv.TvPipNotificationTests
  Prepare .wm.shell.flicker for test migration
This commit is contained in:
TreeHugger Robot
2020-11-04 19:40:06 +00:00
committed by Android (Google) Code Review
14 changed files with 477 additions and 87 deletions

View File

@@ -32,8 +32,19 @@
<!-- Workaround grant runtime permission exception from b/152733071 -->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<!-- Force-stop test apps -->
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<application>
<uses-library android:name="android.test.runner"/>
<service android:name=".NotificationListener"
android:exported="true"
android:label="WMShellTestsNotificationListenerService"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"

View File

@@ -0,0 +1,36 @@
/*
* 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
import android.content.ComponentName
const val IME_WINDOW_NAME = "InputMethod"
const val PIP_WINDOW_NAME = "PipMenuActivity"
// Test App
const val TEST_APP_PACKAGE_NAME = "com.android.wm.shell.flicker.testapp"
// Test App > Pip Activity
val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
TEST_APP_PACKAGE_NAME, ".PipActivity")
const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp"
const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
// Test App > Ime Activity
val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
TEST_APP_PACKAGE_NAME, ".ImeActivity")
const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp"
const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"

View File

@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker
import android.content.pm.PackageManager
import android.os.RemoteException
import android.os.SystemClock
import android.platform.helpers.IAppHelper
@@ -41,6 +42,9 @@ abstract class FlickerTestBase {
val uiDevice by lazy {
UiDevice.getInstance(instrumentation)
}
val packageManager: PackageManager by lazy {
instrumentation.context.getPackageManager()
}
/**
* Build a test tag for the test

View File

@@ -0,0 +1,89 @@
/*
* 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
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import com.android.compatibility.common.util.SystemUtil.runShellCommand
class NotificationListener : NotificationListenerService() {
private val notifications: MutableMap<Any, StatusBarNotification> = mutableMapOf()
override fun onNotificationPosted(sbn: StatusBarNotification) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: $sbn")
notifications[sbn.key] = sbn
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved: $sbn")
notifications.remove(sbn.key)
}
override fun onListenerConnected() {
if (DEBUG) Log.d(TAG, "onListenerConnected")
instance = this
}
override fun onListenerDisconnected() {
if (DEBUG) Log.d(TAG, "onListenerDisconnected")
instance = null
notifications.clear()
}
companion object {
private const val DEBUG = false
private const val TAG = "WMShellFlickerTests_NotificationListener"
private const val CMD_NOTIFICATION_ALLOW_LISTENER = "cmd notification allow_listener %s"
private const val CMD_NOTIFICATION_DISALLOW_LISTENER =
"cmd notification disallow_listener %s"
private const val COMPONENT_NAME = "com.android.wm.shell.flicker/.NotificationListener"
private var instance: NotificationListener? = null
fun startNotificationListener(): Boolean {
if (instance != null) {
return true
}
runShellCommand(CMD_NOTIFICATION_ALLOW_LISTENER.format(COMPONENT_NAME))
return wait { instance != null }
}
fun stopNotificationListener(): Boolean {
if (instance == null) {
return true
}
runShellCommand(CMD_NOTIFICATION_DISALLOW_LISTENER.format(COMPONENT_NAME))
return wait { instance == null }
}
fun waitForNotificationToAppear(predicate: (StatusBarNotification) -> Boolean): Boolean {
return instance?.let {
wait { it.notifications.values.any(predicate) }
} ?: throw IllegalStateException("NotificationListenerService is not connected")
}
fun waitForNotificationToDisappear(predicate: (StatusBarNotification) -> Boolean): Boolean {
return instance?.let {
wait { it.notifications.values.none(predicate) }
} ?: throw IllegalStateException("NotificationListenerService is not connected")
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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
import android.os.SystemClock
private const val DEFAULT_TIMEOUT = 10000L
private const val DEFAULT_POLL_INTERVAL = 1000L
fun wait(condition: () -> Boolean): Boolean {
val (success, _) = waitForResult(extractor = condition, validator = { it })
return success
}
fun <R> waitForResult(
timeout: Long = DEFAULT_TIMEOUT,
interval: Long = DEFAULT_POLL_INTERVAL,
extractor: () -> R,
validator: (R) -> Boolean = { it != null }
): Pair<Boolean, R?> {
val startTime = SystemClock.uptimeMillis()
do {
val result = extractor()
if (validator(result)) {
return (true to result)
}
SystemClock.sleep(interval)
} while (SystemClock.uptimeMillis() - startTime < timeout)
return (false to null)
}

View File

@@ -0,0 +1,81 @@
/*
* 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.helpers
import android.app.ActivityManager
import android.app.Instrumentation
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
abstract class BaseAppHelper(
instrumentation: Instrumentation,
launcherName: String,
private val launcherActivityComponent: ComponentName
) : StandardAppHelper(
instrumentation,
TEST_APP_PACKAGE_NAME,
launcherName,
LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
) {
protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
private val context: Context
get() = mInstrumentation.context
private val activityManager: ActivityManager?
get() = context.getSystemService(ActivityManager::class.java)
private val appSelector = By.pkg(packageName).depth(0)
protected val isTelevision: Boolean
get() = context.packageManager.run {
hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
}
val label: String
get() = context.packageManager.run {
getApplicationLabel(getApplicationInfo(packageName, 0)).toString()
}
fun launchViaIntent() {
context.startActivity(openAppIntent)
uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS)
}
fun forceStop() = activityManager?.forceStopPackage(packageName)
override fun getOpenAppIntent(): Intent {
val intent = Intent()
intent.component = launcherActivityComponent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
return intent
}
companion object {
private const val APP_LAUNCH_WAIT_TIME_MS = 10_000L
}
}

View File

@@ -1,31 +0,0 @@
/*
* 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.helpers
import android.app.Instrumentation
import android.support.test.launcherhelper.ILauncherStrategy
import com.android.server.wm.flicker.helpers.StandardAppHelper
abstract class FlickerAppHelper(
instr: Instrumentation,
launcherName: String,
launcherStrategy: ILauncherStrategy
) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
companion object {
var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
}
}

View File

@@ -17,37 +17,36 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
import android.support.test.launcherhelper.ILauncherStrategy
import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.waitForIME
import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
import org.junit.Assert
open class ImeAppHelper(
instr: Instrumentation,
launcherName: String = "ImeApp",
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
.getInstance(instr)
.launcherStrategy
) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
open fun openIME(device: UiDevice) {
val editText = device.wait(
instrumentation: Instrumentation
) : BaseAppHelper(
instrumentation,
TEST_APP_IME_ACTIVITY_LABEL,
TEST_APP_IME_ACTIVITY_COMPONENT_NAME
) {
fun openIME() {
val editText = uiDevice.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
FIND_TIMEOUT)
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
if (!device.waitForIME()) {
if (!uiDevice.waitForIME()) {
Assert.fail("IME did not appear")
}
}
open fun closeIME(device: UiDevice) {
device.pressBack()
fun closeIME() {
uiDevice.pressBack()
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
device.waitForIdle(1000)
uiDevice.waitForIdle(1000)
}
}

View File

@@ -17,29 +17,56 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
import android.support.test.launcherhelper.ILauncherStrategy
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.os.SystemClock
import android.view.KeyEvent.KEYCODE_WINDOW
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import com.android.server.wm.flicker.helpers.hasPipWindow
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.closePipWindow
import org.junit.Assert
import com.android.server.wm.flicker.helpers.hasPipWindow
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_LABEL
import org.junit.Assert.assertNotNull
class PipAppHelper(
instr: Instrumentation,
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
.getInstance(instr)
.launcherStrategy
) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
fun clickEnterPipButton(device: UiDevice) {
val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
Assert.assertNotNull("Pip button not found, this usually happens when the device " +
instrumentation: Instrumentation
) : BaseAppHelper(
instrumentation,
TEST_APP_PIP_ACTIVITY_LABEL,
TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
) {
fun clickEnterPipButton() {
val enterPipButton = uiDevice.findObject(By.res(packageName, "enter_pip"))
assertNotNull("Pip button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", enterPipButton)
enterPipButton.click()
device.hasPipWindow()
// TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs
if (!isTelevision) {
uiDevice.hasPipWindow()
} else {
// Simply wait for 3 seconds
SystemClock.sleep(3_000)
}
}
fun closePipWindow(device: UiDevice) {
device.closePipWindow()
fun closePipWindow() {
// TODO(b/172321238): remove this check once and simply call closePipWindow once the TV
// logic is integrated there.
if (!isTelevision) {
uiDevice.closePipWindow()
} else {
// Bring up Pip menu
uiDevice.pressKeyCode(KEYCODE_WINDOW)
// Wait for the menu to come up and render the close button
val closeButton = uiDevice.wait(
Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "close_button")), 3_000)
assertNotNull("Pip menu close button is not found", closeButton)
closeButton.click()
// Give it 1 second, just in case
SystemClock.sleep(1_000)
}
}
}

View File

@@ -31,6 +31,7 @@ import com.android.wm.shell.flicker.noUncoveredRegions
import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
import com.android.wm.shell.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.PIP_WINDOW_NAME
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -79,7 +80,7 @@ class EnterPipTest(
}
}
transitions {
testApp.clickEnterPipButton(device)
testApp.clickEnterPipButton()
device.expandPipWindow()
}
assertions {
@@ -89,7 +90,7 @@ class EnterPipTest(
all("pipWindowBecomesVisible") {
this.showsAppWindow(testApp.`package`)
.then()
.showsAppWindow(sPipWindowTitle)
.showsAppWindow(PIP_WINDOW_NAME)
}
}
@@ -103,7 +104,7 @@ class EnterPipTest(
all("pipLayerBecomesVisible") {
this.showsLayer(testApp.launcherName)
.then()
.showsLayer(sPipWindowTitle)
.showsLayer(PIP_WINDOW_NAME)
}
}
}

View File

@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.pip
import android.content.ComponentName
import android.graphics.Region
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.util.Log
import android.view.Surface
import android.view.WindowManager
@@ -29,6 +28,9 @@ import com.android.server.wm.flicker.dsl.runWithFlicker
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
import com.android.wm.shell.flicker.IME_WINDOW_NAME
import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_WINDOW_NAME
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -51,19 +53,11 @@ class PipKeyboardTest(
private val windowManager: WindowManager =
instrumentation.context.getSystemService(WindowManager::class.java)
private val keyboardApp = ImeAppHelper(instrumentation, "ImeApp",
LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy)
private val KEYBOARD_ACTIVITY: ComponentName = ComponentName.createRelative(
"com.android.wm.shell.flicker.testapp", ".ImeActivity")
private val PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
private val INPUT_METHOD_WINDOW_NAME = "InputMethod"
private val testRepetitions = 10
private val keyboardApp = ImeAppHelper(instrumentation)
private val keyboardScenario: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
repeat { testRepetitions }
repeat { TEST_REPETITIONS }
// disable layer tracing
withLayerTracing { null }
setup {
@@ -73,11 +67,11 @@ class PipKeyboardTest(
// launch our target pip app
testApp.open()
this.setRotation(rotation)
testApp.clickEnterPipButton(device)
testApp.clickEnterPipButton()
// open an app with an input field and a keyboard
// UiAutomator doesn't support to launch the multiple Activities in a task.
// So use launchActivity() for the Keyboard Activity.
launchActivity(KEYBOARD_ACTIVITY)
launchActivity(TEST_APP_IME_ACTIVITY_COMPONENT_NAME)
}
}
teardown {
@@ -101,10 +95,10 @@ class PipKeyboardTest(
withTestName { testTag }
transitions {
// open the soft keyboard
keyboardApp.openIME(device)
keyboardApp.openIME()
// then close it again
keyboardApp.closeIME(device)
keyboardApp.closeIME()
}
assertions {
windowManagerTrace {
@@ -127,18 +121,18 @@ class PipKeyboardTest(
withTestName { testTag }
transitions {
// open the soft keyboard
keyboardApp.openIME(device)
keyboardApp.openIME()
}
teardown {
eachRun {
// close the keyboard
keyboardApp.closeIME(device)
keyboardApp.closeIME()
}
}
assertions {
windowManagerTrace {
end {
isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME)
isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME)
}
}
}
@@ -207,6 +201,8 @@ class PipKeyboardTest(
}
companion object {
private const val TEST_REPETITIONS = 10
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {

View File

@@ -24,8 +24,4 @@ abstract class PipTestBase(
rotation: Int
) : NonRotationTestBase(rotationName, rotation) {
protected val testApp = PipAppHelper(instrumentation)
companion object {
const val sPipWindowTitle = "PipMenuActivity"
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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.app.Notification
import android.service.notification.StatusBarNotification
import android.view.Surface
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
import com.android.wm.shell.flicker.NotificationListener.Companion.stopNotificationListener
import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToAppear
import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToDisappear
import org.junit.After
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
/**
* Test Pip Notifications on TV.
* To run this test: `atest WMShellFlickerTests:TvPipNotificationTests`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class TvPipNotificationTests(rotationName: String, rotation: Int)
: TvPipTestBase(rotationName, rotation) {
@Before
override fun setUp() {
super.setUp()
val started = startNotificationListener()
if (!started) {
error("NotificationListener hasn't started")
}
}
@After
override fun tearDown() {
stopNotificationListener()
testApp.forceStop()
super.tearDown()
}
@Test
fun pipNotification_postedAndDismissed() {
testApp.launchViaIntent()
testApp.clickEnterPipButton()
assertTrue("Pip notification should have been posted",
waitForNotificationToAppear { it.isPipNotificationWithTitle(testApp.label) })
testApp.closePipWindow()
assertTrue("Pip notification should have been dismissed",
waitForNotificationToDisappear { it.isPipNotificationWithTitle(testApp.label) })
}
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val supportedRotations = intArrayOf(Surface.ROTATION_0)
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
}
private const val PIP_NOTIFICATION_TAG = "PipNotification"
private val StatusBarNotification.title: String
get() = notification?.extras?.getString(Notification.EXTRA_TITLE) ?: ""
private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean =
tag == PIP_NOTIFICATION_TAG && title == expectedTitle

View File

@@ -0,0 +1,44 @@
/*
* 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.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.pip.PipTestBase
import org.junit.After
import org.junit.Assume
import org.junit.Before
abstract class TvPipTestBase(rotationName: String, rotation: Int)
: PipTestBase(rotationName, rotation) {
private val isTelevision: Boolean
get() = packageManager.run {
hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
}
@Before
open fun setUp() {
Assume.assumeTrue(isTelevision)
uiDevice.wakeUpAndGoToHomeScreen()
}
@After
open fun tearDown() {
}
}