diff options
| author | 2020-11-27 00:26:45 +0000 | |
|---|---|---|
| committer | 2020-11-27 00:26:45 +0000 | |
| commit | 5ba5c09b248ff252502f74d84b3ca22ccf0737b1 (patch) | |
| tree | d06b5280856a077229a45f83249368b2f65d6375 | |
| parent | bf598cdfbced87a281827e01e7b8dd0a07c99a01 (diff) | |
| parent | 72800c90299eae30b590ad0e558bb853262414c2 (diff) | |
Merge "Migrate some CTS tests about PIP presentation to WMShellFlickerTests"
23 files changed, 899 insertions, 170 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index 1bbe6884a48c..4a498d2ec581 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -33,6 +33,7 @@ android_test { "wm-flicker-common-assertions", "wm-flicker-common-app-helpers", "platform-test-annotations", + "wmshell-flicker-test-components", ], } @@ -54,5 +55,6 @@ android_test { "wm-flicker-common-assertions", "wm-flicker-common-app-helpers", "platform-test-annotations", + "wmshell-flicker-test-components", ], } diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml index 9e8330973b40..101b5bf27c77 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml @@ -36,6 +36,8 @@ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> <!-- Control test app's media session --> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> + <!-- ATM.removeRootTasksWithActivityTypes() --> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <application> <uses-library android:name="android.test.runner"/> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt index bbf5afcff67a..96234fcc8570 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -16,35 +16,24 @@ package com.android.wm.shell.flicker -import android.content.ComponentName - const val IME_WINDOW_NAME = "InputMethod" -const val PIP_WINDOW_NAME = "PipMenuActivity" -const val SPLITSCREEN_PRIMARY_WINDOW_NAME = "SplitScreenActivity" -const val SPLITSCREEN_SECONDARY_WINDOW_NAME = "SplitScreenSecondaryActivity" +const val PIP_MENU_WINDOW_NAME = "PipMenuActivity" const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" 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" const val TEST_APP_PIP_MENU_ACTION_NO_OP = "No-Op" const val TEST_APP_PIP_MENU_ACTION_ON = "On" const val TEST_APP_PIP_MENU_ACTION_OFF = "Off" const val TEST_APP_PIP_MENU_ACTION_CLEAR = "Clear" // 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" +// Test App > Test Activity +const val TEST_APP_FIXED_ACTIVITY_LABEL = "FixedApp" // Test App > SplitScreen Activity -val TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME: ComponentName = ComponentName.createRelative( - TEST_APP_PACKAGE_NAME, ".$SPLITSCREEN_PRIMARY_WINDOW_NAME") -val TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME: ComponentName = ComponentName.createRelative( - TEST_APP_PACKAGE_NAME, ".$SPLITSCREEN_SECONDARY_WINDOW_NAME") const val TEST_APP_SPLITSCREEN_PRIMARY_LABEL = "SplitScreenPrimaryApp" const val TEST_APP_SPLITSCREEN_SECONDARY_LABEL = "SplitScreenSecondaryApp" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt index 1a4de0a80bec..f32cd8842074 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt @@ -17,12 +17,11 @@ package com.android.wm.shell.flicker.apppairs import com.android.wm.shell.flicker.NonRotationTestBase -import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL -import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import com.android.wm.shell.flicker.testapp.Components abstract class AppPairsTestBase( rotationName: String, @@ -30,11 +29,11 @@ abstract class AppPairsTestBase( ) : NonRotationTestBase(rotationName, rotation) { protected val appPairsHelper = AppPairsHelper(instrumentation, TEST_APP_SPLITSCREEN_PRIMARY_LABEL, - TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME) + Components.SplitScreenActivity()) protected val primaryApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_PRIMARY_LABEL, - TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME) + Components.SplitScreenActivity()) protected val secondaryApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_SECONDARY_LABEL, - TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME) + Components.SplitScreenSecondaryActivity()) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt index 3b6fcdbee4be..e2cda7ad123d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt @@ -17,19 +17,19 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.graphics.Region import android.system.helpers.ActivityHelper import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.wm.shell.flicker.testapp.Components class AppPairsHelper( instrumentation: Instrumentation, activityLabel: String, - componentName: ComponentName + componentsInfo: Components.ComponentsInfo ) : BaseAppHelper( instrumentation, activityLabel, - componentName + componentsInfo ) { val activityHelper = ActivityHelper.getInstance() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt index 22496a506e0d..6fd1df3b3f30 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager.FEATURE_LEANBACK @@ -28,15 +27,15 @@ import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.StandardAppHelper -import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME +import com.android.wm.shell.flicker.testapp.Components abstract class BaseAppHelper( instrumentation: Instrumentation, launcherName: String, - private val launcherActivityComponent: ComponentName + private val componentsInfo: Components.ComponentsInfo ) : StandardAppHelper( instrumentation, - TEST_APP_PACKAGE_NAME, + Components.PACKAGE_NAME, launcherName, LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy ) { @@ -53,7 +52,7 @@ abstract class BaseAppHelper( } val defaultWindowName: String - get() = launcherActivityComponent.className + get() = componentsInfo.activityName val label: String get() = context.packageManager.run { @@ -63,8 +62,12 @@ abstract class BaseAppHelper( val ui: UiObject2? get() = uiDevice.findObject(appSelector) - fun launchViaIntent() { - context.startActivity(openAppIntent) + fun launchViaIntent(stringExtras: Map<String, String> = mapOf()) { + val intent = openAppIntent + stringExtras.forEach() { + intent.putExtra(it.key, it.value) + } + context.startActivity(intent) uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS) } @@ -75,7 +78,7 @@ abstract class BaseAppHelper( override fun getOpenAppIntent(): Intent { val intent = Intent() - intent.component = launcherActivityComponent + intent.component = componentsInfo.componentName intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) return intent } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt new file mode 100644 index 000000000000..c7f19a5d2620 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt @@ -0,0 +1,29 @@ +/* + * 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 com.android.wm.shell.flicker.TEST_APP_FIXED_ACTIVITY_LABEL +import com.android.wm.shell.flicker.testapp.Components + +class FixedAppHelper( + instrumentation: Instrumentation +) : BaseAppHelper( + instrumentation, + TEST_APP_FIXED_ACTIVITY_LABEL, + Components.FixedActivity() +)
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt index a6650d7f13d1..d580104ade19 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt @@ -21,8 +21,8 @@ import androidx.test.uiautomator.By 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 com.android.wm.shell.flicker.testapp.Components import org.junit.Assert open class ImeAppHelper( @@ -30,7 +30,7 @@ open class ImeAppHelper( ) : BaseAppHelper( instrumentation, TEST_APP_IME_ACTIVITY_LABEL, - TEST_APP_IME_ACTIVITY_COMPONENT_NAME + Components.ImeActivity() ) { fun openIME() { val editText = uiDevice.wait( diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt index e85ba9ef6da2..ed5f8a42258b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt @@ -26,8 +26,8 @@ import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.closePipWindow 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 com.android.wm.shell.flicker.testapp.Components import org.junit.Assert.assertNotNull import org.junit.Assert.fail @@ -36,7 +36,7 @@ class PipAppHelper( ) : BaseAppHelper( instrumentation, TEST_APP_PIP_ACTIVITY_LABEL, - TEST_APP_PIP_ACTIVITY_COMPONENT_NAME + Components.PipActivity() ) { private val mediaSessionManager: MediaSessionManager get() = context.getSystemService(MediaSessionManager::class.java) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt index 10daa675ce36..e67fc97dad2e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt @@ -17,19 +17,19 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.graphics.Region import android.os.SystemClock import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.wm.shell.flicker.testapp.Components class SplitScreenHelper( instrumentation: Instrumentation, activityLabel: String, - componentName: ComponentName + componentsInfo: Components.ComponentsInfo ) : BaseAppHelper( instrumentation, activityLabel, - componentName + componentsInfo ) { /** diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt new file mode 100644 index 000000000000..2015f4941cea --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt @@ -0,0 +1,46 @@ +/* + * 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.app.ActivityTaskManager +import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT +import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED +import android.os.SystemClock +import com.android.wm.shell.flicker.NonRotationTestBase + +abstract class AppTestBase( + rotationName: String, + rotation: Int +) : NonRotationTestBase(rotationName, rotation) { + companion object { + fun removeAllTasksButHome() { + val ALL_ACTIVITY_TYPE_BUT_HOME = intArrayOf( + ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, + ACTIVITY_TYPE_UNDEFINED) + val atm = ActivityTaskManager.getService() + atm.removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME) + } + + fun waitForAnimationComplete() { + // TODO: UiDevice doesn't have reliable way to wait for the completion of animation. + // Consider to introduce WindowManagerStateHelper to access Activity state. + SystemClock.sleep(1000) + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt new file mode 100644 index 000000000000..0663eb344f46 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt @@ -0,0 +1,118 @@ +/* + * 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.RequiresDevice +import com.android.server.wm.flicker.dsl.runFlicker +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.helpers.PipAppHelper +import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +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 and exit. + * To run this test: `atest WMShellFlickerTests:EnterExitPipTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class EnterExitPipTest( + rotationName: String, + rotation: Int +) : AppTestBase(rotationName, rotation) { + private val pipApp = PipAppHelper(instrumentation) + private val testApp = FixedAppHelper(instrumentation) + + @Test + fun testDisplayMetricsPinUnpin() { + runFlicker(instrumentation) { + withTestName { "testDisplayMetricsPinUnpin" } + setup { + test { + removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true")) + testApp.launchViaIntent() + waitForAnimationComplete() + } + } + transitions { + // This will bring PipApp to fullscreen + pipApp.launchViaIntent() + waitForAnimationComplete() + } + teardown { + test { + removeAllTasksButHome() + } + } + assertions { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + windowManagerTrace { + all("pipApp must remain inside visible bounds") { + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + all("Initially shows both app windows then pipApp hides testApp") { + showsAppWindow(testApp.defaultWindowName) + .and().showsAppWindowOnTop(pipApp.defaultWindowName) + .then() + .hidesAppWindow(testApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + all("Initially shows both app layers then pipApp hides testApp") { + showsLayer(testApp.defaultWindowName) + .and().showsLayer(pipApp.defaultWindowName) + .then() + .hidesLayer(testApp.defaultWindowName) + } + start("testApp covers the fullscreen, pipApp remains inside display") { + hasVisibleRegion(testApp.defaultWindowName, displayBounds) + coversAtMostRegion(displayBounds, pipApp.defaultWindowName) + } + end("pipApp covers the fullscreen") { + hasVisibleRegion(pipApp.defaultWindowName, displayBounds) + } + navBarLayerIsAlwaysVisible() + statusBarLayerIsAlwaysVisible() + } + } + } + } + + 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) } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index abb8fc52abbb..6c4e65818e49 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -16,28 +16,21 @@ package com.android.wm.shell.flicker.pip -import android.content.ComponentName -import android.graphics.Region -import android.util.Log import android.view.Surface -import android.view.WindowManager import androidx.test.filters.RequiresDevice -import com.android.compatibility.common.util.SystemUtil import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.dsl.runWithFlicker +import com.android.server.wm.flicker.helpers.WindowUtils 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 import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized -import java.io.IOException /** * Test Pip launch. @@ -50,9 +43,6 @@ class PipKeyboardTest( rotationName: String, rotation: Int ) : PipTestBase(rotationName, rotation) { - private val windowManager: WindowManager = - instrumentation.context.getSystemService(WindowManager::class.java) - private val keyboardApp = ImeAppHelper(instrumentation) private val keyboardScenario: FlickerBuilder @@ -71,7 +61,7 @@ class PipKeyboardTest( // 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(TEST_APP_IME_ACTIVITY_COMPONENT_NAME) + keyboardApp.launchViaIntent() } } teardown { @@ -103,10 +93,8 @@ class PipKeyboardTest( assertions { windowManagerTrace { all("PiP window must remain inside visible bounds") { - coversAtMostRegion( - partialWindowTitle = "PipActivity", - region = Region(windowManager.maximumWindowMetrics.bounds) - ) + val displayBounds = WindowUtils.getDisplayBounds(rotation) + coversAtMostRegion(testApp.defaultWindowName, displayBounds) } } } @@ -132,74 +120,13 @@ class PipKeyboardTest( assertions { windowManagerTrace { end { - isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME) + isAboveWindow(IME_WINDOW_NAME, testApp.defaultWindowName) } } } } } - private fun launchActivity( - activity: ComponentName? = null, - action: String? = null, - flags: Set<Int> = setOf(), - boolExtras: Map<String, Boolean> = mapOf(), - intExtras: Map<String, Int> = mapOf(), - stringExtras: Map<String, String> = mapOf() - ) { - require(activity != null || !action.isNullOrBlank()) { - "Cannot launch an activity with neither activity name nor action!" - } - val command = composeCommand( - "start", activity, action, flags, boolExtras, intExtras, stringExtras) - executeShellCommand(command) - } - - private fun composeCommand( - command: String, - activity: ComponentName?, - action: String?, - flags: Set<Int>, - boolExtras: Map<String, Boolean>, - intExtras: Map<String, Int>, - stringExtras: Map<String, String> - ): String = buildString { - append("am ") - append(command) - activity?.let { - append(" -n ") - append(it.flattenToShortString()) - } - action?.let { - append(" -a ") - append(it) - } - flags.forEach { - append(" -f ") - append(it) - } - boolExtras.forEach { - append(it.withFlag("ez")) - } - intExtras.forEach { - append(it.withFlag("ei")) - } - stringExtras.forEach { - append(it.withFlag("es")) - } - } - - private fun Map.Entry<String, *>.withFlag(flag: String): String = " --$flag $key $value" - - private fun executeShellCommand(cmd: String): String { - try { - return SystemUtil.runShellCommand(instrumentation, cmd) - } catch (e: IOException) { - Log.e("FlickerTests", "Error running shell command: $cmd") - throw e - } - } - companion object { private const val TEST_REPETITIONS = 10 diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt new file mode 100644 index 000000000000..322034ce7688 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt @@ -0,0 +1,203 @@ +/* + * 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.content.Intent +import android.view.Surface +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.dsl.runFlicker +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.helpers.PipAppHelper +import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP +import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION +import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_PIP_ORIENTATION +import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION +import org.junit.Assert.assertEquals +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 with orientation changes. + * To run this test: `atest WMShellFlickerTests:PipOrientationTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipOrientationTest( + rotationName: String, + rotation: Int +) : AppTestBase(rotationName, rotation) { + // Helper class to process test actions by broadcast. + private inner class BroadcastActionTrigger { + private fun createIntentWithAction(broadcastAction: String): Intent { + return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND) + } + fun doAction(broadcastAction: String) { + instrumentation.getContext().sendBroadcast(createIntentWithAction(broadcastAction)) + } + fun requestOrientationForPip(orientation: Int) { + instrumentation.getContext() + .sendBroadcast(createIntentWithAction(ACTION_SET_REQUESTED_ORIENTATION) + .putExtra(EXTRA_PIP_ORIENTATION, orientation.toString())) + } + } + private val broadcastActionTrigger = BroadcastActionTrigger() + + // Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + private val ORIENTATION_LANDSCAPE = 0 + // Corresponds to ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + private val ORIENTATION_PORTRAIT = 1 + + private val testApp = FixedAppHelper(instrumentation) + private val pipApp = PipAppHelper(instrumentation) + + @Test + fun testEnterPipToOtherOrientation() { + runFlicker(instrumentation) { + withTestName { "testEnterPipToOtherOrientation" } + setup { + test { + removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + // Launch a portrait only app on the fullscreen stack + testApp.launchViaIntent(stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())) + waitForAnimationComplete() + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())) + waitForAnimationComplete() + } + } + transitions { + // Enter PiP, and assert that the PiP is within bounds now that the device is back + // in portrait + broadcastActionTrigger.doAction(ACTION_ENTER_PIP) + waitForAnimationComplete() + } + teardown { + test { + removeAllTasksButHome() + } + } + assertions { + windowManagerTrace { + all("pipApp window is always on top") { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + start("pipApp window hides testApp") { + hidesAppWindow(testApp.defaultWindowName) + } + end("testApp windows is shown") { + showsAppWindow(testApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) + val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + start("pipApp layer hides testApp") { + hasVisibleRegion(pipApp.defaultWindowName, startingBounds) + hidesLayer(testApp.defaultWindowName) + } + end("testApp layer covers fullscreen") { + hasVisibleRegion(testApp.defaultWindowName, endingBounds) + } + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + } + } + } + } + + @Test + fun testSetRequestedOrientationWhilePinned() { + runFlicker(instrumentation) { + withTestName { "testSetRequestedOrientationWhilePinned" } + setup { + test { + removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(), + EXTRA_ENTER_PIP to "true")) + waitForAnimationComplete() + assertEquals(Surface.ROTATION_0, device.displayRotation) + } + } + transitions { + // Request that the orientation is set to landscape + broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE) + + // Launch the activity back into fullscreen and ensure that it is now in landscape + pipApp.launchViaIntent() + waitForAnimationComplete() + assertEquals(Surface.ROTATION_90, device.displayRotation) + } + teardown { + test { + removeAllTasksButHome() + } + } + assertions { + val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) + windowManagerTrace { + start("PIP window must remain inside display") { + coversAtMostRegion(pipApp.defaultWindowName, startingBounds) + } + end("pipApp shows on top") { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + start("PIP layer must remain inside display") { + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) + } + end("pipApp layer covers fullscreen") { + hasVisibleRegion(pipApp.defaultWindowName, endingBounds) + } + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + } + } + } + } + + 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) } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt new file mode 100644 index 000000000000..96d98d56e069 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -0,0 +1,127 @@ +/* + * 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.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.Flicker +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.buildTestTag +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.repetitions +import com.android.server.wm.flicker.startRotation +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.helpers.PipAppHelper +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 com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test Pip Stack in bounds after rotations. + * To run this test: `atest WMShellFlickerTests:PipRotationTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipRotationTest( + testName: String, + flickerSpec: Flicker +) : FlickerTestRunner(testName, flickerSpec) { + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val testApp = FixedAppHelper(instrumentation) + val pipApp = PipAppHelper(instrumentation) + return FlickerTestRunnerFactory(instrumentation, + listOf(Surface.ROTATION_0, Surface.ROTATION_90)) + .buildRotationTest { configuration -> + withTestName { buildTestTag("PipRotationTest", testApp, configuration) } + repeat { configuration.repetitions } + setup { + test { + AppTestBase.removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + pipApp.launchViaIntent(stringExtras = mapOf( + EXTRA_ENTER_PIP to "true")) + testApp.launchViaIntent() + AppTestBase.waitForAnimationComplete() + } + eachRun { + setRotation(configuration.startRotation) + } + } + transitions { + setRotation(configuration.endRotation) + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) + } + test { + AppTestBase.removeAllTasksButHome() + } + } + assertions { + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + noUncoveredRegions(configuration.startRotation, + configuration.endRotation, allStates = false) + navBarLayerRotatesAndScales(configuration.startRotation, + configuration.endRotation) + statusBarLayerRotatesScales(configuration.startRotation, + configuration.endRotation) + } + layersTrace { + val startingBounds = WindowUtils.getDisplayBounds( + configuration.startRotation) + val endingBounds = WindowUtils.getDisplayBounds( + configuration.endRotation) + start("appLayerRotates_StartingBounds") { + hasVisibleRegion(testApp.defaultWindowName, startingBounds) + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) + } + end("appLayerRotates_EndingBounds") { + hasVisibleRegion(testApp.defaultWindowName, endingBounds) + coversAtMostRegion(endingBounds, pipApp.defaultWindowName) + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt new file mode 100644 index 000000000000..d20552f0739d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt @@ -0,0 +1,127 @@ +/* + * 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.RequiresDevice +import com.android.server.wm.flicker.dsl.runFlicker +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.exitSplitScreen +import com.android.server.wm.flicker.helpers.isInSplitScreen +import com.android.server.wm.flicker.helpers.launchSplitScreen +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.helpers.ImeAppHelper +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.helpers.PipAppHelper +import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible +import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +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 with split-screen. + * To run this test: `atest WMShellFlickerTests:PipSplitScreenTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 161435597) +class PipSplitScreenTest( + rotationName: String, + rotation: Int +) : AppTestBase(rotationName, rotation) { + private val pipApp = PipAppHelper(instrumentation) + private val imeApp = ImeAppHelper(instrumentation) + private val testApp = FixedAppHelper(instrumentation) + + @Test + fun testShowsPipLaunchingToSplitScreen() { + runFlicker(instrumentation) { + withTestName { "testShowsPipLaunchingToSplitScreen" } + repeat { TEST_REPETITIONS } + setup { + test { + removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true")) + waitForAnimationComplete() + } + } + transitions { + testApp.launchViaIntent() + device.launchSplitScreen() + imeApp.launchViaIntent() + waitForAnimationComplete() + } + teardown { + eachRun { + imeApp.exit() + if (device.isInSplitScreen()) { + device.exitSplitScreen() + } + testApp.exit() + } + test { + removeAllTasksButHome() + } + } + assertions { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + windowManagerTrace { + all("PIP window must remain inside visible bounds") { + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + end("Both app windows should be visible") { + showsAppWindow(testApp.defaultWindowName) + showsAppWindow(imeApp.defaultWindowName) + noWindowsOverlap(testApp.defaultWindowName, imeApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + all("PIP layer must remain inside visible bounds") { + coversAtMostRegion(displayBounds, pipApp.defaultWindowName) + } + end("Both app layers should be visible") { + coversAtMostRegion(displayBounds, testApp.defaultWindowName) + coversAtMostRegion(displayBounds, imeApp.defaultWindowName) + } + navBarLayerIsAlwaysVisible() + statusBarLayerIsAlwaysVisible() + } + } + } + } + + companion object { + const val TEST_REPETITIONS = 2 + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val supportedRotations = intArrayOf(Surface.ROTATION_0) + return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt index c1c34ecfbaec..03a92119fc86 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt @@ -16,12 +16,11 @@ package com.android.wm.shell.flicker.pip -import com.android.wm.shell.flicker.NonRotationTestBase import com.android.wm.shell.flicker.helpers.PipAppHelper abstract class PipTestBase( rotationName: String, rotation: Int -) : NonRotationTestBase(rotationName, rotation) { +) : AppTestBase(rotationName, rotation) { protected val testApp = PipAppHelper(instrumentation) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt index 496fe94ba951..a3440df9ddf8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt @@ -17,11 +17,10 @@ package com.android.wm.shell.flicker.splitscreen import com.android.wm.shell.flicker.NonRotationTestBase -import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL -import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import com.android.wm.shell.flicker.testapp.Components abstract class SplitScreenTestBase( rotationName: String, @@ -29,8 +28,8 @@ abstract class SplitScreenTestBase( ) : NonRotationTestBase(rotationName, rotation) { protected val splitScreenApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_PRIMARY_LABEL, - TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME) + Components.SplitScreenActivity()) protected val secondaryApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_SECONDARY_LABEL, - TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME) + Components.SplitScreenSecondaryActivity()) } diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp index d12b49245277..26627a47ee62 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp @@ -18,3 +18,9 @@ android_test { sdk_version: "current", test_suites: ["device-tests"], } + +java_library { + name: "wmshell-flicker-test-components", + srcs: ["src/**/Components.java"], + sdk_version: "test_current", +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml index 628926a97bf5..a583b725899b 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml @@ -21,13 +21,25 @@ android:targetSdkVersion="29"/> <application android:allowBackup="false" android:supportsRtl="true"> + <activity android:name=".FixedActivity" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:launchMode="singleTop" + android:label="FixedApp" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> <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"> + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" + android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity" + android:launchMode="singleTop" + android:label="PipApp" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> @@ -39,9 +51,9 @@ </activity> <activity android:name=".ImeActivity" - android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity" - android:label="ImeApp" - android:exported="true"> + android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity" + android:label="ImeApp" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java new file mode 100644 index 000000000000..8e9b4cb2d53e --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java @@ -0,0 +1,82 @@ +/* + * 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.content.ComponentName; + +public class Components { + public abstract static class ComponentsInfo { + public ComponentName getComponentName() { + return ComponentName.createRelative(PACKAGE_NAME, "." + getActivityName()); + } + public abstract String getActivityName(); + } + + public static final String PACKAGE_NAME = "com.android.wm.shell.flicker.testapp"; + + public static class FixedActivity extends ComponentsInfo { + // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation} + public static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation"; + + @Override + public String getActivityName() { + return FixedActivity.class.getSimpleName(); + } + } + + public static class PipActivity extends ComponentsInfo { + // Intent action that this activity dynamically registers to enter picture-in-picture + public static final String ACTION_ENTER_PIP = PACKAGE_NAME + ".PipActivity.ENTER_PIP"; + // Intent action that this activity dynamically registers to set requested orientation. + // Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra. + public static final String ACTION_SET_REQUESTED_ORIENTATION = + PACKAGE_NAME + ".PipActivity.SET_REQUESTED_ORIENTATION"; + + // Calls enterPictureInPicture() on creation + public static final String EXTRA_ENTER_PIP = "enter_pip"; + // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation} + public static final String EXTRA_PIP_ORIENTATION = "fixed_orientation"; + // Adds a click listener to finish this activity when it is clicked + public static final String EXTRA_TAP_TO_FINISH = "tap_to_finish"; + + @Override + public String getActivityName() { + return PipActivity.class.getSimpleName(); + } + } + + public static class ImeActivity extends ComponentsInfo { + @Override + public String getActivityName() { + return ImeActivity.class.getSimpleName(); + } + } + + public static class SplitScreenActivity extends ComponentsInfo { + @Override + public String getActivityName() { + return SplitScreenActivity.class.getSimpleName(); + } + } + + public static class SplitScreenSecondaryActivity extends ComponentsInfo { + @Override + public String getActivityName() { + return SplitScreenSecondaryActivity.class.getSimpleName(); + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java new file mode 100644 index 000000000000..d4ae6c1313bf --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java @@ -0,0 +1,35 @@ +/* + * 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 static com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION; + +import android.os.Bundle; + +public class FixedActivity extends SimpleActivity { + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Set the fixed orientation if requested + if (getIntent().hasExtra(EXTRA_FIXED_ORIENTATION)) { + final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_FIXED_ORIENTATION)); + setRequestedOrientation(ori); + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java index 909219583bf7..a6ba7823e22d 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java @@ -24,6 +24,11 @@ import static android.media.session.PlaybackState.STATE_PAUSED; import static android.media.session.PlaybackState.STATE_PLAYING; import static android.media.session.PlaybackState.STATE_STOPPED; +import static com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP; +import static com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION; +import static com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP; +import static com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_PIP_ORIENTATION; + import android.app.Activity; import android.app.PendingIntent; import android.app.PictureInPictureParams; @@ -32,12 +37,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.graphics.drawable.Icon; import android.media.MediaMetadata; import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.os.Bundle; +import android.util.Log; import android.util.Rational; import android.view.View; import android.view.Window; @@ -50,6 +55,7 @@ import java.util.Collections; import java.util.List; public class PipActivity extends Activity { + private static final String TAG = PipActivity.class.getSimpleName(); /** * A media session title for when the session is in {@link STATE_PLAYING}. * TvPipNotificationTests check whether the actual notification title matches this string. @@ -88,27 +94,43 @@ public class PipActivity extends Activity { private final List<RemoteAction> mSwitchOffActions = new ArrayList<>(); private final List<RemoteAction> mSwitchOnActions = new ArrayList<>(); - private final BroadcastReceiver mCustomActionReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case ACTION_SWITCH_ON: - mPipParamsBuilder.setActions(mSwitchOnActions); - break; - case ACTION_SWITCH_OFF: - mPipParamsBuilder.setActions(mSwitchOffActions); - break; - case ACTION_CLEAR: - mPipParamsBuilder.setActions(Collections.emptyList()); - break; - case ACTION_NO_OP: - default: - return; + if (isInPictureInPictureMode()) { + switch (intent.getAction()) { + case ACTION_SWITCH_ON: + mPipParamsBuilder.setActions(mSwitchOnActions); + break; + case ACTION_SWITCH_OFF: + mPipParamsBuilder.setActions(mSwitchOffActions); + break; + case ACTION_CLEAR: + mPipParamsBuilder.setActions(Collections.emptyList()); + break; + case ACTION_NO_OP: + return; + default: + Log.w(TAG, "Unhandled action=" + intent.getAction()); + return; + } + setPictureInPictureParams(mPipParamsBuilder.build()); + } else { + switch (intent.getAction()) { + case ACTION_ENTER_PIP: + enterPip(null); + break; + case ACTION_SET_REQUESTED_ORIENTATION: + setRequestedOrientation(Integer.parseInt(intent.getStringExtra( + EXTRA_PIP_ORIENTATION))); + break; + default: + Log.w(TAG, "Unhandled action=" + intent.getAction()); + return; + } } - setPictureInPictureParams(mPipParamsBuilder.build()); } }; - private boolean mIsReceiverRegistered = false; @Override public void onCreate(Bundle savedInstanceState) { @@ -160,36 +182,25 @@ public class PipActivity extends Activity { final RemoteAction clearAllAction = buildRemoteAction(icon, PIP_ACTION_CLEAR, ACTION_CLEAR); mSwitchOffActions.addAll(Arrays.asList(switchOnAction, clearAllAction)); mSwitchOnActions.addAll(Arrays.asList(noOpAction, switchOffAction, clearAllAction)); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_NO_OP); + filter.addAction(ACTION_SWITCH_ON); + filter.addAction(ACTION_SWITCH_OFF); + filter.addAction(ACTION_CLEAR); + filter.addAction(ACTION_SET_REQUESTED_ORIENTATION); + filter.addAction(ACTION_ENTER_PIP); + registerReceiver(mBroadcastReceiver, filter); + + handleIntentExtra(getIntent()); } @Override protected void onDestroy() { - if (mIsReceiverRegistered) { - unregisterReceiver(mCustomActionReceiver); - mIsReceiverRegistered = false; - } + unregisterReceiver(mBroadcastReceiver); super.onDestroy(); } - @Override - public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, - Configuration newConfig) { - if (isInPictureInPictureMode && !mIsReceiverRegistered) { - final IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_NO_OP); - filter.addAction(ACTION_SWITCH_ON); - filter.addAction(ACTION_SWITCH_OFF); - filter.addAction(ACTION_CLEAR); - registerReceiver(mCustomActionReceiver, filter); - - mIsReceiverRegistered = true; - } else if (!isInPictureInPictureMode && mIsReceiverRegistered) { - unregisterReceiver(mCustomActionReceiver); - - mIsReceiverRegistered = false; - } - } - private RemoteAction buildRemoteAction(Icon icon, String label, String action) { final Intent intent = new Intent(action); final PendingIntent pendingIntent = @@ -254,4 +265,17 @@ public class PipActivity extends Activity { mMediaSession.setMetadata(mMediaMetadataBuilder.build()); mMediaSession.setActive(newState != STATE_STOPPED); } + + private void handleIntentExtra(Intent intent) { + // Set the fixed orientation if requested + if (intent.hasExtra(EXTRA_PIP_ORIENTATION)) { + final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_PIP_ORIENTATION)); + setRequestedOrientation(ori); + } + // Enter picture in picture with the given aspect ratio if provided + if (intent.hasExtra(EXTRA_ENTER_PIP)) { + mPipParamsBuilder.setActions(mSwitchOnActions); + enterPip(null); + } + } } |