Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 531604d4 authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

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
parent f5a7230c
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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();
        }

+1 −1
Original line number Diff line number Diff line
@@ -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());
+27 −0
Original line number Diff line number Diff line
@@ -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()
        }
    }
}
+121 −0
Original line number Diff line number Diff line
/*
 * 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<FlickerTestParameter> {
            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
+11 −0
Original line number Diff line number Diff line
@@ -97,5 +97,16 @@
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".DialogThemedActivity"
            android:taskAffinity="com.android.server.wm.flicker.testapp.DialogThemedActivity"
            android:configChanges="orientation|screenSize"
            android:theme="@style/DialogTheme"
            android:label="DialogThemedActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>
Loading