Merge "Add WM Flicker Tests for App Compat" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
64bd2e2cad
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.appcompat
|
||||
|
||||
import android.content.Context
|
||||
import android.system.helpers.CommandsHelper
|
||||
import android.tools.device.flicker.legacy.FlickerBuilder
|
||||
import android.tools.device.flicker.legacy.FlickerTest
|
||||
import com.android.wm.shell.flicker.BaseTest
|
||||
import com.android.server.wm.flicker.helpers.setRotation
|
||||
import com.android.server.wm.flicker.helpers.LetterboxAppHelper
|
||||
import android.tools.device.flicker.legacy.FlickerTestFactory
|
||||
import android.tools.device.flicker.legacy.IFlickerTestData
|
||||
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
|
||||
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
|
||||
import org.junit.Assume
|
||||
import org.junit.Before
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
|
||||
protected val context: Context = instrumentation.context
|
||||
protected val letterboxApp = LetterboxAppHelper(instrumentation)
|
||||
lateinit var cmdHelper: CommandsHelper
|
||||
lateinit var letterboxStyle: HashMap<String, String>
|
||||
|
||||
/** {@inheritDoc} */
|
||||
override val transition: FlickerBuilder.() -> Unit
|
||||
get() = {
|
||||
setup {
|
||||
setStartRotation()
|
||||
letterboxApp.launchViaIntent(wmHelper)
|
||||
setEndRotation()
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
cmdHelper = CommandsHelper.getInstance(instrumentation)
|
||||
Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
|
||||
}
|
||||
|
||||
private fun mapLetterboxStyle(): HashMap<String, String> {
|
||||
val res = cmdHelper.executeShellCommand("wm get-letterbox-style")
|
||||
val lines = res.lines()
|
||||
val map = HashMap<String, String>()
|
||||
for (line in lines) {
|
||||
val keyValuePair = line.split(":")
|
||||
if (keyValuePair.size == 2) {
|
||||
val key = keyValuePair[0].trim()
|
||||
map[key] = keyValuePair[1].trim()
|
||||
}
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
private fun isIgnoreOrientationRequest(): Boolean {
|
||||
val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
|
||||
return res != null && res.contains("true")
|
||||
}
|
||||
|
||||
fun IFlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
|
||||
|
||||
fun IFlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
|
||||
|
||||
/** Checks that app entering letterboxed state have rounded corners */
|
||||
fun assertLetterboxAppAtStartHasRoundedCorners() {
|
||||
assumeLetterboxRoundedCornersEnabled()
|
||||
flicker.assertLayersStart { this.hasRoundedCorners(letterboxApp) }
|
||||
}
|
||||
|
||||
fun assertLetterboxAppAtEndHasRoundedCorners() {
|
||||
assumeLetterboxRoundedCornersEnabled()
|
||||
flicker.assertLayersEnd { this.hasRoundedCorners(letterboxApp) }
|
||||
}
|
||||
|
||||
/** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
|
||||
private fun assumeLetterboxRoundedCornersEnabled() {
|
||||
if (!::letterboxStyle.isInitialized) {
|
||||
letterboxStyle = mapLetterboxStyle()
|
||||
}
|
||||
Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
|
||||
}
|
||||
|
||||
fun assertLetterboxAppVisibleAtStartAndEnd() {
|
||||
flicker.appWindowIsVisibleAtStart(letterboxApp)
|
||||
flicker.appWindowIsVisibleAtEnd(letterboxApp)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Creates the test configurations.
|
||||
*
|
||||
* See [FlickerTestFactory.rotationTests] for configuring screen orientation and
|
||||
* navigation modes.
|
||||
*/
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<FlickerTest> {
|
||||
return FlickerTestFactory.rotationTests()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.appcompat
|
||||
|
||||
import android.platform.test.annotations.Postsubmit
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import android.tools.device.flicker.legacy.FlickerBuilder
|
||||
import android.tools.device.flicker.legacy.FlickerTest
|
||||
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
|
||||
import android.tools.common.datatypes.component.ComponentNameMatcher
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test launching app in size compat mode.
|
||||
*
|
||||
* To run this test: `atest WMShellFlickerTests:OpenAppInSizeCompatModeTest`
|
||||
*
|
||||
* Actions:
|
||||
* ```
|
||||
* Rotate non resizable portrait only app to opposite orientation to trigger size compat mode
|
||||
* ```
|
||||
* Notes:
|
||||
* ```
|
||||
* Some default assertions (e.g., nav bar, status bar and screen covered)
|
||||
* are inherited [BaseTest]
|
||||
* ```
|
||||
*/
|
||||
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
|
||||
class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
override val transition: FlickerBuilder.() -> Unit
|
||||
get() = {
|
||||
setup {
|
||||
setStartRotation()
|
||||
letterboxApp.launchViaIntent(wmHelper)
|
||||
}
|
||||
transitions { setEndRotation() }
|
||||
teardown { letterboxApp.exit(wmHelper) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows maybe recreated when rotated. Checks that the focus does not change or if it does,
|
||||
* focus returns to [letterboxApp]
|
||||
*/
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun letterboxAppFocusedAtEnd() = flicker.assertEventLog { focusChanges(letterboxApp.`package`) }
|
||||
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
|
||||
|
||||
/**
|
||||
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
|
||||
* flicker, and disappears before the transition is complete
|
||||
*/
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun rotationLayerAppearsAndVanishes() {
|
||||
flicker.assertLayers {
|
||||
this.isVisible(letterboxApp)
|
||||
.then()
|
||||
.isVisible(ComponentNameMatcher.ROTATION)
|
||||
.then()
|
||||
.isVisible(letterboxApp)
|
||||
.isInvisible(ComponentNameMatcher.ROTATION)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.appcompat
|
||||
|
||||
import android.platform.test.annotations.Postsubmit
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import android.tools.device.flicker.legacy.FlickerBuilder
|
||||
import android.tools.device.flicker.legacy.FlickerTest
|
||||
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
|
||||
import android.tools.device.helpers.WindowUtils
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test restarting app in size compat mode.
|
||||
*
|
||||
* To run this test: `atest WMShellFlickerTests:RestartAppInSizeCompatModeTest`
|
||||
*
|
||||
* Actions:
|
||||
* ```
|
||||
* Rotate app to opposite orientation to trigger size compat mode
|
||||
* Press restart button and wait for letterboxed app to resize
|
||||
* ```
|
||||
* Notes:
|
||||
* ```
|
||||
* Some default assertions (e.g., nav bar, status bar and screen covered)
|
||||
* are inherited [BaseTest]
|
||||
* ```
|
||||
*/
|
||||
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
|
||||
class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
override val transition: FlickerBuilder.() -> Unit
|
||||
get() = {
|
||||
super.transition(this)
|
||||
transitions { letterboxApp.clickRestart(wmHelper) }
|
||||
teardown { letterboxApp.exit(wmHelper) }
|
||||
}
|
||||
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
|
||||
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun appLayerVisibilityChanges() {
|
||||
flicker.assertLayers {
|
||||
this.isVisible(letterboxApp)
|
||||
.then()
|
||||
.isInvisible(letterboxApp)
|
||||
.then()
|
||||
.isVisible(letterboxApp)
|
||||
}
|
||||
}
|
||||
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
|
||||
|
||||
/** Checks that the visible region of [letterboxApp] is still within display bounds */
|
||||
@Postsubmit
|
||||
@Test
|
||||
fun appWindowRemainInsideVisibleBounds() {
|
||||
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
|
||||
flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.server.wm.flicker.testapp.ActivityOptions
|
||||
import android.tools.common.datatypes.component.ComponentNameMatcher
|
||||
import android.tools.device.traces.parsers.toFlickerComponent
|
||||
import android.tools.device.traces.parsers.WindowManagerStateHelper
|
||||
import android.tools.device.apphelpers.StandardAppHelper
|
||||
import android.tools.device.helpers.FIND_TIMEOUT
|
||||
import android.tools.device.helpers.SYSTEMUI_PACKAGE
|
||||
|
||||
class LetterboxAppHelper
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.NonResizeablePortraitActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent()
|
||||
) : StandardAppHelper(instr, launcherName, component) {
|
||||
|
||||
fun clickRestart(wmHelper: WindowManagerStateHelper) {
|
||||
val restartButton = uiDevice.wait(Until.findObject(By.res(
|
||||
SYSTEMUI_PACKAGE, "size_compat_restart_button")), FIND_TIMEOUT)
|
||||
restartButton?.run { restartButton.click() } ?: error("Restart button not found")
|
||||
|
||||
// size compat mode restart confirmation dialog button
|
||||
val restartDialogButton = uiDevice.wait(Until.findObject(By.res(
|
||||
SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button")), FIND_TIMEOUT)
|
||||
restartDialogButton?.run { restartDialogButton.click() }
|
||||
?: error("Restart dialog button not found")
|
||||
wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,18 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".NonResizeablePortraitActivity"
|
||||
android:theme="@style/CutoutNever"
|
||||
android:resizeableActivity="false"
|
||||
android:screenOrientation="portrait"
|
||||
android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeablePortraitActivity"
|
||||
android:label="NonResizeablePortraitActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".LaunchNewActivity"
|
||||
android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity"
|
||||
android:theme="@style/CutoutShortEdges"
|
||||
|
||||
@@ -67,6 +67,12 @@ public class ActivityOptions {
|
||||
FLICKER_APP_PACKAGE + ".NonResizeableActivity");
|
||||
}
|
||||
|
||||
public static class NonResizeablePortraitActivity {
|
||||
public static final String LABEL = "NonResizeablePortraitActivity";
|
||||
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
|
||||
FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity");
|
||||
}
|
||||
|
||||
public static class DialogThemedActivity {
|
||||
public static final String LABEL = "DialogThemedActivity";
|
||||
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.server.wm.flicker.testapp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class NonResizeablePortraitActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.activity_non_resizeable);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user