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

Commit 5433f61b authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Remove mImeInsetsFrozenUntilStartInput" into main

parents 56ccb89e 161897ee
Loading
Loading
Loading
Loading
+0 −21
Original line number Diff line number Diff line
@@ -763,13 +763,6 @@ final class ActivityRecord extends WindowToken {
    /** Whether the IME is showing when transitioning away from this activity. */
    boolean mLastImeShown;

    /**
     * When set to true, the IME insets will be frozen until the next app becomes IME input target.
     * @see InsetsPolicy#adjustVisibilityForIme
     * @see ImeInsetsSourceProvider#updateClientVisibility
     */
    boolean mImeInsetsFrozenUntilStartInput;

    /**
     * A flag to determine if this AR is in the process of closing or entering PIP. This is needed
     * to help AR know that the app is in the process of closing but hasn't yet started closing on
@@ -1175,8 +1168,6 @@ final class ActivityRecord extends WindowToken {
                pw.print(" launchMode="); pw.println(launchMode);
        pw.print(prefix); pw.print("mActivityType=");
                pw.println(activityTypeToString(getActivityType()));
        pw.print(prefix); pw.print("mImeInsetsFrozenUntilStartInput=");
                pw.println(mImeInsetsFrozenUntilStartInput);
        if (requestedVrComponent != null) {
            pw.print(prefix);
            pw.print("requestedVrComponent=");
@@ -5874,10 +5865,6 @@ final class ActivityRecord extends WindowToken {
        }

        final DisplayContent displayContent = getDisplayContent();
        if (!visible) {
            mImeInsetsFrozenUntilStartInput = true;
        }

        if (!displayContent.mClosingApps.contains(this)
                && !displayContent.mOpeningApps.contains(this)
                && !fromTransition) {
@@ -6953,14 +6940,6 @@ final class ActivityRecord extends WindowToken {
            // closing activity having to wait until idle timeout to be stopped or destroyed if the
            // next activity won't report idle (e.g. repeated view animation).
            mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();

            // If the activity is visible, but no windows are eligible to start input, unfreeze
            // to avoid permanently frozen IME insets.
            if (mImeInsetsFrozenUntilStartInput && getWindow(
                    win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
                    == null) {
                mImeInsetsFrozenUntilStartInput = false;
            }
        }
    }

+0 −29
Original line number Diff line number Diff line
@@ -4661,35 +4661,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        }
    }

    /**
     * Callback from {@link ImeInsetsSourceProvider#updateClientVisibility} for the system to
     * judge whether or not to notify the IME insets provider to dispatch this reported IME client
     * visibility state to the app clients when needed.
     */
    boolean onImeInsetsClientVisibilityUpdate() {
        boolean[] changed = new boolean[1];

        // Unlike the IME layering target or the control target can be updated during the layout
        // change, the IME input target requires to be changed after gaining the input focus.
        // In case unfreezing IME insets state may too early during IME focus switching, we unfreeze
        // when activities going to be visible until the input target changed, or the
        // activity was the current input target that has to unfreeze after updating the IME
        // client visibility.
        final ActivityRecord inputTargetActivity =
                mImeInputTarget != null ? mImeInputTarget.getActivityRecord() : null;
        final boolean targetChanged = mImeInputTarget != mLastImeInputTarget;
        if (targetChanged || inputTargetActivity != null && inputTargetActivity.isVisibleRequested()
                && inputTargetActivity.mImeInsetsFrozenUntilStartInput) {
            forAllActivities(r -> {
                if (r.mImeInsetsFrozenUntilStartInput && r.isVisibleRequested()) {
                    r.mImeInsetsFrozenUntilStartInput = false;
                    changed[0] = true;
                }
            });
        }
        return changed[0];
    }

    void updateImeControlTarget() {
        updateImeControlTarget(false /* forceUpdateImeParent */);
    }
+0 −1
Original line number Diff line number Diff line
@@ -321,7 +321,6 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
                reportImeDrawnForOrganizerIfNeeded((InsetsControlTarget) caller);
            }
        }
        changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
        if (Flags.refactorInsetsController()) {
            if (changed) {
                ImeTracker.forLogging().onProgress(statsToken,
+0 −16
Original line number Diff line number Diff line
@@ -387,22 +387,6 @@ class InsetsPolicy {
                state.addSource(navSource);
            }
            return state;
        } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
            // During switching tasks with gestural navigation, before the next IME input target
            // starts the input, we should adjust and freeze the last IME visibility of the window
            // in case delivering obsoleted IME insets state during transitioning.
            final InsetsSource originalImeSource = originalState.peekSource(ID_IME);

            if (originalImeSource != null) {
                final boolean imeVisibility = w.isRequestedVisible(Type.ime());
                final InsetsState state = copyState
                        ? new InsetsState(originalState)
                        : originalState;
                final InsetsSource imeSource = new InsetsSource(originalImeSource);
                imeSource.setVisible(imeVisibility);
                state.addSource(imeSource);
                return state;
            }
        } else if (w.mImeInsetsConsumed) {
            // Set the IME source (if there is one) to be invisible if it has been consumed.
            final InsetsSource originalImeSource = originalState.peekSource(ID_IME);
+0 −180
Original line number Diff line number Diff line
@@ -49,17 +49,13 @@ import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsSource.ID_IME;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
@@ -125,7 +121,6 @@ import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.DestroyActivityItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.WindowStateResizeItem;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Intent;
@@ -149,8 +144,6 @@ import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.IWindowManager;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
@@ -171,7 +164,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;

import java.util.ArrayList;
@@ -3370,178 +3362,6 @@ public class ActivityRecordTests extends WindowTestsBase {
        assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
    }

    @SetupWindows(addWindows = W_INPUT_METHOD)
    @Test
    public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
        final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build();
        makeWindowVisibleAndDrawn(app, mImeWindow);
        mDisplayContent.setImeLayeringTarget(app);
        mDisplayContent.setImeInputTarget(app);

        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
        mDisplayContent.mOpeningApps.clear();
        app.mActivityRecord.commitVisibility(false, false);
        app.mActivityRecord.onWindowsGone();

        assertTrue(app.mActivityRecord.mLastImeShown);
        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        // Expect IME insets frozen state will reset when the activity has no IME focusable window.
        app.mActivityRecord.forAllWindows(w -> {
            w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
            return true;
        }, true);

        app.mActivityRecord.commitVisibility(true, false);
        app.mActivityRecord.onWindowsVisible();

        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
    }

    @SetupWindows(addWindows = W_INPUT_METHOD)
    @Test
    public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() {
        final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build();

        mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
                mImeWindow, null, null);
        mImeWindow.getControllableInsetProvider().setServerVisible(true);

        InsetsSource imeSource = new InsetsSource(ID_IME, ime());
        app.mAboveInsetsState.addSource(imeSource);
        mDisplayContent.setImeLayeringTarget(app);
        mDisplayContent.updateImeInputAndControlTarget(app);

        InsetsState state = app.getInsetsState();
        assertFalse(state.getOrCreateSource(imeSource.getId(), ime()).isVisible());
        assertTrue(state.getOrCreateSource(imeSource.getId(), ime()).getFrame().isEmpty());

        // Simulate app is closing and expect IME insets is frozen.
        mDisplayContent.mOpeningApps.clear();
        app.mActivityRecord.commitVisibility(false, false);
        app.mActivityRecord.onWindowsGone();
        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        // Simulate app re-start input or turning screen off/on then unlocked by un-secure
        // keyguard to back to the app, expect IME insets is not frozen
        app.mActivityRecord.commitVisibility(true, false);
        mDisplayContent.updateImeInputAndControlTarget(app);
        performSurfacePlacementAndWaitForWindowAnimator();

        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        imeSource.setVisible(true);
        imeSource.setFrame(new Rect(100, 400, 500, 500));
        app.mAboveInsetsState.addSource(imeSource);

        // Verify when IME is visible and the app can receive the right IME insets from policy.
        makeWindowVisibleAndDrawn(app, mImeWindow);
        state = app.getInsetsState();
        assertTrue(state.peekSource(ID_IME).isVisible());
        assertEquals(state.peekSource(ID_IME).getFrame(), imeSource.getFrame());
    }

    @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
    @Test
    public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
            throws RemoteException {
        final WindowState app1 = newWindowBuilder("app1", TYPE_APPLICATION).build();
        final WindowState app2 = newWindowBuilder("app2", TYPE_APPLICATION).build();

        mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
                mImeWindow, null, null);
        mImeWindow.getControllableInsetProvider().setServerVisible(true);

        // Simulate app2 is closing and let app1 is visible to be IME targets.
        makeWindowVisibleAndDrawn(app1, mImeWindow);
        mDisplayContent.setImeLayeringTarget(app1);
        mDisplayContent.updateImeInputAndControlTarget(app1);
        app2.mActivityRecord.commitVisibility(false, false);

        // app1 requests IME visible.
        app1.setRequestedVisibleTypes(ime(), ime());
        mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1,
                null /* statsToken */);

        // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
        assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
        assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        // Simulate switching to app2 to make it visible to be IME targets.
        spyOn(app2);
        spyOn(app2.mClient);
        spyOn(app2.getProcess());
        ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
        doReturn(true).when(app2).isReadyToDispatchInsetsState();
        mDisplayContent.setImeLayeringTarget(app2);
        app2.mActivityRecord.commitVisibility(true, false);
        mDisplayContent.updateImeInputAndControlTarget(app2);
        performSurfacePlacementAndWaitForWindowAnimator();

        // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
        // to client if the app didn't request IME visible.
        assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        verify(app2.getProcess(), atLeastOnce()).scheduleClientTransactionItem(
                isA(WindowStateResizeItem.class));
        assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
    }

    @Test
    public void testImeInsetsFrozenFlag_multiWindowActivities() {
        final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
        final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).setWindowToken(
                imeToken).build();
        makeWindowVisibleAndDrawn(ime);

        // Create a split-screen root task with activity1 and activity 2.
        final Task task = new TaskBuilder(mSupervisor)
                .setCreateParentTask(true).setCreateActivity(true).build();
        task.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        final ActivityRecord activity1 = task.getTopNonFinishingActivity();
        activity1.getTask().setResumedActivity(activity1, "testApp1");

        final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
                .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
                .setCreateActivity(true).build().getTopMostActivity();
        activity2.getTask().setResumedActivity(activity2, "testApp2");
        activity2.getTask().setParent(task.getRootTask());

        // Simulate activity1 and activity2 both have set mImeInsetsFrozenUntilStartInput when
        // invisible to user.
        activity1.mImeInsetsFrozenUntilStartInput = true;
        activity2.mImeInsetsFrozenUntilStartInput = true;

        final WindowState app1 = newWindowBuilder("app1", TYPE_APPLICATION).setWindowToken(
                activity1).build();
        final WindowState app2 = newWindowBuilder("app2", TYPE_APPLICATION).setWindowToken(
                activity2).build();
        makeWindowVisibleAndDrawn(app1, app2);

        final InsetsStateController controller = mDisplayContent.getInsetsStateController();
        controller.getImeSourceProvider().setWindowContainer(
                ime, null, null);
        ime.getControllableInsetProvider().setServerVisible(true);

        // app1 starts input and expect IME insets for all activities in split-screen will be
        // frozen until the input started.
        mDisplayContent.setImeLayeringTarget(app1);
        mDisplayContent.updateImeInputAndControlTarget(app1);
        mDisplayContent.computeImeTarget(true /* updateImeTarget */);
        performSurfacePlacementAndWaitForWindowAnimator();

        assertEquals(app1, mDisplayContent.getImeInputTarget());
        assertFalse(activity1.mImeInsetsFrozenUntilStartInput);
        assertFalse(activity2.mImeInsetsFrozenUntilStartInput);

        app1.setRequestedVisibleTypes(ime());
        controller.onRequestedVisibleTypesChanged(app1, null /* statsToken */);

        // Expect all activities in split-screen will get IME insets visible state
        assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
        assertTrue(app2.getInsetsState().peekSource(ID_IME).isVisible());
    }

    @Test
    public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() {
        final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build();
Loading