From 531604d4a7d9206c7bde5f0c0c03d8621ca6b14a Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Thu, 30 Dec 2021 23:36:22 +0800 Subject: [PATCH] Fix IME snapshot applied on non-IME input target window In case when the activity shows IME, transitioning from non-IME input targeted dialog activity will see a weird IME snapshot sliding down animation during the dialog dismissing. Also added a flicker test to verify this behavior. Fix: 210868010 Test: manual as below steps: 1) Launch keep note app 2) Tap on any url link to popup "open with" dialog 3) Tap anywhere else on the screen to dismiss the dialog 4) Expect no IME sliding down animation Test: atest LaunchAppShowImeAndDialogThemeAppTest Test: atest DisplayContentTests#testAttachAndShowImeScreenshotOnTarget Change-Id: Ibccaea46547e57b3439c5e787f97a261fbb10125 --- .../com/android/server/wm/DisplayContent.java | 9 +- .../server/wm/DisplayContentTests.java | 2 +- .../flicker/helpers/ImeAppAutoFocusHelper.kt | 27 ++++ .../LaunchAppShowImeAndDialogThemeAppTest.kt | 121 ++++++++++++++++++ .../test-apps/flickerapp/AndroidManifest.xml | 11 ++ .../flickerapp/res/layout/activity_ime.xml | 5 + .../flickerapp/res/values/styles.xml | 12 +- .../wm/flicker/testapp/ActivityOptions.java | 4 + .../flicker/testapp/DialogThemedActivity.java | 57 +++++++++ .../flicker/testapp/ImeActivityAutoFocus.java | 6 + 10 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt create mode 100644 tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 217fc09ae21df..4698e794eb03e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3987,11 +3987,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (target == mImeLayeringTarget) { return; } - // Prepare the IME screenshot for the last IME target when its task is applying app - // transition. This is for the better IME transition to keep IME visibility when - // transitioning to the next task. + // If the IME target is the input target, before it changes, prepare the IME screenshot + // for the last IME target when its task is applying app transition. This is for the + // better IME transition to keep IME visibility when transitioning to the next task. if (mImeLayeringTarget != null && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) { + ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS) + && mImeLayeringTarget == mImeInputTarget) { attachAndShowImeScreenshotOnTarget(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 2f78b588f3055..97ea72467858f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1982,6 +1982,7 @@ public class DisplayContentTests extends WindowTestsBase { // Test step 1: appWin1 is the current IME target and soft-keyboard is visible. mDisplayContent.computeImeTarget(true); assertEquals(appWin1, mDisplayContent.getImeTarget(IME_TARGET_LAYERING)); + mDisplayContent.setImeInputTarget(appWin1); spyOn(mDisplayContent.mInputMethodWindow); doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible(); mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true); @@ -1998,7 +1999,6 @@ public class DisplayContentTests extends WindowTestsBase { // be shown at this time. final Transaction t = mDisplayContent.getPendingTransaction(); spyOn(t); - mDisplayContent.setImeInputTarget(appWin2); mDisplayContent.computeImeTarget(true); assertEquals(appWin2, mDisplayContent.getImeTarget(IME_TARGET_LAYERING)); assertTrue(mDisplayContent.shouldImeAttachedToApp()); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt index 0b1748a6bda41..6d67ee7366046 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt @@ -17,7 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation +import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.traces.common.FlickerComponentName import com.android.server.wm.traces.parser.toFlickerComponent @@ -47,4 +49,29 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor( } launcherStrategy.launch(appName, expectedPackage) } + + fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) { + val button = uiDevice.wait(Until.findObject(By.res(getPackage(), + "start_dialog_themed_activity_btn")), FIND_TIMEOUT) + + require(button != null) { + "Button not found, this usually happens when the device " + + "was left in an unknown state (e.g. Screen turned off)" + } + button.click() + wmHelper.waitForAppTransitionIdle() + wmHelper.waitForFullScreenApp( + ActivityOptions.DIALOG_THEMED_ACTIVITY_COMPONENT_NAME.toFlickerComponent()) + } + fun dismissDialog(wmHelper: WindowManagerStateHelper) { + val dialog = uiDevice.wait( + Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT) + + // Tapping outside of the dialog to dismiss + if (dialog != null) { + val dialogBounds = dialog.visibleBounds + uiDevice.click(dialogBounds.left, dialogBounds.top - 300) + wmHelper.waitForAppTransitionIdle() + } + } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt new file mode 100644 index 0000000000000..7b0d714b52869 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt @@ -0,0 +1,121 @@ +/* + * 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.ime + +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit +import android.view.Surface +import android.view.WindowManagerPolicyConstants +import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +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.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper +import com.android.server.wm.traces.common.FlickerComponentName +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity. + * To run this test: `atest FlickerTests:LaunchAppShowImeAndDialogThemeAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + setup { + eachRun { + testApp.launchViaIntent(wmHelper) + wmHelper.waitImeShown() + testApp.startDialogThemedActivity(wmHelper) + } + } + teardown { + eachRun { + testApp.exit() + } + } + transitions { + testApp.dismissDialog(wmHelper) + } + } + } + + /** + * Checks that [FlickerComponentName.IME] layer becomes visible during the transition + */ + @Presubmit + @Test + fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible() + + /** + * Checks that [FlickerComponentName.IME] layer is visible at the end of the transition + */ + @Presubmit + @Test + fun imeLayerExistsEnd() { + testSpec.assertLayersEnd { + this.isVisible(FlickerComponentName.IME) + } + } + + /** + * Checks that [FlickerComponentName.IME_SNAPSHOT] layer is invisible always. + */ + @Presubmit + @Test + fun imeSnapshotNotVisible() { + testSpec.assertLayers { + this.isInvisible(FlickerComponentName.IME_SNAPSHOT) + } + } + + 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 { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests( + repetitions = 3, + supportedRotations = listOf(Surface.ROTATION_0), + supportedNavigationModes = listOf( + WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, + WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY + ) + ) + } + } +} \ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index 0a88f6bb5908d..9e371e5e381e7 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -97,5 +97,16 @@ + + + + + + diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml index 2620ff407efc9..baaf7073b3a6b 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml @@ -31,4 +31,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Finish activity" /> +