summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yuncheol Heo <ycheo@google.com> 2020-11-27 00:26:45 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-11-27 00:26:45 +0000
commit5ba5c09b248ff252502f74d84b3ca22ccf0737b1 (patch)
treed06b5280856a077229a45f83249368b2f65d6375
parentbf598cdfbced87a281827e01e7b8dd0a07c99a01 (diff)
parent72800c90299eae30b590ad0e558bb853262414c2 (diff)
Merge "Migrate some CTS tests about PIP presentation to WMShellFlickerTests"
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt29
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt46
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt118
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt83
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt203
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt127
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt127
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml30
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java82
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java35
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java104
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);
+ }
+ }
}