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

Commit 44cab451 authored by Wilson Wu's avatar Wilson Wu
Browse files

Fix wrong ime parent in embedded activity

We have CL[1] to polish the ime transition. But in
ActivityEmbedding, the ime layering target may higher
than input target. And the ime parent didn't be updated
since input target and layering target are unsync.

Update ime parent for this case.

[1]: I332c0e4fff62df5d7b793eda2767bb58fe85a938

Bug: 260387203
Test: Manual test with test apk in the bug
Test: atest TaskFragmentTest#testUpdateImeParentForActivityEmbedding
Change-Id: I78c82a0677d2ab7a1e247e91e5dfa1e5235e95bb
parent 7137d916
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4589,7 +4589,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     */
    @VisibleForTesting
    SurfaceControl computeImeParent() {
        if (!ImeTargetVisibilityPolicy.isReadyToComputeImeParent(mImeLayeringTarget,
        if (!ImeTargetVisibilityPolicy.isValidToComputeImeParent(mImeLayeringTarget,
                mImeInputTarget)) {
            return null;
        }
+31 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;

import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;

import android.annotation.Nullable;
import android.os.IBinder;
import android.view.WindowManager;

@@ -50,10 +51,12 @@ public abstract class ImeTargetVisibilityPolicy {
     * Called when {@link DisplayContent#computeImeParent()} to check if it's valid to keep
     * computing the ime parent.
     *
     * @param imeLayeringTarget The window which IME target to layer on top of it.
     * @param imeInputTarget The window which start the input connection, receive input from IME.
     * @return {@code true} to keep computing the ime parent, {@code false} to defer this operation
     */
    public static boolean isReadyToComputeImeParent(WindowState imeLayeringTarget,
            InputTarget imeInputTarget) {
    public static boolean isValidToComputeImeParent(@Nullable WindowState imeLayeringTarget,
            @Nullable InputTarget imeInputTarget) {
        if (imeLayeringTarget == null) {
            return false;
        }
@@ -69,7 +72,9 @@ public abstract class ImeTargetVisibilityPolicy {
        boolean imeLayeringTargetMayUseIme =
                WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags)
                        || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;

        if (isImeTargetMismatchOnEmbedding(imeLayeringTarget, imeInputTarget)) {
            return true;
        }
        // Do not change parent if the window hasn't requested IME.
        var inputAndLayeringTargetsDisagree = (imeInputTarget == null
                || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord());
@@ -77,4 +82,27 @@ public abstract class ImeTargetVisibilityPolicy {

        return !inputTargetStale;
    }

    private static boolean isImeTargetMismatchOnEmbedding(
            @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) {
        if (imeInputTarget == null || imeLayeringTarget == null) {
            return false;
        }
        final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord();
        final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord();
        final WindowState inputTargetWindow = imeInputTarget.getWindowState();
        if (inputTargetRecord == null || layeringTargetRecord == null
                || inputTargetWindow == null) {
            return false;
        }
        final boolean isImeTargetEmbedded = inputTargetRecord.isEmbedded()
                && layeringTargetRecord.isEmbedded();
        // The IME layering target is calculated by the window hierarchy in DisplayContent.
        // The layering target and input target may be different when the window hasn't started
        // input connection, WMS hasn't received the target which reported from IMMS. We basically
        // won't update IME parent for better IME transition.
        // But in activity embedding, tapping a window won't update it to the top window so the IME
        // layering target may higher than input target. Update IME parent for this case.
        return isImeTargetEmbedded && imeLayeringTarget.compareTo(inputTargetWindow) > 0;
    }
}
+31 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -613,4 +614,34 @@ public class TaskFragmentTest extends WindowTestsBase {
        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, tf1.getOrientation(SCREEN_ORIENTATION_UNSET));
        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, task.getOrientation(SCREEN_ORIENTATION_UNSET));
    }

    @Test
    public void testUpdateImeParentForActivityEmbedding() {
        // Setup two activities in ActivityEmbedding.
        final Task task = createTask(mDisplayContent);
        final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
                .setParentTask(task)
                .createActivityCount(1)
                .setOrganizer(mOrganizer)
                .setFragmentToken(new Binder())
                .build();
        final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
                .setParentTask(task)
                .createActivityCount(1)
                .setOrganizer(mOrganizer)
                .setFragmentToken(new Binder())
                .build();
        final ActivityRecord activity0 = tf0.getTopMostActivity();
        final ActivityRecord activity1 = tf1.getTopMostActivity();
        final WindowState win0 = createWindow(null, TYPE_BASE_APPLICATION, activity0, "win0");
        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity1, "win1");
        doReturn(false).when(mDisplayContent).shouldImeAttachedToApp();

        mDisplayContent.setImeInputTarget(win0);
        mDisplayContent.setImeLayeringTarget(win1);

        // The ImeParent should be the display.
        assertEquals(mDisplayContent.getImeContainer().getParent().getSurfaceControl(),
                mDisplayContent.computeImeParent());
    }
}