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:
Hongwei Wang
2020-08-12 15:32:01 -07:00
parent 48f430566d
commit bbf561ac3a
23 changed files with 799 additions and 20 deletions

View 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

View 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"
],
}

View 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>

View 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>

View 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`

View File

@@ -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()
}
}

View File

@@ -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"
}
}

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.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) }
}
}
}

View File

@@ -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"
}
}

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.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()
}
}

View File

@@ -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) }
}
}
}

View File

@@ -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"
}
}

View File

@@ -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"],
}

View File

@@ -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>

View File

@@ -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>

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.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));
}
}

View File

@@ -13,7 +13,7 @@
// limitations under the License.
android_test {
name: "WindowManagerShellTests",
name: "WMShellUnitTests",
srcs: ["**/*.java"],

View File

@@ -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" />