diff options
Diffstat (limited to 'libs/WindowManager/Shell/tests/flicker')
77 files changed, 3017 insertions, 975 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index 9dd25fe0e6fe..3ca5b9c38aff 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -25,11 +25,17 @@ package { android_test { name: "WMShellFlickerTests", - srcs: ["src/**/*.java", "src/**/*.kt"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], manifest: "AndroidManifest.xml", test_config: "AndroidTest.xml", platform_apis: true, certificate: "platform", + optimize: { + enabled: false, + }, test_suites: ["device-tests"], libs: ["android.test.runner"], static_libs: [ diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml index e6d32ff1166f..06df9568e01a 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml @@ -42,6 +42,9 @@ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> <!-- ATM.removeRootTasksWithActivityTypes() --> <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> + <!-- Enable bubble notification--> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <!-- Allow the test to write directly to /sdcard/ --> <application android:requestLegacyExternalStorage="true"> <uses-library android:name="android.test.runner"/> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index c5b5b91d570b..c4be785cff19 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -14,100 +14,104 @@ * limitations under the License. */ +@file:JvmName("CommonAssertions") package com.android.wm.shell.flicker import android.graphics.Region import android.view.Surface import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.traces.layers.getVisibleBounds +import com.android.server.wm.traces.common.FlickerComponentName -fun FlickerTestParameter.appPairsDividerIsVisible() { +fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() { assertLayersEnd { - this.isVisible(APP_PAIR_SPLIT_DIVIDER) + this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) } } -fun FlickerTestParameter.appPairsDividerIsInvisible() { +fun FlickerTestParameter.appPairsDividerIsInvisibleAtEnd() { assertLayersEnd { - this.notContains(APP_PAIR_SPLIT_DIVIDER) + this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT) } } fun FlickerTestParameter.appPairsDividerBecomesVisible() { assertLayers { - this.isInvisible(DOCKED_STACK_DIVIDER) + this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT) .then() - .isVisible(DOCKED_STACK_DIVIDER) + .isVisible(DOCKED_STACK_DIVIDER_COMPONENT) } } -fun FlickerTestParameter.dockedStackDividerIsVisible() { +fun FlickerTestParameter.dockedStackDividerIsVisibleAtEnd() { assertLayersEnd { - this.isVisible(DOCKED_STACK_DIVIDER) + this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) } } fun FlickerTestParameter.dockedStackDividerBecomesVisible() { assertLayers { - this.isInvisible(DOCKED_STACK_DIVIDER) + this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT) .then() - .isVisible(DOCKED_STACK_DIVIDER) + .isVisible(DOCKED_STACK_DIVIDER_COMPONENT) } } fun FlickerTestParameter.dockedStackDividerBecomesInvisible() { assertLayers { - this.isVisible(DOCKED_STACK_DIVIDER) + this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) .then() - .isInvisible(DOCKED_STACK_DIVIDER) + .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT) } } -fun FlickerTestParameter.dockedStackDividerIsInvisible() { +fun FlickerTestParameter.dockedStackDividerNotExistsAtEnd() { assertLayersEnd { - this.notContains(DOCKED_STACK_DIVIDER) + this.notContains(DOCKED_STACK_DIVIDER_COMPONENT) } } -fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) { +fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd( + rotation: Int, + primaryComponent: FlickerComponentName +) { assertLayersEnd { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - visibleRegion(primaryLayerName) - .coversExactly(getPrimaryRegion(dividerRegion, rotation)) + val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(primaryComponent) + .overlaps(getPrimaryRegion(dividerRegion, rotation)) } } -fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisible( +fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd( rotation: Int, - primaryLayerName: String + primaryComponent: FlickerComponentName ) { assertLayersEnd { - val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) - visibleRegion(primaryLayerName) - .coversExactly(getPrimaryRegion(dividerRegion, rotation)) + val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(primaryComponent) + .overlaps(getPrimaryRegion(dividerRegion, rotation)) } } -fun FlickerTestParameter.appPairsSecondaryBoundsIsVisible( +fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd( rotation: Int, - secondaryLayerName: String + secondaryComponent: FlickerComponentName ) { assertLayersEnd { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - visibleRegion(secondaryLayerName) - .coversExactly(getSecondaryRegion(dividerRegion, rotation)) + val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(secondaryComponent) + .overlaps(getSecondaryRegion(dividerRegion, rotation)) } } -fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisible( +fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisibleAtEnd( rotation: Int, - secondaryLayerName: String + secondaryComponent: FlickerComponentName ) { assertLayersEnd { - val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) - visibleRegion(secondaryLayerName) - .coversExactly(getSecondaryRegion(dividerRegion, rotation)) + val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(secondaryComponent) + .overlaps(getSecondaryRegion(dividerRegion, rotation)) } } 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 03b93c74233c..40891f36a5da 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 @@ -14,9 +14,11 @@ * limitations under the License. */ +@file:JvmName("CommonConstants") package com.android.wm.shell.flicker -const val IME_WINDOW_NAME = "InputMethod" +import com.android.server.wm.traces.common.FlickerComponentName + const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" -const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider" -const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
\ No newline at end of file +val APP_PAIR_SPLIT_DIVIDER_COMPONENT = FlickerComponentName("", "AppPairSplitDivider#") +val DOCKED_STACK_DIVIDER_COMPONENT = FlickerComponentName("", "DockedStackDivider#")
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt index a6d67355f271..b63d9fffdb61 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:JvmName("WaitUtils") package com.android.wm.shell.flicker import android.os.SystemClock diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt index ef9f7421fd60..038be9c190c2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.apppairs -import android.os.SystemClock import android.platform.test.annotations.Presubmit import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice @@ -25,7 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.wm.shell.flicker.appPairsDividerIsInvisible +import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow @@ -61,7 +60,7 @@ class AppPairsTestCannotPairNonResizeableApps( // TODO pair apps through normal UX flow executeShellCommand( composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) } } } @@ -85,15 +84,13 @@ class AppPairsTestCannotPairNonResizeableApps( @Test override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales() - @FlakyTest + @Presubmit @Test - override fun navBarLayerIsAlwaysVisible() { - super.navBarLayerIsAlwaysVisible() - } + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() @Presubmit @Test - fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible() + fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd() @Presubmit @Test @@ -103,8 +100,8 @@ class AppPairsTestCannotPairNonResizeableApps( "Non resizeable app not initialized" } testSpec.assertWmEnd { - isVisible(nonResizeableApp.defaultWindowName) - isInvisible(primaryApp.defaultWindowName) + isAppWindowVisible(nonResizeableApp.component) + isAppWindowInvisible(primaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt index db63c4c43523..bbc6b2dbece8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.apppairs -import android.os.SystemClock import android.platform.test.annotations.Presubmit import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice @@ -25,10 +24,10 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.traces.layers.getVisibleBounds -import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER -import com.android.wm.shell.flicker.appPairsDividerIsVisible +import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.AppPairsHelper +import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -54,10 +53,14 @@ class AppPairsTestPairPrimaryAndSecondaryApps( // TODO pair apps through normal UX flow executeShellCommand( composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + waitAppsShown(primaryApp, secondaryApp) } } + @Presubmit + @Test + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() + @FlakyTest @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() @@ -68,14 +71,14 @@ class AppPairsTestPairPrimaryAndSecondaryApps( @Presubmit @Test - fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd() @Presubmit @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.defaultWindowName) - isVisible(secondaryApp.defaultWindowName) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } @@ -83,10 +86,10 @@ class AppPairsTestPairPrimaryAndSecondaryApps( @Test fun appsEndingBounds() { testSpec.assertLayersEnd { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - visibleRegion(primaryApp.defaultWindowName) + val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(primaryApp.component) .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion)) - visibleRegion(secondaryApp.defaultWindowName) + visibleRegion(secondaryApp.component) .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion)) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt index c8d34237231c..bb784a809b7e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.apppairs -import android.os.SystemClock import android.platform.test.annotations.Presubmit import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice @@ -25,7 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.wm.shell.flicker.appPairsDividerIsVisible +import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow @@ -61,7 +60,7 @@ class AppPairsTestSupportPairNonResizeableApps( // TODO pair apps through normal UX flow executeShellCommand( composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) } } } @@ -77,6 +76,10 @@ class AppPairsTestSupportPairNonResizeableApps( resetMultiWindowConfig(instrumentation) } + @Presubmit + @Test + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() + @FlakyTest @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() @@ -87,7 +90,7 @@ class AppPairsTestSupportPairNonResizeableApps( @Presubmit @Test - fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd() @Presubmit @Test @@ -97,8 +100,8 @@ class AppPairsTestSupportPairNonResizeableApps( "Non resizeable app not initialized" } testSpec.assertWmEnd { - isVisible(nonResizeableApp.defaultWindowName) - isVisible(primaryApp.defaultWindowName) + isAppWindowVisible(nonResizeableApp.component) + isAppWindowVisible(primaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt index 83df83600d11..a1a4db112dfd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt @@ -25,10 +25,10 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.traces.layers.getVisibleBounds -import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER -import com.android.wm.shell.flicker.appPairsDividerIsInvisible +import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd import com.android.wm.shell.flicker.helpers.AppPairsHelper +import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -51,9 +51,11 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps( get() = { super.transition(this, it) setup { - executeShellCommand( - composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + eachRun { + executeShellCommand( + composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) + waitAppsShown(primaryApp, secondaryApp) + } } transitions { // TODO pair apps through normal UX flow @@ -73,14 +75,14 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps( @Presubmit @Test - fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible() + fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd() @Presubmit @Test fun bothAppWindowsInvisible() { testSpec.assertWmEnd { - isInvisible(primaryApp.defaultWindowName) - isInvisible(secondaryApp.defaultWindowName) + isAppWindowInvisible(primaryApp.component) + isAppWindowInvisible(secondaryApp.component) } } @@ -88,10 +90,10 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps( @Test fun appsStartingBounds() { testSpec.assertLayersStart { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - visibleRegion(primaryApp.defaultWindowName) + val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region + visibleRegion(primaryApp.component) .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion)) - visibleRegion(secondaryApp.defaultWindowName) + visibleRegion(secondaryApp.component) .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion)) } } @@ -100,16 +102,14 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps( @Test fun appsEndingBounds() { testSpec.assertLayersEnd { - notContains(primaryApp.defaultWindowName) - notContains(secondaryApp.defaultWindowName) + notContains(primaryApp.component) + notContains(secondaryApp.component) } } - @FlakyTest + @Presubmit @Test - override fun navBarLayerIsAlwaysVisible() { - super.navBarLayerIsAlwaysVisible() - } + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt index 1935bb97849c..9e20bbbc1a1b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt @@ -20,24 +20,23 @@ import android.app.Instrumentation import android.content.Context import android.platform.test.annotations.Presubmit import android.system.helpers.ActivityHelper -import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerBuilderProvider import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.BaseAppHelper import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow @@ -55,7 +54,7 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) protected val activityHelper = ActivityHelper.getInstance() protected val appPairsHelper = AppPairsHelper(instrumentation, Components.SplitScreenActivity.LABEL, - Components.SplitScreenActivity.COMPONENT) + Components.SplitScreenActivity.COMPONENT.toFlickerComponent()) protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation) protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) @@ -154,39 +153,33 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) @FlakyTest(bugId = 186510496) @Test - open fun navBarLayerIsAlwaysVisible() { - testSpec.navBarLayerIsAlwaysVisible() + open fun navBarLayerIsVisible() { + testSpec.navBarLayerIsVisible() } @Presubmit @Test - open fun statusBarLayerIsAlwaysVisible() { - testSpec.statusBarLayerIsAlwaysVisible() + open fun statusBarLayerIsVisible() { + testSpec.statusBarLayerIsVisible() } @Presubmit @Test - open fun navBarWindowIsAlwaysVisible() { - testSpec.navBarWindowIsAlwaysVisible() + open fun navBarWindowIsVisible() { + testSpec.navBarWindowIsVisible() } @Presubmit @Test - open fun statusBarWindowIsAlwaysVisible() { - testSpec.statusBarWindowIsAlwaysVisible() + open fun statusBarWindowIsVisible() { + testSpec.statusBarWindowIsVisible() } @Presubmit @Test - open fun navBarLayerRotatesAndScales() { - testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, - testSpec.config.endRotation) - } + open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() @Presubmit @Test - open fun statusBarLayerRotatesScales() { - testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, - testSpec.config.endRotation) - } + open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt index c875c0006703..56a2531a3fe1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.apppairs -import android.os.SystemClock import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -28,10 +27,10 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.setRotation -import com.android.wm.shell.flicker.appPairsDividerIsVisible -import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible -import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible -import com.android.wm.shell.flicker.helpers.AppPairsHelper +import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -57,41 +56,43 @@ class RotateTwoLaunchedAppsInAppPairsMode( transitions { executeShellCommand(composePairsCommand( primaryTaskId, secondaryTaskId, true /* pair */)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + waitAppsShown(primaryApp, secondaryApp) setRotation(testSpec.config.endRotation) } } - @FlakyTest + @Presubmit @Test - override fun statusBarLayerIsAlwaysVisible() { - super.statusBarLayerIsAlwaysVisible() - } + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() + + @Presubmit + @Test + override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible() @Presubmit @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.defaultWindowName) - .isVisible(secondaryApp.defaultWindowName) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } @Presubmit @Test - fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd() - @FlakyTest(bugId = 172776659) + @Presubmit @Test - fun appPairsPrimaryBoundsIsVisible() = - testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation, - primaryApp.defaultWindowName) + fun appPairsPrimaryBoundsIsVisibleAtEnd() = + testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.config.endRotation, + primaryApp.component) - @FlakyTest(bugId = 172776659) + @FlakyTest @Test - fun appPairsSecondaryBoundsIsVisible() = - testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation, - secondaryApp.defaultWindowName) + fun appPairsSecondaryBoundsIsVisibleAtEnd() = + testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.config.endRotation, + secondaryApp.component) companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt index c3360ca0f7d3..0699a4fd0512 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.apppairs -import android.os.SystemClock import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -28,12 +27,10 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.appPairsDividerIsVisible -import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible -import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible -import com.android.wm.shell.flicker.helpers.AppPairsHelper +import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -60,48 +57,50 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode( this.setRotation(testSpec.config.endRotation) executeShellCommand( composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + waitAppsShown(primaryApp, secondaryApp) } } @Presubmit @Test - fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd() @Presubmit @Test - override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + override fun navBarWindowIsVisible() = super.navBarWindowIsVisible() @Presubmit @Test - override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() - @FlakyTest + @Presubmit @Test - override fun statusBarLayerIsAlwaysVisible() { - super.statusBarLayerIsAlwaysVisible() - } + override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible() + + @Presubmit + @Test + override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible() @Presubmit @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.defaultWindowName) - isVisible(secondaryApp.defaultWindowName) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } @FlakyTest(bugId = 172776659) @Test - fun appPairsPrimaryBoundsIsVisible() = - testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation, - primaryApp.defaultWindowName) + fun appPairsPrimaryBoundsIsVisibleAtEnd() = + testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.config.endRotation, + primaryApp.component) @FlakyTest(bugId = 172776659) @Test - fun appPairsSecondaryBoundsIsVisible() = - testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation, - secondaryApp.defaultWindowName) + fun appPairsSecondaryBoundsIsVisibleAtEnd() = + testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.config.endRotation, + secondaryApp.component) companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt index 512fd9a58ea8..b95193a17265 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt @@ -22,7 +22,10 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import org.junit.Assume.assumeFalse +import org.junit.Before import org.junit.Test abstract class RotateTwoLaunchedAppsTransition( @@ -37,8 +40,8 @@ abstract class RotateTwoLaunchedAppsTransition( test { device.wakeUpAndGoToHomeScreen() this.setRotation(Surface.ROTATION_0) - primaryApp.launchViaIntent() - secondaryApp.launchViaIntent() + primaryApp.launchViaIntent(wmHelper) + secondaryApp.launchViaIntent(wmHelper) updateTasksId() } } @@ -52,10 +55,17 @@ abstract class RotateTwoLaunchedAppsTransition( } } + @Before + override fun setup() { + // AppPairs hasn't been updated to Shell Transition. There will be conflict on rotation. + assumeFalse(isShellTransitionsEnabled()) + super.setup() + } + @FlakyTest @Test - override fun navBarLayerIsAlwaysVisible() { - super.navBarLayerIsAlwaysVisible() + override fun navBarLayerIsVisible() { + super.navBarLayerIsVisible() } @FlakyTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt new file mode 100644 index 000000000000..322d8b5e4dac --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 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.bubble + +import android.app.INotificationManager +import android.app.Instrumentation +import android.app.NotificationManager +import android.content.Context +import android.os.ServiceManager +import android.view.Surface +import androidx.test.filters.FlakyTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiObject2 +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE +import com.android.server.wm.flicker.repetitions +import com.android.wm.shell.flicker.helpers.LaunchBubbleHelper +import org.junit.Test +import org.junit.runners.Parameterized + +/** + * Base configurations for Bubble flicker tests + */ +abstract class BaseBubbleScreen(protected val testSpec: FlickerTestParameter) { + + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected val context: Context = instrumentation.context + protected val testApp = LaunchBubbleHelper(instrumentation) + + protected val notifyManager = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)) + + protected val packageManager = context.getPackageManager() + protected val uid = packageManager.getApplicationInfo( + testApp.component.packageName, 0).uid + + protected lateinit var addBubbleBtn: UiObject2 + protected lateinit var cancelAllBtn: UiObject2 + + protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + + @JvmOverloads + protected open fun buildTransition( + extraSpec: FlickerBuilder.(Map<String, Any?>) -> Unit = {} + ): FlickerBuilder.(Map<String, Any?>) -> Unit { + return { configuration -> + + setup { + test { + notifyManager.setBubblesAllowed(testApp.component.packageName, + uid, NotificationManager.BUBBLE_PREFERENCE_ALL) + testApp.launchViaIntent(wmHelper) + addBubbleBtn = device.wait(Until.findObject( + By.text("Add Bubble")), FIND_OBJECT_TIMEOUT) + cancelAllBtn = device.wait(Until.findObject( + By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT) + } + } + + teardown { + notifyManager.setBubblesAllowed(testApp.component.packageName, + uid, NotificationManager.BUBBLE_PREFERENCE_NONE) + testApp.exit() + } + + extraSpec(this, configuration) + } + } + + @FlakyTest + @Test + fun testAppIsAlwaysVisible() { + testSpec.assertLayers { + this.isVisible(testApp.component) + } + } + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + repeat { testSpec.config.repetitions } + transition(this, testSpec.config) + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) + } + + const val FIND_OBJECT_TIMEOUT = 2000L + const val SYSTEM_UI_PACKAGE = SYSTEMUI_PACKAGE + const val BUBBLE_RES_NAME = "bubble_view" + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt new file mode 100644 index 000000000000..bfdcb363a818 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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.bubble + +import android.content.Context +import android.graphics.Point +import android.util.DisplayMetrics +import android.view.WindowManager +import androidx.test.filters.RequiresDevice +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.annotation.Group4 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +/** + * Test launching a new activity from bubble. + * + * To run this test: `atest WMShellFlickerTests:DismissBubbleScreen` + * + * Actions: + * Dismiss a bubble notification + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@Group4 +class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { + + val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + val displaySize = DisplayMetrics() + + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition() { + setup { + eachRun { + addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found") + } + } + transitions { + wm?.run { wm.getDefaultDisplay().getMetrics(displaySize) } ?: error("WM not found") + val dist = Point((displaySize.widthPixels / 2), displaySize.heightPixels) + val showBubble = device.wait(Until.findObject( + By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT) + showBubble?.run { drag(dist, 1000) } ?: error("Show bubble not found") + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt new file mode 100644 index 000000000000..42eeadf3ddd9 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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.bubble + +import androidx.test.filters.RequiresDevice +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.annotation.Group4 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +/** + * Test launching a new activity from bubble. + * + * To run this test: `atest WMShellFlickerTests:ExpandBubbleScreen` + * + * Actions: + * Launch an app and enable app's bubble notification + * Send a bubble notification + * The activity for the bubble is launched + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@Group4 +class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { + + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition() { + setup { + test { + addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Bubble widget not found") + } + } + transitions { + val showBubble = device.wait(Until.findObject( + By.res("com.android.systemui", "bubble_view")), FIND_OBJECT_TIMEOUT) + showBubble?.run { showBubble.click() } ?: error("Bubble notify not found") + device.pressBack() + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt index cf84a2c696d0..47e8c0c047a8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -14,47 +14,35 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.bubble -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder -import org.junit.FixMethodOrder -import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test Pip launch. - * To run this test: `atest WMShellFlickerTests:PipCloseWithDismissButton` + * Test creating a bubble notification + * + * To run this test: `atest WMShellFlickerTests:LaunchBubbleScreen` + * + * Actions: + * Launch an app and enable app's bubble notification + * Send a bubble notification */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 -class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) { +@Group4 +class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit - get() = { - super.transition(this, it) + get() = buildTransition() { transitions { - pipApp.closePipWindow(wmHelper) + addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Bubble widget not found") } } - - @FlakyTest - @Test - override fun pipLayerBecomesInvisible() { - super.pipLayerBecomesInvisible() - } - - @FlakyTest - @Test - override fun pipWindowBecomesInvisible() { - super.pipWindowBecomesInvisible() - } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt new file mode 100644 index 000000000000..194e28fd6e8a --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 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.bubble + +import android.os.SystemClock +import androidx.test.filters.RequiresDevice +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.annotation.Group4 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +/** + * Test launching a new activity from bubble. + * + * To run this test: `atest WMShellFlickerTests:MultiBubblesScreen` + * + * Actions: + * Switch in different bubble notifications + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@Group4 +class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { + + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition() { + setup { + test { + for (i in 1..3) { + addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found") + } + val showBubble = device.wait(Until.findObject( + By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT) + showBubble?.run { showBubble.click() } ?: error("Show bubble not found") + SystemClock.sleep(1000) + } + } + transitions { + val bubbles = device.wait(Until.findObjects( + By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT) + for (entry in bubbles) { + entry?.run { entry.click() } ?: error("Bubble not found") + SystemClock.sleep(1000) + } + } + } +} 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 5b8cfb81016a..623055f659b9 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,14 +17,15 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.graphics.Region +import com.android.server.wm.flicker.Flicker import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.traces.common.FlickerComponentName class AppPairsHelper( instrumentation: Instrumentation, activityLabel: String, - component: ComponentName + component: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, component) { fun getPrimaryBounds(dividerBounds: Region): android.graphics.Region { val primaryAppBounds = Region(0, 0, dividerBounds.bounds.right, @@ -43,5 +44,17 @@ class AppPairsHelper( companion object { const val TEST_REPETITIONS = 1 const val TIMEOUT_MS = 3_000L + + fun Flicker.waitAppsShown(app1: SplitScreenHelper?, app2: SplitScreenHelper?) { + wmHelper.waitFor("primaryAndSecondaryAppsVisible") { dump -> + val primaryAppVisible = app1?.let { + dump.wmState.isWindowSurfaceShown(app1.defaultWindowName) + } ?: false + val secondaryAppVisible = app2?.let { + dump.wmState.isWindowSurfaceShown(app2.defaultWindowName) + } ?: false + primaryAppVisible && secondaryAppVisible + } + } } } 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 4fe69ad7fabe..57bc0d580d72 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,9 +17,9 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.pm.PackageManager.FEATURE_LEANBACK import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY +import android.os.SystemProperties import android.support.test.launcherhelper.LauncherStrategyFactory import android.util.Log import androidx.test.uiautomator.By @@ -27,13 +27,13 @@ import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until import com.android.compatibility.common.util.SystemUtil import com.android.server.wm.flicker.helpers.StandardAppHelper -import com.android.server.wm.traces.parser.toWindowName +import com.android.server.wm.traces.common.FlickerComponentName import java.io.IOException abstract class BaseAppHelper( instrumentation: Instrumentation, launcherName: String, - component: ComponentName + component: FlickerComponentName ) : StandardAppHelper( instrumentation, launcherName, @@ -60,6 +60,9 @@ abstract class BaseAppHelper( companion object { private const val APP_CLOSE_WAIT_TIME_MS = 3_000L + fun isShellTransitionsEnabled() = + SystemProperties.getBoolean("persist.debug.shell_transit", false) + fun executeShellCommand(instrumentation: Instrumentation, cmd: String) { try { SystemUtil.runShellCommand(instrumentation, cmd) 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 index b4ae18749b34..471e010cf560 100644 --- 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 @@ -17,10 +17,11 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class FixedAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.FixedActivity.LABEL, - Components.FixedActivity.COMPONENT + Components.FixedActivity.COMPONENT.toFlickerComponent() )
\ 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 cac46fe676b3..0f00edea136f 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,13 +21,14 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.FIND_TIMEOUT +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.testapp.Components open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.ImeActivity.LABEL, - Components.ImeActivity.COMPONENT + Components.ImeActivity.COMPONENT.toFlickerComponent() ) { /** * Opens the IME and wait for it to be displayed @@ -61,7 +62,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( if (wmHelper == null) { device.waitForIdle() } else { - require(wmHelper.waitImeWindowShown()) { "IME did not appear" } + require(wmHelper.waitImeShown()) { "IME did not appear" } } } @@ -78,7 +79,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( if (wmHelper == null) { uiDevice.waitForIdle() } else { - require(wmHelper.waitImeWindowGone()) { "IME did did not close" } + require(wmHelper.waitImeGone()) { "IME did did not close" } } } else { // While pressing the back button should close the IME on TV as well, it may also lead diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt index 0037059e2c51..6695c17ed514 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt @@ -14,16 +14,20 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.helpers -import android.content.ComponentName -import com.android.server.wm.traces.common.windowmanager.WindowManagerState -import com.android.server.wm.traces.parser.toWindowName +import android.app.Instrumentation +import com.android.server.wm.traces.parser.toFlickerComponent +import com.android.wm.shell.flicker.testapp.Components -/** - * Checks that an activity [activity] is in PIP mode - */ -fun WindowManagerState.isInPipMode(activity: ComponentName): Boolean { - val windowName = activity.toWindowName() - return isInPipMode(windowName) +class LaunchBubbleHelper(instrumentation: Instrumentation) : BaseAppHelper( + instrumentation, + Components.LaunchBubbleActivity.LABEL, + Components.LaunchBubbleActivity.COMPONENT.toFlickerComponent() +) { + + companion object { + const val TEST_REPETITIONS = 1 + const val TIMEOUT_MS = 3_000L + } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt index 7f99e62b36b0..12ccbafce651 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt @@ -17,14 +17,14 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.Context import android.provider.Settings +import com.android.server.wm.traces.common.FlickerComponentName class MultiWindowHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: ComponentName + componentsInfo: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { companion object { 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 f4dd7decb1b7..2357b0debb33 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 @@ -17,12 +17,16 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import android.graphics.Rect import android.media.session.MediaController import android.media.session.MediaSessionManager import android.os.SystemClock import androidx.test.uiautomator.By import androidx.test.uiautomator.BySelector +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.helpers.FIND_TIMEOUT import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow import com.android.wm.shell.flicker.pip.tv.isFocusedOrHasFocusedChild @@ -31,7 +35,7 @@ import com.android.wm.shell.flicker.testapp.Components class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.PipActivity.LABEL, - Components.PipActivity.COMPONENT + Components.PipActivity.COMPONENT.toFlickerComponent() ) { private val mediaSessionManager: MediaSessionManager get() = context.getSystemService(MediaSessionManager::class.java) @@ -62,7 +66,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( stringExtras: Map<String, String> ) { super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras) - wmHelper.waitFor { it.wmState.hasPipWindow() } + wmHelper.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } } private fun focusOnObject(selector: BySelector): Boolean { @@ -84,7 +88,11 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( clickObject(ENTER_PIP_BUTTON_ID) // Wait on WMHelper or simply wait for 3 seconds - wmHelper?.waitFor { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000) + wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000) + // when entering pip, the dismiss button is visible at the start. to ensure the pip + // animation is complete, wait until the pip dismiss button is no longer visible. + // b/176822698: dismiss-only state will be removed in the future + uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT) } fun clickStartMediaSessionButton() { @@ -113,61 +121,61 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( } } + private fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect { + val windowRegion = wmHelper.getWindowRegion(component) + require(!windowRegion.isEmpty) { + "Unable to find a PIP window in the current state" + } + return windowRegion.bounds + } + /** - * Expands the pip window and dismisses it by clicking on the X button. - * - * Note, currently the View coordinates reported by the accessibility are relative to - * the window, so the correct coordinates need to be calculated - * - * For example, in a PIP window located at Rect(508, 1444 - 1036, 1741), the - * dismiss button coordinates are shown as Rect(650, 0 - 782, 132), with center in - * Point(716, 66), instead of Point(970, 1403) - * - * See b/179337864 + * Taps the pip window and dismisses it by clicking on the X button. */ fun closePipWindow(wmHelper: WindowManagerStateHelper) { if (isTelevision) { uiDevice.closeTvPipWindow() } else { - expandPipWindow(wmHelper) - val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss")) - requireNotNull(exitPipObject) { "PIP window dismiss button not found" } - val dismissButtonBounds = exitPipObject.visibleBounds + val windowRect = getWindowRect(wmHelper) + uiDevice.click(windowRect.centerX(), windowRect.centerY()) + // search and interact with the dismiss button + val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") + uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) + val dismissPipObject = uiDevice.findObject(dismissSelector) + ?: error("PIP window dismiss button not found") + val dismissButtonBounds = dismissPipObject.visibleBounds uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY()) } // Wait for animation to complete. - wmHelper.waitFor { !it.wmState.hasPipWindow() } + wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() } wmHelper.waitForHomeActivityVisible() } /** - * Click once on the PIP window to expand it + * Close the pip window by pressing the expand button */ - fun expandPipWindow(wmHelper: WindowManagerStateHelper) { - val windowRegion = wmHelper.getWindowRegion(component) - require(!windowRegion.isEmpty) { - "Unable to find a PIP window in the current state" - } - val windowRect = windowRegion.bounds + fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) { + val windowRect = getWindowRect(wmHelper) uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // Ensure WindowManagerService wait until all animations have completed + // search and interact with the expand button + val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button") + uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT) + val expandPipObject = uiDevice.findObject(expandSelector) + ?: error("PIP window expand button not found") + val expandButtonBounds = expandPipObject.visibleBounds + uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY()) + wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() } wmHelper.waitForAppTransitionIdle() - mInstrumentation.uiAutomation.syncInputTransactions() } /** - * Double click on the PIP window to reopen to app + * Double click on the PIP window to expand it */ - fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) { - val windowRegion = wmHelper.getWindowRegion(component) - require(!windowRegion.isEmpty) { - "Unable to find a PIP window in the current state" - } - val windowRect = windowRegion.bounds + fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) { + val windowRect = getWindowRect(wmHelper) uiDevice.click(windowRect.centerX(), windowRect.centerY()) uiDevice.click(windowRect.centerX(), windowRect.centerY()) - wmHelper.waitFor { !it.wmState.hasPipWindow() } wmHelper.waitForAppTransitionIdle() } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt index ba13e38ae9e3..4d0fbc4a0e38 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt @@ -17,10 +17,11 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class SimpleAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.SimpleActivity.LABEL, - Components.SimpleActivity.COMPONENT + Components.SimpleActivity.COMPONENT.toFlickerComponent() )
\ No newline at end of file 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 901b7a393291..0ec9b2d869a8 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,32 +17,39 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName +import android.content.res.Resources +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class SplitScreenHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: ComponentName + componentsInfo: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { companion object { const val TEST_REPETITIONS = 1 const val TIMEOUT_MS = 3_000L + // TODO: remove all legacy split screen flicker tests when legacy split screen is fully + // deprecated. + fun isUsingLegacySplit(): Boolean = + Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useLegacySplit) + fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.SplitScreenActivity.LABEL, - Components.SplitScreenActivity.COMPONENT) + Components.SplitScreenActivity.COMPONENT.toFlickerComponent()) fun getSecondary(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.SplitScreenSecondaryActivity.LABEL, - Components.SplitScreenSecondaryActivity.COMPONENT) + Components.SplitScreenSecondaryActivity.COMPONENT.toFlickerComponent()) fun getNonResizeable(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.NonResizeableActivity.LABEL, - Components.NonResizeableActivity.COMPONENT) + Components.NonResizeableActivity.COMPONENT.toFlickerComponent()) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt index 4f12f2bb9f5f..bd44d082a1aa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt @@ -18,20 +18,21 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.platform.test.annotations.Presubmit import android.view.Surface +import android.view.WindowManagerPolicyConstants +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.HOME_WINDOW_TITLE -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -48,7 +49,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class EnterSplitScreenDockActivity( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -60,16 +61,16 @@ class EnterSplitScreenDockActivity( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, LIVE_WALLPAPER_PACKAGE_NAME, - splitScreenApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *HOME_WINDOW_TITLE) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT, + splitScreenApp.component, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, LAUNCHER_COMPONENT) @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = - testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, - splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + splitScreenApp.component) @Presubmit @Test @@ -77,27 +78,39 @@ class EnterSplitScreenDockActivity( @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(splitScreenApp.defaultWindowName) + isAppWindowVisible(splitScreenApp.component) } } + @FlakyTest + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 + supportedRotations = listOf(Surface.ROTATION_0), // bugId = 179116910 + supportedNavigationModes = listOf( + WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt index f91f634a00e5..625d48b8ab5a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt @@ -22,10 +22,11 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -42,6 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@Group4 class EnterSplitScreenFromDetachedRecentTask( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -61,24 +63,34 @@ class EnterSplitScreenFromDetachedRecentTask( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, - splitScreenApp.defaultWindowName) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + splitScreenApp.component) @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(splitScreenApp.defaultWindowName) + isAppWindowVisible(splitScreenApp.component) } } + @Presubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt index 85ded8a45233..2ed2806af528 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt @@ -22,18 +22,17 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 -import com.android.server.wm.flicker.appWindowBecomesVisible +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -49,7 +48,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class EnterSplitScreenLaunchToSide( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -62,22 +61,22 @@ class EnterSplitScreenLaunchToSide( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, + secondaryApp.component, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = - testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, - splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + splitScreenApp.component) @Presubmit @Test - fun dockedStackSecondaryBoundsIsVisible() = - testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, - secondaryApp.defaultWindowName) + fun dockedStackSecondaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + secondaryApp.component) @Presubmit @Test @@ -85,15 +84,35 @@ class EnterSplitScreenLaunchToSide( @Presubmit @Test - fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + fun appWindowBecomesVisible() { + testSpec.assertWm { + // when the app is launched, first the activity becomes visible, then the + // SnapshotStartingWindow appears and then the app window becomes visible. + // Because we log WM once per frame, sometimes the activity and the window + // become visible in the same entry, sometimes not, thus it is not possible to + // assert the visibility of the activity here + this.isAppWindowInvisible(secondaryApp.component) + .then() + // during re-parenting, the window may disappear and reappear from the + // trace, this occurs because we log only 1x per frame + .notContains(secondaryApp.component, isOptional = true) + .then() + .isAppWindowVisible(secondaryApp.component) + } + } + + @Presubmit + @Test + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt index e958bf39930e..ee6cf341c9ff 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt @@ -22,11 +22,11 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.canSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.dockedStackDividerIsInvisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -50,7 +50,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group1 +@Group4 class EnterSplitScreenNotSupportNonResizable( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -70,12 +70,12 @@ class EnterSplitScreenNotSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + nonResizeableApp.component, + splitScreenApp.component) @Before override fun setup() { @@ -91,7 +91,12 @@ class EnterSplitScreenNotSupportNonResizable( @Presubmit @Test - fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible() + fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt index d3acc82121b0..163b6ffda6e2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt @@ -25,8 +25,8 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -67,12 +67,12 @@ class EnterSplitScreenSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + nonResizeableApp.component, + splitScreenApp.component) @Before override fun setup() { @@ -88,16 +88,21 @@ class EnterSplitScreenSupportNonResizable( @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(nonResizeableApp.defaultWindowName) + isAppWindowVisible(nonResizeableApp.component) } } + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt index bad46836dcb7..2b629b0a7eb5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.Postsubmit import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice @@ -24,15 +24,13 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.layerBecomesInvisible -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER +import com.android.server.wm.flicker.navBarWindowIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -67,31 +65,52 @@ class ExitLegacySplitScreenFromBottom( } } transitions { - device.exitSplitScreenFromBottom() + device.exitSplitScreenFromBottom(wmHelper) } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, WindowManagerStateHelper.SPLASH_SCREEN_NAME, - splitScreenApp.defaultWindowName, secondaryApp.defaultWindowName, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, + splitScreenApp.component, secondaryApp.component, + FlickerComponentName.SNAPSHOT) - @Presubmit + @Postsubmit @Test - fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(DOCKED_STACK_DIVIDER) + fun layerBecomesInvisible() { + testSpec.assertLayers { + this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) + .then() + .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT) + } + } @FlakyTest @Test - fun appWindowBecomesInVisible() = - testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName) + fun appWindowBecomesInVisible() { + testSpec.assertWm { + this.isAppWindowVisible(secondaryApp.component) + .then() + .isAppWindowInvisible(secondaryApp.component) + } + } + + @Postsubmit + @Test + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - @Presubmit + @Postsubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - @Presubmit + @FlakyTest + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt index 76dcd8b89242..95fe3bef4852 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt @@ -24,15 +24,13 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.layerBecomesInvisible -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.dockedStackDividerIsInvisible +import com.android.server.wm.flicker.navBarWindowIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -71,31 +69,52 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, WindowManagerStateHelper.SPLASH_SCREEN_NAME, - splitScreenApp.defaultWindowName, secondaryApp.defaultWindowName, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, + splitScreenApp.component, secondaryApp.component, + FlickerComponentName.SNAPSHOT) - @FlakyTest(bugId = 175687842) + @Presubmit @Test - fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible() + fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() @FlakyTest @Test - fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + fun layerBecomesInvisible() { + testSpec.assertLayers { + this.isVisible(splitScreenApp.component) + .then() + .isInvisible(splitScreenApp.component) + } + } @FlakyTest @Test - fun appWindowBecomesInVisible() = - testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + fun appWindowBecomesInVisible() { + testSpec.assertWm { + this.isAppWindowVisible(splitScreenApp.component) + .then() + .isAppWindowInvisible(splitScreenApp.component) + } + } + + @Presubmit + @Test + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() + + @Presubmit + @Test + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt index d0a64b3774c7..f7d628d48769 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt @@ -23,15 +23,11 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesInVisible -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.layerBecomesInvisible -import com.android.server.wm.flicker.layerBecomesVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER -import com.android.wm.shell.flicker.dockedStackDividerIsInvisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -72,11 +68,11 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, - nonResizeableApp.defaultWindowName, splitScreenApp.defaultWindowName, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, + nonResizeableApp.component, splitScreenApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -92,44 +88,109 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( @Presubmit @Test - fun resizableAppLayerBecomesInvisible() = - testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + fun resizableAppLayerBecomesInvisible() { + testSpec.assertLayers { + this.isVisible(splitScreenApp.component) + .then() + .isInvisible(splitScreenApp.component) + } + } + + @Presubmit + @Test + fun nonResizableAppLayerBecomesVisible() { + testSpec.assertLayers { + this.notContains(nonResizeableApp.component) + .then() + .isInvisible(nonResizeableApp.component) + .then() + .isVisible(nonResizeableApp.component) + } + } + /** + * Assets that [splitScreenApp] exists at the start of the trace and, once it becomes + * invisible, it remains invisible until the end of the trace. + */ @Presubmit @Test - fun nonResizableAppLayerBecomesVisible() = - testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + fun resizableAppWindowBecomesInvisible() { + testSpec.assertWm { + // when the activity gets PAUSED the window may still be marked as visible + // it will be updated in the next log entry. This occurs because we record 1x + // per frame, thus ignore activity check here + this.isAppWindowVisible(splitScreenApp.component) + .then() + // immediately after the window (after onResume and before perform relayout) + // the activity is invisible. This may or not be logged, since we record 1x + // per frame, thus ignore activity check here + .isAppWindowInvisible(splitScreenApp.component) + } + } + /** + * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then + * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes + * visible, it remains visible until the end of the trace. + */ @Presubmit @Test - fun resizableAppWindowBecomesInvisible() = - testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + fun nonResizableAppWindowBecomesVisible() { + testSpec.assertWm { + this.notContains(nonResizeableApp.component) + .then() + // we log once per frame, upon logging, window may be visible or not depending + // on what was processed until that moment. Both behaviors are correct + .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) + .then() + // immediately after the window (after onResume and before perform relayout) + // the activity is invisible. This may or not be logged, since we record 1x + // per frame, thus ignore activity check here + .isAppWindowVisible(nonResizeableApp.component) + } + } + /** + * Asserts that both the app window and the activity are visible at the end of the trace + */ @Presubmit @Test - fun nonResizableAppWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppWindowBecomesVisibleAtEnd() { + testSpec.assertWmEnd { + isAppWindowVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible() + fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() @Presubmit @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { - isInvisible(splitScreenApp.defaultWindowName) - isVisible(nonResizeableApp.defaultWindowName) + isAppWindowInvisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } + @Presubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 + repetitions = SplitScreenHelper.TEST_REPETITIONS, + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt index c26c05fa8db6..a5c6571f68de 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt @@ -23,13 +23,11 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.layerBecomesVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER -import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -70,11 +68,11 @@ class LegacySplitScreenFromIntentSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, - nonResizeableApp.defaultWindowName, splitScreenApp.defaultWindowName, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, + nonResizeableApp.component, splitScreenApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -90,27 +88,59 @@ class LegacySplitScreenFromIntentSupportNonResizable( @Presubmit @Test - fun nonResizableAppLayerBecomesVisible() = - testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppLayerBecomesVisible() { + testSpec.assertLayers { + this.isInvisible(nonResizeableApp.component) + .then() + .isVisible(nonResizeableApp.component) + } + } + /** + * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then + * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes + * visible, it remains visible until the end of the trace. + */ @Presubmit @Test - fun nonResizableAppWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppWindowBecomesVisible() { + testSpec.assertWm { + this.notContains(nonResizeableApp.component) + .then() + // we log once per frame, upon logging, window may be visible or not depending + // on what was processed until that moment. Both behaviors are correct + .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) + .then() + // immediately after the window (after onResume and before perform relayout) + // the activity is invisible. This may or not be logged, since we record 1x + // per frame, thus ignore activity check here + .isAppWindowVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { - isVisible(splitScreenApp.defaultWindowName) - isVisible(nonResizeableApp.defaultWindowName) + isAppWindowVisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } + @Presubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt index fb1758975442..6f486b0ddfea 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen +import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice @@ -23,16 +24,12 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesInVisible -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.layerBecomesInvisible -import com.android.server.wm.flicker.layerBecomesVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER -import com.android.wm.shell.flicker.dockedStackDividerIsInvisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -73,11 +70,11 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME, - splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, + TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -93,37 +90,73 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( @Presubmit @Test - fun resizableAppLayerBecomesInvisible() = - testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + fun resizableAppLayerBecomesInvisible() { + testSpec.assertLayers { + this.isVisible(splitScreenApp.component) + .then() + .isInvisible(splitScreenApp.component) + } + } @Presubmit @Test - fun nonResizableAppLayerBecomesVisible() = - testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppLayerBecomesVisible() { + testSpec.assertLayers { + this.isInvisible(nonResizeableApp.component) + .then() + .isVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun resizableAppWindowBecomesInvisible() = - testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + fun resizableAppWindowBecomesInvisible() { + testSpec.assertWm { + // when the activity gets PAUSED the window may still be marked as visible + // it will be updated in the next log entry. This occurs because we record 1x + // per frame, thus ignore activity check here + this.isAppWindowVisible(splitScreenApp.component) + .then() + // immediately after the window (after onResume and before perform relayout) + // the activity is invisible. This may or not be logged, since we record 1x + // per frame, thus ignore activity check here + .isAppWindowInvisible(splitScreenApp.component) + } + } - @Presubmit + @Postsubmit @Test - fun nonResizableAppWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppWindowBecomesVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(nonResizeableApp.component) + .then() + .isAppWindowVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible() + fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() @Presubmit @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { - isInvisible(splitScreenApp.defaultWindowName) - isVisible(nonResizeableApp.defaultWindowName) + isAppWindowInvisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } + @Presubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt index a9c28efcdf44..f03c927b8d58 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt @@ -23,14 +23,12 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.layerBecomesVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER -import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -71,11 +69,11 @@ class LegacySplitScreenFromRecentSupportNonResizable( } } - override val ignoredWindows: List<String> - get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME, - splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, + TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -91,27 +89,60 @@ class LegacySplitScreenFromRecentSupportNonResizable( @Presubmit @Test - fun nonResizableAppLayerBecomesVisible() = - testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppLayerBecomesVisible() { + testSpec.assertLayers { + this.isInvisible(nonResizeableApp.component) + .then() + .isVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun nonResizableAppWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + fun nonResizableAppWindowBecomesVisible() { + testSpec.assertWm { + // when the app is launched, first the activity becomes visible, then the + // SnapshotStartingWindow appears and then the app window becomes visible. + // Because we log WM once per frame, sometimes the activity and the window + // become visible in the same entry, sometimes not, thus it is not possible to + // assert the visibility of the activity here + this.isAppWindowInvisible(nonResizeableApp.component) + .then() + // during re-parenting, the window may disappear and reappear from the + // trace, this occurs because we log only 1x per frame + .notContains(nonResizeableApp.component, isOptional = true) + .then() + // if the window reappears after re-parenting it will most likely not + // be visible in the first log entry (because we log only 1x per frame) + .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) + .then() + .isAppWindowVisible(nonResizeableApp.component) + } + } @Presubmit @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { - isVisible(splitScreenApp.defaultWindowName) - isVisible(nonResizeableApp.defaultWindowName) + isAppWindowVisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } + @Presubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt index a4d2ab51e358..2ccd03bf1d6a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt @@ -16,10 +16,9 @@ package com.android.wm.shell.flicker.legacysplitscreen +import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.support.test.launcherhelper.LauncherStrategyFactory import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter @@ -27,21 +26,19 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.focusDoesNotChange +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.exitSplitScreen import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.layerBecomesInvisible -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible +import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible import com.android.wm.shell.flicker.helpers.SimpleAppHelper import org.junit.FixMethodOrder @@ -62,8 +59,6 @@ import org.junit.runners.Parameterized class LegacySplitScreenToLauncher( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { - private val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation) - .launcherStrategy.supportedLauncherPackage private val testApp = SimpleAppHelper(instrumentation) override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit @@ -90,51 +85,69 @@ class LegacySplitScreenToLauncher( } } - override val ignoredWindows: List<String> - get() = listOf(launcherPackageName, WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test - fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible() @Presubmit @Test - fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation) + fun entireScreenCovered() = testSpec.entireScreenCovered() @Presubmit @Test - fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() @Presubmit @Test - fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Presubmit @Test - fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() - @Presubmit + @Postsubmit @Test fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible() + @Postsubmit + @Test + fun layerBecomesInvisible() { + testSpec.assertLayers { + this.isVisible(testApp.component) + .then() + .isInvisible(testApp.component) + } + } + + @Postsubmit + @Test + fun focusDoesNotChange() { + testSpec.assertEventLog { + this.focusDoesNotChange() + } + } + @Presubmit @Test - fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(testApp.getPackage()) + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() - @FlakyTest(bugId = 151179149) + @Presubmit @Test - fun focusDoesNotChange() = testSpec.focusDoesNotChange() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt index e8d4d1e9ada2..661c8b69068e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt @@ -31,11 +31,14 @@ 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.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.After +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Test @@ -46,12 +49,17 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation) protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation) - protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation) - .launcherStrategy.supportedLauncherPackage + protected val LAUNCHER_COMPONENT = FlickerComponentName("", + LauncherStrategyFactory.getInstance(instrumentation) + .launcherStrategy.supportedLauncherPackage) private var prevDevEnableNonResizableMultiWindow = 0 @Before open fun setup() { + // Only run legacy split tests when the system is using legacy split screen. + assumeTrue(SplitScreenHelper.isUsingLegacySplit()) + // Legacy split is having some issue with Shell transition, and will be deprecated soon. + assumeFalse(isShellTransitionsEnabled()) prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context) if (prevDevEnableNonResizableMultiWindow != 0) { // Turn off the development option @@ -70,8 +78,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa * * b/182720234 */ - open val ignoredWindows: List<String> = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + open val ignoredWindows: List<FlickerComponentName> = listOf( + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { configuration -> @@ -138,9 +147,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa } companion object { - internal const val LIVE_WALLPAPER_PACKAGE_NAME = - "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2" - internal const val LETTERBOX_NAME = "Letterbox" - internal const val TOAST_NAME = "Toast" + internal val LIVE_WALLPAPER_COMPONENT = FlickerComponentName("", + "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2") + internal val LETTERBOX_COMPONENT = FlickerComponentName("", "Letterbox") + internal val TOAST_COMPONENT = FlickerComponentName("", "Toast") } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt index 05eb5f49a641..34eff80a04bc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt @@ -24,15 +24,11 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.focusChanges +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.layerBecomesVisible -import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.flicker.statusBarLayerIsVisible +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.appPairsDividerBecomesVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder @@ -62,22 +58,28 @@ class OpenAppToLegacySplitScreen( } } - override val ignoredWindows: List<String> - get() = listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - WindowManagerStateHelper.SPLASH_SCREEN_NAME, - WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @FlakyTest @Test - fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage()) + fun appWindowBecomesVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(splitScreenApp.component) + .then() + .isAppWindowVisible(splitScreenApp.component) + } + } - @FlakyTest + @Presubmit @Test - fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) + fun entireScreenCovered() = testSpec.entireScreenCovered() @Presubmit @Test - fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() @Presubmit @Test @@ -85,12 +87,27 @@ class OpenAppToLegacySplitScreen( @FlakyTest @Test - fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage()) + fun layerBecomesVisible() { + testSpec.assertLayers { + this.isInvisible(splitScreenApp.component) + .then() + .isVisible(splitScreenApp.component) + } + } + + @Presubmit + @Test + fun focusChanges() { + testSpec.assertEventLog { + this.focusChanges(splitScreenApp.`package`, + "recents_animation_input_consumer", "NexusLauncherActivity") + } + } - @FlakyTest(bugId = 151179149) + @Presubmit @Test - fun focusChanges() = testSpec.focusChanges(splitScreenApp.`package`, - "recents_animation_input_consumer", "NexusLauncherActivity") + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt index 3e83b6382939..58e1def6f37a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt @@ -27,24 +27,24 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.resizeSplitScreen import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.noUncoveredRegions +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.traces.layers.getVisibleBounds -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.parser.toFlickerComponent +import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.helpers.SimpleAppHelper +import com.android.wm.shell.flicker.testapp.Components import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -101,16 +101,16 @@ class ResizeLegacySplitScreen( } @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @FlakyTest(bugId = 156223549) @Test fun topAppWindowIsAlwaysVisible() { testSpec.assertWm { - this.showsAppWindow(sSimpleActivity) + this.isAppWindowVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) } } @@ -118,45 +118,43 @@ class ResizeLegacySplitScreen( @Test fun bottomAppWindowIsAlwaysVisible() { testSpec.assertWm { - this.showsAppWindow(sImeActivity) + this.isAppWindowVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) } } @Test - fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible() @Test - fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() @Test - fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation) + fun entireScreenCovered() = testSpec.entireScreenCovered() @Test - fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() @Test - fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Test fun topAppLayerIsAlwaysVisible() { testSpec.assertLayers { - this.isVisible(sSimpleActivity) + this.isVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) } } @Test fun bottomAppLayerIsAlwaysVisible() { testSpec.assertLayers { - this.isVisible(sImeActivity) + this.isVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) } } @Test fun dividerLayerIsAlwaysVisible() { testSpec.assertLayers { - this.isVisible(DOCKED_STACK_DIVIDER) + this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) } } @@ -166,7 +164,7 @@ class ResizeLegacySplitScreen( testSpec.assertLayersStart { val displayBounds = WindowUtils.displayBounds val dividerBounds = - entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds + layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds val topAppBounds = Region(0, 0, dividerBounds.right, dividerBounds.top + WindowUtils.dockedStackDividerInset) @@ -174,8 +172,10 @@ class ResizeLegacySplitScreen( dividerBounds.bottom - WindowUtils.dockedStackDividerInset, displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight) - visibleRegion("SimpleActivity").coversExactly(topAppBounds) - visibleRegion("ImeActivity").coversExactly(bottomAppBounds) + visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) + .coversExactly(topAppBounds) + visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) + .coversExactly(bottomAppBounds) } } @@ -185,7 +185,7 @@ class ResizeLegacySplitScreen( testSpec.assertLayersStart { val displayBounds = WindowUtils.displayBounds val dividerBounds = - entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds + layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds val topAppBounds = Region(0, 0, dividerBounds.right, dividerBounds.top + WindowUtils.dockedStackDividerInset) @@ -194,8 +194,10 @@ class ResizeLegacySplitScreen( displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight) - visibleRegion(sSimpleActivity).coversExactly(topAppBounds) - visibleRegion(sImeActivity).coversExactly(bottomAppBounds) + visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) + .coversExactly(topAppBounds) + visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) + .coversExactly(bottomAppBounds) } } @@ -207,8 +209,6 @@ class ResizeLegacySplitScreen( } companion object { - private const val sSimpleActivity = "SimpleActivity" - private const val sImeActivity = "ImeActivity" private val startRatio = Rational(1, 3) private val stopRatio = Rational(2, 3) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt index 58482eaae3f5..8a50bc0b20cf 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt @@ -24,18 +24,16 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -66,38 +64,44 @@ class RotateOneLaunchedAppAndEnterSplitScreen( @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = - testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, - splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + splitScreenApp.component) - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, - testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, - testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @FlakyTest @Test - fun appWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName) + fun appWindowBecomesVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(splitScreenApp.component) + .then() + .isAppWindowVisible(splitScreenApp.component) + } + } + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt index 06828d6adb26..84676a9186be 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt @@ -24,18 +24,16 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -66,35 +64,43 @@ class RotateOneLaunchedAppInSplitScreenMode( @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = testSpec.dockedStackPrimaryBoundsIsVisible( - testSpec.config.startRotation, splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd( + testSpec.config.startRotation, splitScreenApp.component) - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales( - testSpec.config.startRotation, testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( - testSpec.config.startRotation, testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @FlakyTest @Test - fun appWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName) + fun appWindowBecomesVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(splitScreenApp.component) + .then() + .isAppWindowVisible(splitScreenApp.component) + } + } + + @Presubmit + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt index f8e32bf171d8..2abdca9216f9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt @@ -18,26 +18,23 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.platform.test.annotations.Presubmit import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -69,42 +66,63 @@ class RotateTwoLaunchedAppAndEnterSplitScreen( @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = - testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, - splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + splitScreenApp.component) @Presubmit @Test - fun dockedStackSecondaryBoundsIsVisible() = - testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, - secondaryApp.defaultWindowName) + fun dockedStackSecondaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + secondaryApp.component) - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, - testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( - testSpec.config.startRotation, testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() + + @Presubmit + @Test + fun appWindowBecomesVisible() { + testSpec.assertWm { + // when the app is launched, first the activity becomes visible, then the + // SnapshotStartingWindow appears and then the app window becomes visible. + // Because we log WM once per frame, sometimes the activity and the window + // become visible in the same entry, sometimes not, thus it is not possible to + // assert the visibility of the activity here + this.isAppWindowInvisible(secondaryApp.component) + .then() + // during re-parenting, the window may disappear and reappear from the + // trace, this occurs because we log only 1x per frame + .notContains(secondaryApp.component, isOptional = true) + .then() + // if the window reappears after re-parenting it will most likely not + // be visible in the first log entry (because we log only 1x per frame) + .isAppWindowInvisible(secondaryApp.component, isOptional = true) + .then() + .isAppWindowVisible(secondaryApp.component) + } + } @Presubmit @Test - fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt index cb246ca0b694..fe9b9f514015 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt @@ -24,20 +24,18 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd +import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder import org.junit.Test @@ -74,44 +72,55 @@ class RotateTwoLaunchedAppInSplitScreenMode( @Presubmit @Test - fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() @Presubmit @Test - fun dockedStackPrimaryBoundsIsVisible() = - testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, - splitScreenApp.defaultWindowName) + fun dockedStackPrimaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + splitScreenApp.component) @Presubmit @Test - fun dockedStackSecondaryBoundsIsVisible() = - testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, - secondaryApp.defaultWindowName) + fun dockedStackSecondaryBoundsIsVisibleAtEnd() = + testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation, + secondaryApp.component) - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, - testSpec.config.endRotation) + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - @FlakyTest(bugId = 169271943) + @Presubmit @Test - fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, - testSpec.config.endRotation) + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @FlakyTest @Test - fun appWindowBecomesVisible() = - testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + fun appWindowBecomesVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(secondaryApp.component) + .then() + .isAppWindowVisible(secondaryApp.component) + } + } + + @Presubmit + @Test + fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() + + @Presubmit + @Test + fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() @Presubmit @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() @Presubmit @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt index 2a660747bc1d..f9b08000290f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:JvmName("CommonAssertions") package com.android.wm.shell.flicker.pip -internal const val PIP_WINDOW_TITLE = "PipMenuActivity" +internal const val PIP_WINDOW_COMPONENT = "PipMenuActivity" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index b6af26060050..52a744f3897d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -23,6 +23,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.LAUNCHER_COMPONENT import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder import org.junit.FixMethodOrder @@ -32,8 +33,21 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test Pip launch. + * Test entering pip from an app by interacting with the app UI + * * To run this test: `atest WMShellFlickerTests:EnterPipTest` + * + * Actions: + * Launch an app in full screen + * Press an "enter pip" button to put [pipApp] in pip mode + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @@ -41,49 +55,121 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group3 class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + /** + * Defines the transition used to run the test + */ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = buildTransition(eachRun = true, stringExtras = emptyMap()) { transitions { - pipApp.clickEnterPipButton() - pipApp.expandPipWindow(wmHelper) + pipApp.clickEnterPipButton(wmHelper) } } - @FlakyTest + /** + * Checks [pipApp] window remains visible throughout the animation + */ + @Presubmit @Test - override fun noUncoveredRegions() { - super.noUncoveredRegions() + fun pipAppWindowAlwaysVisible() { + testSpec.assertWm { + this.isAppWindowVisible(pipApp.component) + } } + /** + * Checks [pipApp] layer remains visible throughout the animation + */ @Presubmit @Test - fun pipAppWindowAlwaysVisible() { + fun pipAppLayerAlwaysVisible() { + testSpec.assertLayers { + this.isVisible(pipApp.component) + } + } + + /** + * Checks that the pip app window remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + fun pipWindowRemainInsideVisibleBounds() { testSpec.assertWm { - this.showsAppWindow(pipApp.defaultWindowName) + coversAtMost(displayBounds, pipApp.component) } } - @FlakyTest + /** + * Checks that the pip app layer remains inside the display bounds throughout the whole + * animation + */ + @Presubmit @Test - fun pipLayerBecomesVisible() { + fun pipLayerRemainInsideVisibleBounds() { testSpec.assertLayers { - this.isVisible(pipApp.windowName) + coversAtMost(displayBounds, pipApp.component) } } - @FlakyTest + /** + * Checks that the visible region of [pipApp] always reduces during the animation + */ + @Presubmit @Test - fun pipWindowBecomesVisible() { - testSpec.assertWm { - invoke("pipWindowIsNotVisible") { - verify("Has no pip window").that(it.wmState.hasPipWindow()).isTrue() - }.then().invoke("pipWindowIsVisible") { - verify("Has pip window").that(it.wmState.hasPipWindow()).isTrue() + fun pipLayerReduces() { + val layerName = pipApp.component.toLayerName() + testSpec.assertLayers { + val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + current.visibleRegion.coversAtMost(previous.visibleRegion.region) } } } + /** + * Checks that [pipApp] window becomes pinned + */ + @Presubmit + @Test + fun pipWindowBecomesPinned() { + testSpec.assertWm { + invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp.component) } + .then() + .invoke("pipWindowIsPinned") { it.isPinned(pipApp.component) } + } + } + + /** + * Checks [LAUNCHER_COMPONENT] layer remains visible throughout the animation + */ + @Presubmit + @Test + fun launcherLayerBecomesVisible() { + testSpec.assertLayers { + isInvisible(LAUNCHER_COMPONENT) + .then() + .isVisible(LAUNCHER_COMPONENT) + } + } + + /** + * Checks the focus doesn't change during the animation + */ + @FlakyTest + @Test + fun focusDoesNotChange() { + testSpec.assertEventLog { + this.focusDoesNotChange() + } + } + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<FlickerTestParameter> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt index 3a1456e53f87..c8c3f4d64294 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -25,7 +25,11 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.navBarLayerRotatesAndScales +import com.android.server.wm.flicker.statusBarLayerRotatesScales +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.helpers.FixedAppHelper import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT @@ -38,8 +42,22 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test Pip with orientation changes. - * To run this test: `atest WMShellFlickerTests:PipOrientationTest` + * Test entering pip while changing orientation (from app in landscape to pip window in portrait) + * + * To run this test: `atest EnterPipToOtherOrientationTest:EnterPipToOtherOrientationTest` + * + * Actions: + * Launch [testApp] on a fixed portrait orientation + * Launch [pipApp] on a fixed landscape orientation + * Broadcast action [ACTION_ENTER_PIP] to enter pip mode + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @@ -53,6 +71,9 @@ class EnterPipToOtherOrientationTest( private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + /** + * Defines the transition used to run the test + */ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { configuration -> setupAndTeardown(this, configuration) @@ -79,65 +100,125 @@ class EnterPipToOtherOrientationTest( broadcastActionTrigger.doAction(ACTION_ENTER_PIP) wmHelper.waitFor { it.wmState.hasPipWindow() } wmHelper.waitForAppTransitionIdle() + // during rotation the status bar becomes invisible and reappears at the end + wmHelper.waitForNavBarStatusBarVisible() } } + /** + * Checks that the [FlickerComponentName.NAV_BAR] has the correct position at + * the start and end of the transition + */ @FlakyTest @Test - override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() + override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - @FlakyTest + /** + * Checks that the [FlickerComponentName.STATUS_BAR] has the correct position at + * the start and end of the transition + */ + @Presubmit @Test - override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales() + override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - @FlakyTest + /** + * Checks that all parts of the screen are covered at the start and end of the transition + * + * TODO b/197726599 Prevents all states from being checked + */ + @Presubmit @Test - override fun noUncoveredRegions() { - super.noUncoveredRegions() - } + override fun entireScreenCovered() = testSpec.entireScreenCovered(allStates = false) + /** + * Checks [pipApp] window remains visible and on top throughout the transition + */ @Presubmit @Test fun pipAppWindowIsAlwaysOnTop() { testSpec.assertWm { - showsAppWindowOnTop(pipApp.defaultWindowName) + isAppWindowOnTop(pipApp.component) } } + /** + * Checks that [testApp] window is not visible at the start + */ @Presubmit @Test - fun pipAppHidesTestApp() { + fun testAppWindowInvisibleOnStart() { testSpec.assertWmStart { - isInvisible(testApp.defaultWindowName) + isAppWindowInvisible(testApp.component) } } + /** + * Checks that [testApp] window is visible at the end + */ @Presubmit @Test - fun testAppWindowIsVisible() { + fun testAppWindowVisibleOnEnd() { testSpec.assertWmEnd { - isVisible(testApp.defaultWindowName) + isAppWindowVisible(testApp.component) + } + } + + /** + * Checks that [testApp] layer is not visible at the start + */ + @Presubmit + @Test + fun testAppLayerInvisibleOnStart() { + testSpec.assertLayersStart { + isInvisible(testApp.component) + } + } + + /** + * Checks that [testApp] layer is visible at the end + */ + @Presubmit + @Test + fun testAppLayerVisibleOnEnd() { + testSpec.assertLayersEnd { + isVisible(testApp.component) } } + /** + * Checks that the visible region of [pipApp] covers the full display area at the start of + * the transition + */ @Presubmit @Test - fun pipAppLayerHidesTestApp() { + fun pipAppLayerCoversFullScreenOnStart() { testSpec.assertLayersStart { - visibleRegion(pipApp.defaultWindowName).coversExactly(startingBounds) - isInvisible(testApp.defaultWindowName) + visibleRegion(pipApp.component).coversExactly(startingBounds) } } + /** + * Checks that the visible region of [testApp] plus the visible region of [pipApp] + * cover the full display area at the end of the transition + */ @Presubmit @Test - fun testAppLayerCoversFullScreen() { + fun testAppPlusPipLayerCoversFullScreenOnEnd() { testSpec.assertLayersEnd { - visibleRegion(testApp.defaultWindowName).coversExactly(endingBounds) + val pipRegion = visibleRegion(pipApp.component).region + visibleRegion(testApp.component) + .plus(pipRegion) + .coversExactly(endingBounds) } } companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt new file mode 100644 index 000000000000..64b7eb53bd6f --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.pip + +import android.platform.test.annotations.Presubmit +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import org.junit.Test + +/** + * Base class for pip expand tests + */ +abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + protected val testApp = FixedAppHelper(instrumentation) + + /** + * Checks that the pip app window remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + open fun pipAppWindowRemainInsideVisibleBounds() { + testSpec.assertWm { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks that the pip app layer remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + open fun pipAppLayerRemainInsideVisibleBounds() { + testSpec.assertLayers { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks both app windows are visible at the start of the transition (with [pipApp] on top). + * Then, during the transition, [testApp] becomes invisible and [pipApp] remains visible + */ + @Presubmit + @Test + open fun showBothAppWindowsThenHidePip() { + testSpec.assertWm { + // when the activity is STOPPING, sometimes it becomes invisible in an entry before + // the window, sometimes in the same entry. This occurs because we log 1x per frame + // thus we ignore activity here + isAppWindowVisible(testApp.component) + .isAppWindowOnTop(pipApp.component) + .then() + .isAppWindowInvisible(testApp.component) + .isAppWindowVisible(pipApp.component) + } + } + + /** + * Checks both app layers are visible at the start of the transition. Then, during the + * transition, [testApp] becomes invisible and [pipApp] remains visible + */ + @Presubmit + @Test + open fun showBothAppLayersThenHidePip() { + testSpec.assertLayers { + isVisible(testApp.component) + .isVisible(pipApp.component) + .then() + .isInvisible(testApp.component) + .isVisible(pipApp.component) + } + } + + /** + * Checks that the visible region of [testApp] plus the visible region of [pipApp] + * cover the full display area at the start of the transition + */ + @Presubmit + @Test + open fun testPlusPipAppsCoverFullScreenAtStart() { + testSpec.assertLayersStart { + val pipRegion = visibleRegion(pipApp.component).region + visibleRegion(testApp.component) + .plus(pipRegion) + .coversExactly(displayBounds) + } + } + + /** + * Checks that the visible region of [pipApp] covers the full display area at the end of + * the transition + */ + @Presubmit + @Test + open fun pipAppCoversFullScreenAtEnd() { + testSpec.assertLayersEnd { + visibleRegion(pipApp.component).coversExactly(displayBounds) + } + } + + /** + * Checks that the visible region of [pipApp] always expands during the animation + */ + @Presubmit + @Test + open fun pipLayerExpands() { + val layerName = pipApp.component.toLayerName() + testSpec.assertLayers { + val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + current.visibleRegion.coversAtLeast(previous.visibleRegion.region) + } + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt index eae7e973711c..5207fed59208 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt @@ -20,15 +20,16 @@ import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.LAUNCHER_COMPONENT import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.startRotation import org.junit.Test -import org.junit.runners.Parameterized -abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) { +/** + * Base class for exiting pip (closing pip window) without returning to the app + */ +abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) { override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = buildTransition(eachRun = true) { configuration -> setup { @@ -43,37 +44,49 @@ abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransitio } } + /** + * Checks that [pipApp] window is pinned and visible at the start and then becomes + * unpinned and invisible at the same moment, and remains unpinned and invisible + * until the end of the transition + */ @Presubmit @Test open fun pipWindowBecomesInvisible() { testSpec.assertWm { - this.showsAppWindow(PIP_WINDOW_TITLE) - .then() - .hidesAppWindow(PIP_WINDOW_TITLE) + this.invoke("hasPipWindow") { + it.isPinned(pipApp.component).isAppWindowVisible(pipApp.component) + }.then().invoke("!hasPipWindow") { + it.isNotPinned(pipApp.component).isAppWindowInvisible(pipApp.component) + } } } + /** + * Checks that [pipApp] and [LAUNCHER_COMPONENT] layers are visible at the start + * of the transition. Then [pipApp] layer becomes invisible, and remains invisible + * until the end of the transition + */ @Presubmit @Test open fun pipLayerBecomesInvisible() { testSpec.assertLayers { - this.isVisible(PIP_WINDOW_TITLE) + this.isVisible(pipApp.component) + .isVisible(LAUNCHER_COMPONENT) .then() - .isInvisible(PIP_WINDOW_TITLE) + .isInvisible(pipApp.component) + .isVisible(LAUNCHER_COMPONENT) } } + /** + * Checks that the focus changes between the [pipApp] window and the launcher when + * closing the pip window + */ @FlakyTest(bugId = 151179149) @Test - open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity") - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<FlickerTestParameter> { - return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) + open fun focusChanges() { + testSpec.assertEventLog { + this.focusChanges(pipApp.launcherName, "NexusLauncherActivity") } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt new file mode 100644 index 000000000000..b53342d6f2f7 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 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.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test expanding a pip window back to full screen via the expand button + * + * To run this test: `atest WMShellFlickerTests:ExitPipViaExpandButtonClickTest` + * + * Actions: + * Launch an app in pip mode [pipApp], + * Launch another full screen mode [testApp] + * Expand [pipApp] app to full screen by clicking on the pip window and + * then on the expand button + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Group3 +class ExitPipViaExpandButtonClickTest( + testSpec: FlickerTestParameter +) : ExitPipToAppTransition(testSpec) { + + /** + * Defines the transition used to run the test + */ + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition(eachRun = true) { + setup { + eachRun { + // launch an app behind the pip one + testApp.launchViaIntent(wmHelper) + } + } + transitions { + // This will bring PipApp to fullscreen + pipApp.expandPipWindowToApp(wmHelper) + // Wait until the other app is no longer visible + wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName()) + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) + } + } +}
\ No newline at end of file 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/ExitPipViaIntentTest.kt index 00e50e7fe3b5..1fec3cf85214 100644 --- 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/ExitPipViaIntentTest.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory @@ -24,88 +23,62 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.wm.shell.flicker.helpers.FixedAppHelper 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` + * Test expanding a pip window back to full screen via an intent + * + * To run this test: `atest WMShellFlickerTests:ExitPipViaIntentTest` + * + * Actions: + * Launch an app in pip mode [pipApp], + * Launch another full screen mode [testApp] + * Expand [pipApp] app to full screen via an intent + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited from [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group3 -class EnterExitPipTest( - testSpec: FlickerTestParameter -) : PipTransition(testSpec) { - private val testApp = FixedAppHelper(instrumentation) +class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransition(testSpec) { + /** + * Defines the transition used to run the test + */ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = buildTransition(eachRun = true) { setup { eachRun { + // launch an app behind the pip one testApp.launchViaIntent(wmHelper) } } transitions { // This will bring PipApp to fullscreen pipApp.launchViaIntent(wmHelper) + // Wait until the other app is no longer visible + wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName()) } } - @Presubmit - @Test - fun pipAppRemainInsideVisibleBounds() { - testSpec.assertWm { - coversAtMost(displayBounds, pipApp.defaultWindowName) - } - } - - @Presubmit - @Test - fun showBothAppWindowsThenHidePip() { - testSpec.assertWm { - showsAppWindow(testApp.defaultWindowName) - .showsAppWindowOnTop(pipApp.defaultWindowName) - .then() - .hidesAppWindow(testApp.defaultWindowName) - } - } - - @Presubmit - @Test - fun showBothAppLayersThenHidePip() { - testSpec.assertLayers { - isVisible(testApp.defaultWindowName) - .isVisible(pipApp.defaultWindowName) - .then() - .isInvisible(testApp.defaultWindowName) - } - } - - @Presubmit - @Test - fun testAppCoversFullScreenWithPipOnDisplay() { - testSpec.assertLayersStart { - visibleRegion(testApp.defaultWindowName).coversExactly(displayBounds) - visibleRegion(pipApp.defaultWindowName).coversAtMost(displayBounds) - } - } - - @Presubmit - @Test - fun pipAppCoversFullScreen() { - testSpec.assertLayersEnd { - visibleRegion(pipApp.defaultWindowName).coversExactly(displayBounds) - } - } - companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<FlickerTestParameter> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt new file mode 100644 index 000000000000..73626c23065a --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt @@ -0,0 +1,78 @@ +/* + * 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.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test closing a pip window via the dismiss button + * + * To run this test: `atest WMShellFlickerTests:ExitPipWithDismissButtonTest` + * + * Actions: + * Launch an app in pip mode [pipApp], + * Click on the pip window + * Click on dismiss button and wait window disappear + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Group3 +class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) { + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = { + super.transition(this, it) + transitions { + pipApp.closePipWindow(wmHelper) + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt index 524a1b404591..9e43deef8d99 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt @@ -22,9 +22,9 @@ import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales import org.junit.FixMethodOrder import org.junit.Test @@ -33,42 +33,58 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test Pip launch. - * To run this test: `atest WMShellFlickerTests:PipCloseWithSwipe` + * Test closing a pip window by swiping it to the bottom-center of the screen + * + * To run this test: `atest WMShellFlickerTests:ExitPipWithSwipeDownTest` + * + * Actions: + * Launch an app in pip mode [pipApp], + * Swipe the pip window to the bottom-center of the screen and wait it disappear + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group3 -class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) { +class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) { override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit - get() = { - super.transition(this, it) + get() = { args -> + super.transition(this, args) transitions { val pipRegion = wmHelper.getWindowRegion(pipApp.component).bounds val pipCenterX = pipRegion.centerX() val pipCenterY = pipRegion.centerY() val displayCenterX = device.displayWidth / 2 - device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 5) + device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 10) + wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() } + wmHelper.waitForWindowSurfaceDisappeared(pipApp.component) + wmHelper.waitForAppTransitionIdle() } } @Presubmit @Test - override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible() + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() @Presubmit @Test - override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible() + override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible() @Presubmit @Test - override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() + override fun navBarWindowIsVisible() = super.navBarWindowIsVisible() @Presubmit @Test - override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() + override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible() @FlakyTest @Test @@ -80,14 +96,29 @@ class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition @Presubmit @Test - override fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Presubmit @Test - override fun noUncoveredRegions() = super.noUncoveredRegions() + override fun entireScreenCovered() = super.entireScreenCovered() @Presubmit @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 20) + } + } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt new file mode 100644 index 000000000000..d0fee9a82093 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -0,0 +1,174 @@ +/* + * 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.platform.test.annotations.Presubmit +import android.view.Surface +import androidx.test.filters.FlakyTest +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.LAUNCHER_COMPONENT +import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test expanding a pip window by double clicking it + * + * To run this test: `atest WMShellFlickerTests:ExpandPipOnDoubleClickTest` + * + * Actions: + * Launch an app in pip mode [pipApp], + * Expand [pipApp] app to its maximum pip size by double clicking on it + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Group3 +class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition(eachRun = true) { + transitions { + pipApp.doubleClickPipWindow(wmHelper) + } + } + + /** + * Checks that the pip app window remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + fun pipWindowRemainInsideVisibleBounds() { + testSpec.assertWm { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks that the pip app layer remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + fun pipLayerRemainInsideVisibleBounds() { + testSpec.assertLayers { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks [pipApp] window remains visible throughout the animation + */ + @Presubmit + @Test + fun pipWindowIsAlwaysVisible() { + testSpec.assertWm { + isAppWindowVisible(pipApp.component) + } + } + + /** + * Checks [pipApp] layer remains visible throughout the animation + */ + @Presubmit + @Test + fun pipLayerIsAlwaysVisible() { + testSpec.assertLayers { + isVisible(pipApp.component) + } + } + + /** + * Checks that the visible region of [pipApp] always expands during the animation + */ + @Presubmit + @Test + fun pipLayerExpands() { + val layerName = pipApp.component.toLayerName() + testSpec.assertLayers { + val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + current.visibleRegion.coversAtLeast(previous.visibleRegion.region) + } + } + } + + /** + * Checks [pipApp] window remains pinned throughout the animation + */ + @Presubmit + @Test + fun windowIsAlwaysPinned() { + testSpec.assertWm { + this.invoke("hasPipWindow") { it.isPinned(pipApp.component) } + } + } + + /** + * Checks [pipApp] layer remains visible throughout the animation + */ + @Presubmit + @Test + fun launcherIsAlwaysVisible() { + testSpec.assertLayers { + isVisible(LAUNCHER_COMPONENT) + } + } + + /** + * Checks that the focus doesn't change between windows during the transition + */ + @FlakyTest + @Test + fun focusDoesNotChange() { + testSpec.assertEventLog { + this.focusDoesNotChange() + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt new file mode 100644 index 000000000000..0ab857d755ee --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 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.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.traces.RegionSubject +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test Pip movement with Launcher shelf height change (decrease). + * + * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest` + * + * Actions: + * Launch [pipApp] in pip mode + * Launch [testApp] + * Press home + * Check if pip window moves down (visually) + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Group3 +class MovePipDownShelfHeightChangeTest( + testSpec: FlickerTestParameter +) : MovePipShelfHeightTransition(testSpec) { + /** + * Defines the transition used to run the test + */ + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = buildTransition(eachRun = false) { + teardown { + eachRun { + testApp.launchViaIntent(wmHelper) + } + test { + testApp.exit(wmHelper) + } + } + transitions { + taplInstrumentation.pressHome() + } + } + + override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) { + current.isHigherOrEqual(previous.region) + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt new file mode 100644 index 000000000000..6e0324c17272 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2021 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.platform.test.annotations.Presubmit +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.traces.RegionSubject +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import org.junit.Test + +/** + * Base class for pip tests with Launcher shelf height change + */ +abstract class MovePipShelfHeightTransition( + testSpec: FlickerTestParameter +) : PipTransition(testSpec) { + protected val taplInstrumentation = LauncherInstrumentation() + protected val testApp = FixedAppHelper(instrumentation) + + /** + * Checks if the window movement direction is valid + */ + protected abstract fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) + + /** + * Checks [pipApp] window remains visible throughout the animation + */ + @Presubmit + @Test + open fun pipWindowIsAlwaysVisible() { + testSpec.assertWm { + isAppWindowVisible(pipApp.component) + } + } + + /** + * Checks [pipApp] layer remains visible throughout the animation + */ + @Presubmit + @Test + open fun pipLayerIsAlwaysVisible() { + testSpec.assertLayers { + isVisible(pipApp.component) + } + } + + /** + * Checks that the pip app window remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + open fun pipWindowRemainInsideVisibleBounds() { + testSpec.assertWm { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks that the pip app layer remains inside the display bounds throughout the whole + * animation + */ + @Presubmit + @Test + open fun pipLayerRemainInsideVisibleBounds() { + testSpec.assertLayers { + coversAtMost(displayBounds, pipApp.component) + } + } + + /** + * Checks that the visible region of [pipApp] always moves in the correct direction + * during the animation. + */ + @Presubmit + @Test + open fun pipWindowMoves() { + val windowName = pipApp.component.toWindowName() + testSpec.assertWm { + val pipWindowList = this.windowStates { it.name.contains(windowName) && it.isVisible } + pipWindowList.zipWithNext { previous, current -> + assertRegionMovement(previous.frame, current.frame) + } + } + } + + /** + * Checks that the visible region of [pipApp] always moves up during the animation + */ + @Presubmit + @Test + open fun pipLayerMoves() { + val layerName = pipApp.component.toLayerName() + testSpec.assertLayers { + val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + assertRegionMovement(previous.visibleRegion, current.visibleRegion) + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt index 1294ac93f647..e507edfda48c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt @@ -16,36 +16,49 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice -import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.google.common.truth.Truth +import com.android.server.wm.flicker.traces.RegionSubject 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 movement with Launcher shelf height change. - * To run this test: `atest WMShellFlickerTests:PipShelfHeightTest` + * Test Pip movement with Launcher shelf height change (increase). + * + * To run this test: `atest WMShellFlickerTests:MovePipUpShelfHeightChangeTest` + * + * Actions: + * Launch [pipApp] in pip mode + * Press home + * Launch [testApp] + * Check if pip window moves up (visually) + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group3 -class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { - private val taplInstrumentation = LauncherInstrumentation() - private val testApp = FixedAppHelper(instrumentation) - +class MovePipUpShelfHeightChangeTest( + testSpec: FlickerTestParameter +) : MovePipShelfHeightTransition(testSpec) { + /** + * Defines the transition used to run the test + */ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = buildTransition(eachRun = false) { teardown { @@ -61,33 +74,17 @@ class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpe } } - @Presubmit - @Test - fun pipAlwaysVisible() = testSpec.assertWm { this.showsAppWindow(pipApp.windowName) } - - @Presubmit - @Test - fun pipLayerInsideDisplay() { - testSpec.assertLayersStart { - visibleRegion(pipApp.defaultWindowName).coversAtMost(displayBounds) - } - } - - @Presubmit - @Test - fun pipWindowMovesUp() = testSpec.assertWmEnd { - val initialState = this.trace?.first()?.wmState - ?: error("Trace should not be empty") - val startPos = initialState.pinnedWindows.first().frame - val currPos = this.wmState.pinnedWindows.first().frame - val subject = Truth.assertWithMessage("Pip should have moved up") - subject.that(currPos.top).isGreaterThan(startPos.top) - subject.that(currPos.bottom).isGreaterThan(startPos.bottom) - subject.that(currPos.left).isEqualTo(startPos.left) - subject.that(currPos.right).isEqualTo(startPos.right) + override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) { + current.isLowerOrEqual(previous.region) } companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<FlickerTestParameter> { 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 d88f94d5954a..aba8aced298f 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 @@ -22,12 +22,12 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.startRotation -import com.android.wm.shell.flicker.IME_WINDOW_NAME +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder import org.junit.Test @@ -43,7 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val imeApp = ImeAppHelper(instrumentation) @@ -79,7 +79,7 @@ class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) fun pipInVisibleBounds() { testSpec.assertWm { val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) - coversAtMost(displayBounds, pipApp.defaultWindowName) + coversAtMost(displayBounds, pipApp.component) } } @@ -90,7 +90,7 @@ class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) @Test fun pipIsAboveAppWindow() { testSpec.assertWmTag(TAG_IME_VISIBLE) { - isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName) + isAboveWindow(FlickerComponentName.IME, pipApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt index 6833b96a802b..9bea5c03dadb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt @@ -23,15 +23,20 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder 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.server.wm.flicker.repetitions import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome +import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.helpers.ImeAppHelper +import com.android.wm.shell.flicker.helpers.SplitScreenHelper import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue +import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -46,12 +51,19 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 161435597) -@Group3 +@Group4 class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val imeApp = ImeAppHelper(instrumentation) private val testApp = FixedAppHelper(instrumentation) + @Before + open fun setup() { + // Only run legacy split tests when the system is using legacy split screen. + assumeTrue(SplitScreenHelper.isUsingLegacySplit()) + // Legacy split is having some issue with Shell transition, and will be deprecated soon. + assumeFalse(isShellTransitionsEnabled()) + } + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { withTestName { testSpec.name } @@ -80,11 +92,11 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t } } - @Presubmit + @FlakyTest(bugId = 161435597) @Test fun pipWindowInsideDisplayBounds() { testSpec.assertWm { - coversAtMost(displayBounds, pipApp.defaultWindowName) + coversAtMost(displayBounds, pipApp.component) } } @@ -92,25 +104,17 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(testApp.defaultWindowName) - isVisible(imeApp.defaultWindowName) - noWindowsOverlap(testApp.defaultWindowName, imeApp.defaultWindowName) + isAppWindowVisible(testApp.component) + isAppWindowVisible(imeApp.component) + doNotOverlap(testApp.component, imeApp.component) } } - @Presubmit - @Test - override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() - - @Presubmit - @Test - override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() - - @Presubmit + @FlakyTest(bugId = 161435597) @Test fun pipLayerInsideDisplayBounds() { testSpec.assertLayers { - coversAtMost(displayBounds, pipApp.defaultWindowName) + coversAtMost(displayBounds, pipApp.component) } } @@ -118,18 +122,14 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t @Test fun bothAppLayersVisible() { testSpec.assertLayersEnd { - visibleRegion(testApp.defaultWindowName).coversAtMost(displayBounds) - visibleRegion(imeApp.defaultWindowName).coversAtMost(displayBounds) + visibleRegion(testApp.component).coversAtMost(displayBounds) + visibleRegion(imeApp.component).coversAtMost(displayBounds) } } - @Presubmit - @Test - override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible() - - @Presubmit + @FlakyTest(bugId = 161435597) @Test - override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible() + override fun entireScreenCovered() = super.entireScreenCovered() companion object { const val TEST_REPETITIONS = 2 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 index d531af28e2ad..669f37ad1e72 100644 --- 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 @@ -23,13 +23,13 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.wm.shell.flicker.helpers.FixedAppHelper @@ -41,17 +41,32 @@ import org.junit.runners.Parameterized /** * Test Pip Stack in bounds after rotations. + * * To run this test: `atest WMShellFlickerTests:PipRotationTest` + * + * Actions: + * Launch a [pipApp] in pip mode + * Launch another app [fixedApp] (appears below pip) + * Rotate the screen from [testSpec.config.startRotation] to [testSpec.config.endRotation] + * (usually, 0->90 and 90->0) + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited from [PipTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val fixedApp = FixedAppHelper(instrumentation) - private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) - private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation) + private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + private val screenBoundsEnd = WindowUtils.getDisplayBounds(testSpec.config.endRotation) override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = buildTransition(eachRun = false) { configuration -> @@ -66,49 +81,104 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) transitions { setRotation(configuration.endRotation) } - teardown { - eachRun { - setRotation(Surface.ROTATION_0) - } - } } - @FlakyTest(bugId = 185400889) + /** + * Checks that all parts of the screen are covered at the start and end of the transition + */ + @Presubmit @Test - override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, - testSpec.config.endRotation, allStates = false) + override fun entireScreenCovered() = testSpec.entireScreenCovered() + /** + * Checks the position of the navigation bar at the start and end of the transition + */ @FlakyTest @Test - override fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, - testSpec.config.endRotation) + override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() + /** + * Checks the position of the status bar at the start and end of the transition + */ @Presubmit @Test - override fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, - testSpec.config.endRotation) + override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - @FlakyTest(bugId = 185400889) + /** + * Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition + */ + @Presubmit @Test fun appLayerRotates_StartingBounds() { testSpec.assertLayersStart { - visibleRegion(fixedApp.defaultWindowName).coversExactly(startingBounds) - visibleRegion(pipApp.defaultWindowName).coversAtMost(startingBounds) + visibleRegion(fixedApp.component).coversExactly(screenBoundsStart) } } - @FlakyTest(bugId = 185400889) + /** + * Checks that [fixedApp] layer is within [screenBoundsEnd] at the end of the transition + */ + @Presubmit @Test fun appLayerRotates_EndingBounds() { testSpec.assertLayersEnd { - visibleRegion(fixedApp.defaultWindowName).coversExactly(endingBounds) - visibleRegion(pipApp.defaultWindowName).coversAtMost(endingBounds) + visibleRegion(fixedApp.component).coversExactly(screenBoundsEnd) + } + } + + /** + * Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition + */ + @Presubmit + @Test + fun pipLayerRotates_StartingBounds() { + testSpec.assertLayersStart { + visibleRegion(pipApp.component).coversAtMost(screenBoundsStart) + } + } + + /** + * Checks that [pipApp] layer is within [screenBoundsEnd] at the end of the transition + */ + @Presubmit + @Test + fun pipLayerRotates_EndingBounds() { + testSpec.assertLayersEnd { + visibleRegion(pipApp.component).coversAtMost(screenBoundsEnd) + } + } + + /** + * Ensure that the [pipApp] window does not obscure the [fixedApp] at the start of the + * transition + */ + @Presubmit + @Test + fun pipIsAboveFixedAppWindow_Start() { + testSpec.assertWmStart { + isAboveWindow(pipApp.component, fixedApp.component) + } + } + + /** + * Ensure that the [pipApp] window does not obscure the [fixedApp] at the end of the + * transition + */ + @Presubmit + @Test + fun pipIsAboveFixedAppWindow_End() { + testSpec.assertWmEnd { + isAboveWindow(pipApp.component, fixedApp.component) } } companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt deleted file mode 100644 index 55e5c4128967..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.pip - -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.startRotation -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test Pip launch. - * To run this test: `atest WMShellFlickerTests:PipToAppTest` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 -class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { - override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit - get() = buildTransition(eachRun = true) { configuration -> - setup { - eachRun { - this.setRotation(configuration.startRotation) - } - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - } - transitions { - pipApp.expandPipWindowToApp(wmHelper) - } - } - - @FlakyTest - @Test - fun appReplacesPipWindow() { - testSpec.assertWm { - this.showsAppWindow(PIP_WINDOW_TITLE) - .then() - .showsAppWindowOnTop(pipApp.launcherName) - } - } - - @FlakyTest - @Test - fun appReplacesPipLayer() { - testSpec.assertLayers { - this.isVisible(PIP_WINDOW_TITLE) - .then() - .isVisible(pipApp.launcherName) - } - } - - @FlakyTest - @Test - fun testAppCoversFullScreen() { - testSpec.assertLayersStart { - visibleRegion(pipApp.defaultWindowName).coversExactly(displayBounds) - } - } - - @FlakyTest(bugId = 151179149) - @Test - fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", - pipApp.launcherName, "NexusLauncherActivity") - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<FlickerTestParameter> { - return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt index b4c75a6d1165..e8a61e8a1dae 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt @@ -20,25 +20,24 @@ import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Presubmit import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerBuilderProvider import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.noUncoveredRegions +import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible import com.android.wm.shell.flicker.helpers.PipAppHelper import com.android.wm.shell.flicker.testapp.Components import org.junit.Test @@ -162,32 +161,29 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) { @Presubmit @Test - open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + open fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() @Presubmit @Test - open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + open fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - @FlakyTest + @Presubmit @Test - open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + open fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible() - @FlakyTest + @Presubmit @Test - open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + open fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() @Presubmit @Test - open fun navBarLayerRotatesAndScales() = - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() @Presubmit @Test - open fun statusBarLayerRotatesScales() = - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() @Presubmit @Test - open fun noUncoveredRegions() = - testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + open fun entireScreenCovered() = testSpec.entireScreenCovered() }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt index 1f58bb2bf9db..d6dbc366aec0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -16,14 +16,13 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE @@ -44,7 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class SetRequestedOrientationWhilePinnedTest( testSpec: FlickerTestParameter ) : PipTransition(testSpec) { @@ -83,55 +82,69 @@ class SetRequestedOrientationWhilePinnedTest( @FlakyTest @Test + override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() + + @FlakyTest + @Test + override fun navBarWindowIsVisible() = super.navBarWindowIsVisible() + + @FlakyTest + @Test + override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible() + + @FlakyTest + @Test + override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible() + + @FlakyTest + @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() @FlakyTest @Test override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales() - @Presubmit + @FlakyTest @Test fun pipWindowInsideDisplay() { testSpec.assertWmStart { - frameRegion(pipApp.defaultWindowName).coversAtMost(startingBounds) + frameRegion(pipApp.component).coversAtMost(startingBounds) } } - @Presubmit + @FlakyTest @Test fun pipAppShowsOnTop() { testSpec.assertWmEnd { - showsAppWindowOnTop(pipApp.defaultWindowName) + isAppWindowOnTop(pipApp.component) } } - @Presubmit + @FlakyTest @Test fun pipLayerInsideDisplay() { testSpec.assertLayersStart { - visibleRegion(pipApp.defaultWindowName).coversAtMost(startingBounds) + visibleRegion(pipApp.component).coversAtMost(startingBounds) } } - @Presubmit + @FlakyTest @Test fun pipAlwaysVisible() = testSpec.assertWm { - this.showsAppWindow(pipApp.windowName) + this.isAppWindowVisible(pipApp.component) } - @Presubmit + @FlakyTest @Test fun pipAppLayerCoversFullScreen() { testSpec.assertLayersEnd { - visibleRegion(pipApp.defaultWindowName).coversExactly(endingBounds) + visibleRegion(pipApp.component).coversExactly(endingBounds) } } @FlakyTest @Test - override fun noUncoveredRegions() { - super.noUncoveredRegions() - } + override fun entireScreenCovered() = super.entireScreenCovered() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt index 0110ba3f5b30..061218a015e4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt @@ -37,14 +37,17 @@ class TvPipMenuTests : TvPipTestBase() { private val systemUiResources = packageManager.getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME) private val pipBoundsWhileInMenu: Rect = systemUiResources.run { - val bounds = getString(getIdentifier("pip_menu_bounds", "string", SYSTEM_UI_PACKAGE_NAME)) + val bounds = getString(getIdentifier("pip_menu_bounds", "string", + SYSTEM_UI_PACKAGE_NAME)) Rect.unflattenFromString(bounds) ?: error("Could not retrieve PiP menu bounds") } private val playButtonDescription = systemUiResources.run { - getString(getIdentifier("pip_play", "string", SYSTEM_UI_PACKAGE_NAME)) + getString(getIdentifier("pip_play", "string", + SYSTEM_UI_PACKAGE_NAME)) } private val pauseButtonDescription = systemUiResources.run { - getString(getIdentifier("pip_pause", "string", SYSTEM_UI_PACKAGE_NAME)) + getString(getIdentifier("pip_pause", "string", + SYSTEM_UI_PACKAGE_NAME)) } @Before diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt index 1b73920046dc..1c663409b913 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt @@ -70,7 +70,8 @@ fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? { // descendant and then retrieve the element from the menu and return to the caller of this // method. val elementSelector = By.desc(desc) - val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR).hasDescendant(elementSelector) + val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR) + .hasDescendant(elementSelector) return wait(Until.findObject(menuContainingElementSelector), WAIT_TIME_MS) ?.findObject(elementSelector) @@ -94,7 +95,8 @@ fun UiDevice.clickTvPipMenuFullscreenButton() { } fun UiDevice.clickTvPipMenuElementWithDescription(desc: String) { - focusOnAndClickTvPipMenuElement(By.desc(desc).pkg(SYSTEM_UI_PACKAGE_NAME)) || + focusOnAndClickTvPipMenuElement(By.desc(desc) + .pkg(SYSTEM_UI_PACKAGE_NAME)) || error("Could not focus on the Pip menu object with \"$desc\" description") // So apparently Accessibility framework on TV is not very reliable and sometimes the state of // the tree of accessibility nodes as seen by the accessibility clients kind of lags behind of 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 5549330df766..2cdbffa7589c 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml @@ -107,5 +107,20 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + <activity + android:name=".LaunchBubbleActivity" + android:label="LaunchBubbleApp" + android:exported="true" + android:launchMode="singleTop"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <action android:name="android.intent.action.VIEW" /> + </intent-filter> + </activity> + <activity + android:name=".BubbleActivity" + android:label="BubbleApp" + android:exported="false" + android:resizeableActivity="true" /> </application> </manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png Binary files differnew file mode 100644 index 000000000000..d424a17b4157 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml new file mode 100644 index 000000000000..b43f31da748d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/> + <path + android:fillColor="#FF000000" + android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/> + <path + android:fillColor="#FF000000" + android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"/> +</vector> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml new file mode 100644 index 000000000000..0e8c7a0fe64a --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,4c-4.97,0 -9,3.58 -9,8c0,1.53 0.49,2.97 1.33,4.18c0.12,0.18 0.2,0.46 0.1,0.66c-0.33,0.68 -0.79,1.52 -1.38,2.39c-0.12,0.17 0.01,0.41 0.21,0.39c0.63,-0.05 1.86,-0.26 3.38,-0.91c0.17,-0.07 0.36,-0.06 0.52,0.03C8.55,19.54 10.21,20 12,20c4.97,0 9,-3.58 9,-8S16.97,4 12,4zM16.94,11.63l-3.29,3.29c-0.13,0.13 -0.34,0.04 -0.34,-0.14v-1.57c0,-0.11 -0.1,-0.21 -0.21,-0.2c-2.19,0.06 -3.65,0.65 -5.14,1.95c-0.15,0.13 -0.38,0 -0.33,-0.19c0.7,-2.57 2.9,-4.57 5.5,-4.75c0.1,-0.01 0.18,-0.09 0.18,-0.19V8.2c0,-0.18 0.22,-0.27 0.34,-0.14l3.29,3.29C17.02,11.43 17.02,11.55 16.94,11.63z" + android:fillColor="#000000" + android:fillType="evenOdd"/> +</vector> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml new file mode 100644 index 000000000000..f8b0ca3da26e --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <Button + android:id="@+id/button_finish" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:layout_marginStart="8dp" + android:text="Finish" /> + <Button + android:id="@+id/button_new_task" + android:layout_width="wrap_content" + android:layout_height="46dp" + android:layout_marginStart="8dp" + android:text="New Task" /> + <Button + android:id="@+id/button_new_bubble" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:text="New Bubble" /> + + <Button + android:id="@+id/button_activity_for_result" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:text="Activity For Result" /> +</LinearLayout> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml new file mode 100644 index 000000000000..f23c46455c63 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 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. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@android:color/black"> + + <Button + android:id="@+id/button_create" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:text="Add Bubble" /> + + <Button + android:id="@+id/button_cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/button_create" + android:layout_centerHorizontal="true" + android:layout_marginTop="20dp" + android:text="Cancel Bubble" /> + + <Button + android:id="@+id/button_cancel_all" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/button_cancel" + android:layout_centerHorizontal="true" + android:layout_marginTop="20dp" + android:text="Cancel All Bubble" /> +</RelativeLayout> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java new file mode 100644 index 000000000000..bc3bc75ab903 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.testapp; + + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.widget.Toast; + +public class BubbleActivity extends Activity { + private int mNotifId = 0; + + public BubbleActivity() { + super(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent != null) { + mNotifId = intent.getIntExtra(BubbleHelper.EXTRA_BUBBLE_NOTIF_ID, -1); + } else { + mNotifId = -1; + } + + setContentView(R.layout.activity_bubble); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + String result = resultCode == Activity.RESULT_OK ? "OK" : "CANCELLED"; + Toast.makeText(this, "Activity result: " + result, Toast.LENGTH_SHORT).show(); + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java new file mode 100644 index 000000000000..d743dffd3c9e --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.testapp; + + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Person; +import android.app.RemoteInput; +import android.content.Context; +import android.content.Intent; +import android.graphics.Point; +import android.graphics.drawable.Icon; +import android.os.SystemClock; +import android.service.notification.StatusBarNotification; +import android.view.WindowManager; + +import java.util.HashMap; + +public class BubbleHelper { + + static final String EXTRA_BUBBLE_NOTIF_ID = "EXTRA_BUBBLE_NOTIF_ID"; + static final String CHANNEL_ID = "bubbles"; + static final String CHANNEL_NAME = "Bubbles"; + static final int DEFAULT_HEIGHT_DP = 300; + + private static BubbleHelper sInstance; + + private final Context mContext; + private NotificationManager mNotificationManager; + private float mDisplayHeight; + + private HashMap<Integer, BubbleInfo> mBubbleMap = new HashMap<>(); + + private int mNextNotifyId = 0; + private int mColourIndex = 0; + + public static class BubbleInfo { + public int id; + public int height; + public Icon icon; + + public BubbleInfo(int id, int height, Icon icon) { + this.id = id; + this.height = height; + this.icon = icon; + } + } + + public static BubbleHelper getInstance(Context context) { + if (sInstance == null) { + sInstance = new BubbleHelper(context); + } + return sInstance; + } + + private BubbleHelper(Context context) { + mContext = context; + mNotificationManager = context.getSystemService(NotificationManager.class); + + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, + NotificationManager.IMPORTANCE_DEFAULT); + channel.setDescription("Channel that posts bubbles"); + channel.setAllowBubbles(true); + mNotificationManager.createNotificationChannel(channel); + + Point p = new Point(); + WindowManager wm = context.getSystemService(WindowManager.class); + wm.getDefaultDisplay().getRealSize(p); + mDisplayHeight = p.y; + + } + + private int getNextNotifyId() { + int id = mNextNotifyId; + mNextNotifyId++; + return id; + } + + private Icon getIcon() { + return Icon.createWithResource(mContext, R.drawable.bg); + } + + public int addNewBubble(boolean autoExpand, boolean suppressNotif) { + int id = getNextNotifyId(); + BubbleInfo info = new BubbleInfo(id, DEFAULT_HEIGHT_DP, getIcon()); + mBubbleMap.put(info.id, info); + + Notification.BubbleMetadata data = getBubbleBuilder(info) + .setSuppressNotification(suppressNotif) + .setAutoExpandBubble(false) + .build(); + Notification notification = getNotificationBuilder(info.id) + .setBubbleMetadata(data).build(); + + mNotificationManager.notify(info.id, notification); + return info.id; + } + + private Notification.Builder getNotificationBuilder(int id) { + Person chatBot = new Person.Builder() + .setBot(true) + .setName("BubbleBot") + .setImportant(true) + .build(); + + RemoteInput remoteInput = new RemoteInput.Builder("key") + .setLabel("Reply") + .build(); + + String shortcutId = "BubbleChat"; + return new Notification.Builder(mContext, CHANNEL_ID) + .setChannelId(CHANNEL_ID) + .setShortcutId(shortcutId) + .setContentIntent(PendingIntent.getActivity(mContext, 0, + new Intent(mContext, LaunchBubbleActivity.class), + PendingIntent.FLAG_UPDATE_CURRENT)) + .setStyle(new Notification.MessagingStyle(chatBot) + .setConversationTitle("Bubble Chat") + .addMessage("Hello? This is bubble: " + id, + SystemClock.currentThreadTimeMillis() - 300000, chatBot) + .addMessage("Is it me, " + id + ", you're looking for?", + SystemClock.currentThreadTimeMillis(), chatBot) + ) + .setSmallIcon(R.drawable.ic_bubble); + } + + private Notification.BubbleMetadata.Builder getBubbleBuilder(BubbleInfo info) { + Intent target = new Intent(mContext, BubbleActivity.class); + target.putExtra(EXTRA_BUBBLE_NOTIF_ID, info.id); + PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, info.id, target, + PendingIntent.FLAG_UPDATE_CURRENT); + + return new Notification.BubbleMetadata.Builder() + .setIntent(bubbleIntent) + .setIcon(info.icon) + .setDesiredHeight(info.height); + } + + public void cancel(int id) { + mNotificationManager.cancel(id); + } + + public void cancelAll() { + mNotificationManager.cancelAll(); + } + + public void cancelLast() { + StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications(); + if (activeNotifications.length > 0) { + mNotificationManager.cancel( + activeNotifications[activeNotifications.length - 1].getId()); + } + } + + public void cancelFirst() { + StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications(); + if (activeNotifications.length > 0) { + mNotificationManager.cancel(activeNotifications[0].getId()); + } + } +} 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 index 0ead91bb37de..0ed59bdafd1d 100644 --- 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 @@ -87,4 +87,16 @@ public class Components { public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".SplitScreenSecondaryActivity"); } + + public static class LaunchBubbleActivity { + public static final String LABEL = "LaunchBubbleApp"; + public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME, + PACKAGE_NAME + ".LaunchBubbleActivity"); + } + + public static class BubbleActivity { + public static final String LABEL = "BubbleApp"; + public static final ComponentName COMPONENT = new ComponentName(PACKAGE_NAME, + PACKAGE_NAME + ".BubbleActivity"); + } } diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java new file mode 100644 index 000000000000..71fa66d8a61c --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.testapp; + + +import android.app.Activity; +import android.app.Person; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.graphics.drawable.Icon; +import android.os.Bundle; +import android.view.View; + +import java.util.Arrays; + +public class LaunchBubbleActivity extends Activity { + + private BubbleHelper mBubbleHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addInboxShortcut(getApplicationContext()); + mBubbleHelper = BubbleHelper.getInstance(this); + setContentView(R.layout.activity_main); + findViewById(R.id.button_create).setOnClickListener(this::add); + findViewById(R.id.button_cancel).setOnClickListener(this::cancel); + findViewById(R.id.button_cancel_all).setOnClickListener(this::cancelAll); + } + + private void add(View v) { + mBubbleHelper.addNewBubble(false /* autoExpand */, false /* suppressNotif */); + } + + private void cancel(View v) { + mBubbleHelper.cancelLast(); + } + + private void cancelAll(View v) { + mBubbleHelper.cancelAll(); + } + + private void addInboxShortcut(Context context) { + Icon icon = Icon.createWithResource(this, R.drawable.bg); + Person[] persons = new Person[4]; + for (int i = 0; i < persons.length; i++) { + persons[i] = new Person.Builder() + .setBot(false) + .setIcon(icon) + .setName("google" + i) + .setImportant(true) + .build(); + } + + ShortcutInfo shortcut = new ShortcutInfo.Builder(context, "BubbleChat") + .setShortLabel("BubbleChat") + .setLongLived(true) + .setIntent(new Intent(Intent.ACTION_VIEW)) + .setIcon(Icon.createWithResource(context, R.drawable.ic_message)) + .setPersons(persons) + .build(); + ShortcutManager scmanager = context.getSystemService(ShortcutManager.class); + scmanager.addDynamicShortcuts(Arrays.asList(shortcut)); + } + +} |