Add flicker test for WM Shell
Separated folders in libs/WindowManager/Shell/tests - unittest, for unit tests - flicker, for this flicker tests - propose to add functional/ folder for functional tests Note also - Copied over EnterPipTest from existing flicker tests as proof of concept - TODO: need to figure out the next step for the flicker test library itself as it's currently packaged in com.android.server.wm Bug: 161561007 Test: atest WMShellFlickerTests Test: atest WMShellUnitTests Change-Id: Ic06e7cb0f98151591ccb9f5217260939349a9aa5
This commit is contained in:
15
libs/WindowManager/Shell/tests/README.md
Normal file
15
libs/WindowManager/Shell/tests/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# WM Shell Test
|
||||
|
||||
This contains all tests written for WM (WindowManager) Shell and it's currently
|
||||
divided into 3 categories
|
||||
|
||||
- unittest, tests against individual functions, usually @SmallTest and do not
|
||||
require UI automation nor real device to run
|
||||
- integration, this maybe a mix of functional and integration tests. Contains
|
||||
tests verify the WM Shell as a whole, like talking to WM core. This usually
|
||||
involves mocking the window manager service or even talking to the real one.
|
||||
Due to this nature, test cases in this package is normally annotated as
|
||||
@LargeTest and runs with UI automation on real device
|
||||
- flicker, similar to functional tests with its sole focus on flickerness. See
|
||||
[WM Shell Flicker Test Package](http://cs/android/framework/base/libs/WindowManager/Shell/tests/flicker/)
|
||||
for more details
|
||||
34
libs/WindowManager/Shell/tests/flicker/Android.bp
Normal file
34
libs/WindowManager/Shell/tests/flicker/Android.bp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
android_test {
|
||||
name: "WMShellFlickerTests",
|
||||
srcs: ["src/**/*.java", "src/**/*.kt"],
|
||||
manifest: "AndroidManifest.xml",
|
||||
test_config: "AndroidTest.xml",
|
||||
platform_apis: true,
|
||||
certificate: "platform",
|
||||
test_suites: ["device-tests"],
|
||||
libs: ["android.test.runner"],
|
||||
static_libs: [
|
||||
"androidx.test.ext.junit",
|
||||
"flickerlib",
|
||||
"truth-prebuilt",
|
||||
"app-helpers-core",
|
||||
"launcher-helper-lib",
|
||||
"launcher-aosp-tapl"
|
||||
],
|
||||
}
|
||||
43
libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
Normal file
43
libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.flicker">
|
||||
|
||||
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
|
||||
<!-- Read and write traces from external storage -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<!-- Write secure settings -->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<!-- Capture screen contents -->
|
||||
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
|
||||
<!-- Enable / Disable tracing !-->
|
||||
<uses-permission android:name="android.permission.DUMP" />
|
||||
<!-- Run layers trace -->
|
||||
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
|
||||
<!-- 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"/>
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner"/>
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.wm.shell.flicker"
|
||||
android:label="WindowManager Shell Flicker Tests">
|
||||
</instrumentation>
|
||||
</manifest>
|
||||
40
libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
Normal file
40
libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright 2020 Google Inc. All Rights Reserved.
|
||||
-->
|
||||
<configuration description="Runs WindowManager Shell Flicker Tests">
|
||||
<option name="test-tag" value="FlickerTests" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
|
||||
<!-- keeps the screen on during tests -->
|
||||
<option name="screen-always-on" value="on" />
|
||||
<!-- prevents the phone from restarting -->
|
||||
<option name="force-skip-system-props" value="true" />
|
||||
<!-- set WM tracing verbose level to all -->
|
||||
<option name="run-command" value="cmd window tracing level all" />
|
||||
<!-- inform WM to log all transactions -->
|
||||
<option name="run-command" value="cmd window tracing transaction" />
|
||||
<!-- restart launcher to activate TAPL -->
|
||||
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
|
||||
</target_preparer>
|
||||
<target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
|
||||
<!-- reboot the device to teardown any crashed tests -->
|
||||
<option name="cleanup-action" value="REBOOT" />
|
||||
</target_preparer>
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true"/>
|
||||
<option name="test-file-name" value="WMShellFlickerTests.apk"/>
|
||||
<option name="test-file-name" value="WMShellFlickerTestApp.apk" />
|
||||
</target_preparer>
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
|
||||
<option name="package" value="com.android.wm.shell.flicker"/>
|
||||
<option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
|
||||
<option name="shell-timeout" value="6600s" />
|
||||
<option name="test-timeout" value="6000s" />
|
||||
<option name="hidden-api-checks" value="false" />
|
||||
</test>
|
||||
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
|
||||
<option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
|
||||
<option name="collect-on-run-ended-only" value="true" />
|
||||
<option name="clean-up" value="true" />
|
||||
</metrics_collector>
|
||||
</configuration>
|
||||
10
libs/WindowManager/Shell/tests/flicker/README.md
Normal file
10
libs/WindowManager/Shell/tests/flicker/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# WM Shell Flicker Test Package
|
||||
|
||||
Please reference the following links
|
||||
|
||||
- [Introduction to Flicker Test Library](http://cs/android/platform_testing/libraries/flicker/)
|
||||
- [Flicker Test in frameworks/base](http://cs/android/frameworks/base/tests/FlickerTests/)
|
||||
|
||||
on what is Flicker Test and how to write a Flicker Test
|
||||
|
||||
To run the Flicker Tests for WM Shell, simply run `atest WMShellFlickerTests`
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 com.android.server.wm.flicker.dsl.EventLogAssertion
|
||||
import com.android.server.wm.flicker.dsl.LayersAssertion
|
||||
import com.android.server.wm.flicker.dsl.WmAssertion
|
||||
import com.android.server.wm.flicker.helpers.WindowUtils
|
||||
|
||||
@JvmOverloads
|
||||
fun WmAssertion.statusBarWindowIsAlwaysVisible(
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
|
||||
this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun WmAssertion.navBarWindowIsAlwaysVisible(
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all("navBarWindowIsAlwaysVisible", enabled, bugId) {
|
||||
this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun LayersAssertion.noUncoveredRegions(
|
||||
beginRotation: Int,
|
||||
endRotation: Int = beginRotation,
|
||||
allStates: Boolean = true,
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
|
||||
val endingBounds = WindowUtils.getDisplayBounds(endRotation)
|
||||
if (allStates) {
|
||||
all("noUncoveredRegions", enabled, bugId) {
|
||||
if (startingBounds == endingBounds) {
|
||||
this.coversAtLeastRegion(startingBounds)
|
||||
} else {
|
||||
this.coversAtLeastRegion(startingBounds)
|
||||
.then()
|
||||
.coversAtLeastRegion(endingBounds)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
start("noUncoveredRegions_StartingPos") {
|
||||
this.coversAtLeastRegion(startingBounds)
|
||||
}
|
||||
end("noUncoveredRegions_EndingPos") {
|
||||
this.coversAtLeastRegion(endingBounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun LayersAssertion.navBarLayerIsAlwaysVisible(
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all("navBarLayerIsAlwaysVisible", enabled, bugId) {
|
||||
this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun LayersAssertion.statusBarLayerIsAlwaysVisible(
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
|
||||
this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun LayersAssertion.navBarLayerRotatesAndScales(
|
||||
beginRotation: Int,
|
||||
endRotation: Int = beginRotation,
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
|
||||
val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
|
||||
|
||||
start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
|
||||
this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
|
||||
}
|
||||
end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
|
||||
this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
|
||||
}
|
||||
|
||||
if (startingPos == endingPos) {
|
||||
all("navBarLayerRotatesAndScales", enabled, bugId) {
|
||||
this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun LayersAssertion.statusBarLayerRotatesScales(
|
||||
beginRotation: Int,
|
||||
endRotation: Int = beginRotation,
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
|
||||
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
|
||||
|
||||
start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
|
||||
this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
|
||||
}
|
||||
end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
|
||||
this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
|
||||
}
|
||||
}
|
||||
|
||||
fun EventLogAssertion.focusChanges(
|
||||
vararg windows: String,
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all(enabled = enabled, bugId = bugId) {
|
||||
this.focusChanges(windows)
|
||||
}
|
||||
}
|
||||
|
||||
fun EventLogAssertion.focusDoesNotChange(
|
||||
bugId: Int = 0,
|
||||
enabled: Boolean = bugId == 0
|
||||
) {
|
||||
all(enabled = enabled, bugId = bugId) {
|
||||
this.focusDoesNotChange()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.RemoteException
|
||||
import android.os.SystemClock
|
||||
import android.platform.helpers.IAppHelper
|
||||
import android.view.Surface
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import com.android.server.wm.flicker.Flicker
|
||||
|
||||
/**
|
||||
* Base class of all Flicker test that performs common functions for all flicker tests:
|
||||
*
|
||||
*
|
||||
* - Caches transitions so that a transition is run once and the transition results are used by
|
||||
* tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
|
||||
* multiple times.
|
||||
* - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
|
||||
* - Fails tests if results are not available for any test due to jank.
|
||||
*/
|
||||
abstract class FlickerTestBase {
|
||||
val instrumentation by lazy {
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
}
|
||||
val uiDevice by lazy {
|
||||
UiDevice.getInstance(instrumentation)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a test tag for the test
|
||||
* @param testName Name of the transition(s) being tested
|
||||
* @param app App being launcher
|
||||
* @param rotation Initial screen rotation
|
||||
*
|
||||
* @return test tag with pattern <NAME>__<APP>__<ROTATION>
|
||||
</ROTATION></APP></NAME> */
|
||||
protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
|
||||
return buildTestTag(
|
||||
testName, app, rotation, rotation, app2 = null, extraInfo = "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a test tag for the test
|
||||
* @param testName Name of the transition(s) being tested
|
||||
* @param app App being launcher
|
||||
* @param beginRotation Initial screen rotation
|
||||
* @param endRotation End screen rotation (if any, otherwise use same as initial)
|
||||
*
|
||||
* @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
|
||||
</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
|
||||
protected fun buildTestTag(
|
||||
testName: String,
|
||||
app: IAppHelper,
|
||||
beginRotation: Int,
|
||||
endRotation: Int
|
||||
): String {
|
||||
return buildTestTag(
|
||||
testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a test tag for the test
|
||||
* @param testName Name of the transition(s) being tested
|
||||
* @param app App being launcher
|
||||
* @param app2 Second app being launched (if any)
|
||||
* @param beginRotation Initial screen rotation
|
||||
* @param endRotation End screen rotation (if any, otherwise use same as initial)
|
||||
* @param extraInfo Additional information to append to the tag
|
||||
*
|
||||
* @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
|
||||
</EXTRA></NAME> */
|
||||
protected fun buildTestTag(
|
||||
testName: String,
|
||||
app: IAppHelper,
|
||||
beginRotation: Int,
|
||||
endRotation: Int,
|
||||
app2: IAppHelper?,
|
||||
extraInfo: String
|
||||
): String {
|
||||
var testTag = "${testName}__${app.launcherName}"
|
||||
if (app2 != null) {
|
||||
testTag += "-${app2.launcherName}"
|
||||
}
|
||||
testTag += "__${Surface.rotationToString(beginRotation)}"
|
||||
if (endRotation != beginRotation) {
|
||||
testTag += "-${Surface.rotationToString(endRotation)}"
|
||||
}
|
||||
if (extraInfo.isNotEmpty()) {
|
||||
testTag += "__$extraInfo"
|
||||
}
|
||||
return testTag
|
||||
}
|
||||
|
||||
protected fun Flicker.setRotation(rotation: Int) {
|
||||
try {
|
||||
when (rotation) {
|
||||
Surface.ROTATION_270 -> device.setOrientationLeft()
|
||||
Surface.ROTATION_90 -> device.setOrientationRight()
|
||||
Surface.ROTATION_0 -> device.setOrientationNatural()
|
||||
else -> device.setOrientationNatural()
|
||||
}
|
||||
// Wait for animation to complete
|
||||
SystemClock.sleep(1000)
|
||||
} catch (e: RemoteException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
|
||||
const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
|
||||
const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
|
||||
}
|
||||
}
|
||||
@@ -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.view.Surface
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
abstract class NonRotationTestBase(
|
||||
protected val rotationName: String,
|
||||
protected val rotation: Int
|
||||
) : FlickerTestBase() {
|
||||
companion object {
|
||||
const val SCREENSHOT_LAYER = "RotationLayer"
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<Array<Any>> {
|
||||
val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
|
||||
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.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"
|
||||
}
|
||||
}
|
||||
@@ -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.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 com.android.server.wm.flicker.helpers.hasPipWindow
|
||||
import com.android.server.wm.flicker.helpers.closePipWindow
|
||||
import org.junit.Assert
|
||||
|
||||
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 " +
|
||||
"was left in an unknown state (e.g. in split screen)", enterPipButton)
|
||||
enterPipButton.click()
|
||||
device.hasPipWindow()
|
||||
}
|
||||
|
||||
fun closePipWindow(device: UiDevice) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import android.view.Surface
|
||||
import androidx.test.filters.FlakyTest
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.android.server.wm.flicker.dsl.flicker
|
||||
import com.android.server.wm.flicker.helpers.closePipWindow
|
||||
import com.android.server.wm.flicker.helpers.expandPipWindow
|
||||
import com.android.server.wm.flicker.helpers.hasPipWindow
|
||||
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
|
||||
import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
|
||||
import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
|
||||
import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
|
||||
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 org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test Pip launch.
|
||||
* To run this test: `atest FlickerTests:PipToAppTest`
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@FlakyTest(bugId = 152738416)
|
||||
class EnterPipTest(
|
||||
rotationName: String,
|
||||
rotation: Int
|
||||
) : PipTestBase(rotationName, rotation) {
|
||||
@Test
|
||||
fun test() {
|
||||
flicker(instrumentation) {
|
||||
withTag { buildTestTag("enterPip", testApp, rotation) }
|
||||
repeat { 1 }
|
||||
setup {
|
||||
test {
|
||||
device.wakeUpAndGoToHomeScreen()
|
||||
}
|
||||
eachRun {
|
||||
device.pressHome()
|
||||
testApp.open()
|
||||
this.setRotation(rotation)
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
testApp.exit()
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
test {
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
transitions {
|
||||
testApp.clickEnterPipButton(device)
|
||||
device.expandPipWindow()
|
||||
}
|
||||
assertions {
|
||||
windowManagerTrace {
|
||||
navBarWindowIsAlwaysVisible()
|
||||
statusBarWindowIsAlwaysVisible()
|
||||
all("pipWindowBecomesVisible") {
|
||||
this.showsAppWindow(testApp.`package`)
|
||||
.then()
|
||||
.showsAppWindow(sPipWindowTitle)
|
||||
}
|
||||
}
|
||||
|
||||
layersTrace {
|
||||
navBarLayerIsAlwaysVisible()
|
||||
statusBarLayerIsAlwaysVisible()
|
||||
noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
|
||||
navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
|
||||
statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
|
||||
|
||||
all("pipLayerBecomesVisible") {
|
||||
this.showsLayer(testApp.launcherName)
|
||||
.then()
|
||||
.showsLayer(sPipWindowTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,25 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell;
|
||||
package com.android.wm.shell.flicker.pip
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import com.android.wm.shell.flicker.NonRotationTestBase
|
||||
import com.android.wm.shell.flicker.helpers.PipAppHelper
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
abstract class PipTestBase(
|
||||
rotationName: String,
|
||||
rotation: Int
|
||||
) : NonRotationTestBase(rotationName, rotation) {
|
||||
protected val testApp = PipAppHelper(instrumentation)
|
||||
|
||||
/**
|
||||
* Tests for the shell.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WindowManagerShellTest {
|
||||
|
||||
WindowManagerShell mShell;
|
||||
|
||||
@Test
|
||||
public void testNothing() {
|
||||
// Do nothing
|
||||
companion object {
|
||||
const val sPipWindowTitle = "PipMenuActivity"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
android_test {
|
||||
name: "WMShellFlickerTestApp",
|
||||
srcs: ["**/*.java"],
|
||||
sdk_version: "current",
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.flicker.testapp">
|
||||
|
||||
<uses-sdk android:minSdkVersion="29"
|
||||
android:targetSdkVersion="29"/>
|
||||
<application android:allowBackup="false"
|
||||
android:supportsRtl="true">
|
||||
<activity android:name=".PipActivity"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
|
||||
android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
|
||||
android:label="PipApp"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/holo_blue_bright">
|
||||
<Button android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/enter_pip"
|
||||
android:text="Enter PIP"/>
|
||||
</LinearLayout>
|
||||
@@ -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.testapp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.util.Rational;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
|
||||
public class PipActivity extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
WindowManager.LayoutParams p = getWindow().getAttributes();
|
||||
p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
|
||||
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
getWindow().setAttributes(p);
|
||||
setContentView(R.layout.activity_pip);
|
||||
Button enterPip = (Button) findViewById(R.id.enter_pip);
|
||||
|
||||
PictureInPictureParams params = new PictureInPictureParams.Builder()
|
||||
.setAspectRatio(new Rational(1, 1))
|
||||
.setSourceRectHint(new Rect(0, 0, 100, 100))
|
||||
.build();
|
||||
|
||||
enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
android_test {
|
||||
name: "WindowManagerShellTests",
|
||||
name: "WMShellUnitTests",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="install-arg" value="-t" />
|
||||
<option name="test-file-name" value="WindowManagerShellTests.apk" />
|
||||
<option name="test-file-name" value="WMShellUnitTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="framework-base-presubmit" />
|
||||
<option name="test-tag" value="WindowManagerShellTests" />
|
||||
<option name="test-tag" value="WMShellUnitTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.wm.shell.tests" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
Reference in New Issue
Block a user