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

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

Fix IME insets animation stucked by wrong InsetsHint

There is a chance that if InsetsSourceProvider#updateControlForTarget
invoked when its serverVisible not yet visible, then the insetsHint of
the new InsetsSourceControl will be empty because CL[1] will set
insets source frame as empty when the serverVisible is false.

This would make the insetsHint of the control may not able to get
updated if the source frame size is same as the last visible source
frame in the next onPostLayout, that affects the insets animation
will not fullly animated because of wrong InsetsHint.

Add a mInsetsHint field in InsetsSourceProvider to strore the last
insetsHint from onPostLayout for initializing the new source control.

[1]: Ie7845de2830cdbdfd0049b8eef5a5f0704f796e8

Fix: 230581950
Bug: 229938982
Test: manual as issue steps.
Test: atest InsetsStateControllTest#testGetInsetsHintForNewControl
Change-Id: I0fd5845d1f816b558deeed490c93ec207e2f0607
parent c0573c98
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ abstract class InsetsSourceProvider {
    private boolean mIsLeashReadyForDispatching;
    private final Rect mSourceFrame = new Rect();
    private final Rect mLastSourceFrame = new Rect();
    private @NonNull Insets mInsetsHint = Insets.NONE;

    private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
        if (mControl != null) {
@@ -298,6 +299,7 @@ abstract class InsetsSourceProvider {
                if (!insetsHint.equals(mControl.getInsetsHint())) {
                    changed = true;
                    mControl.setInsetsHint(insetsHint);
                    mInsetsHint = insetsHint;
                }
                mLastSourceFrame.set(mSource.getFrame());
            }
@@ -433,8 +435,8 @@ abstract class InsetsSourceProvider {
        final SurfaceControl leash = mAdapter.mCapturedLeash;
        mControlTarget = target;
        updateVisibility();
        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
                mSource.calculateInsets(mWindowContainer.getBounds(), true /* ignoreVisibility */));
        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition, mInsetsHint);

        ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
                "InsetsSource Control %s for target %s", mControl, mControlTarget);
    }
+30 −0
Original line number Diff line number Diff line
@@ -449,6 +449,36 @@ public class InsetsStateControllerTest extends WindowTestsBase {
        assertNotNull(app.getInsetsState().peekSource(ITYPE_NAVIGATION_BAR));
    }

    @UseTestDisplay(addWindows = W_INPUT_METHOD)
    @Test
    public void testGetInsetsHintForNewControl() {
        final WindowState app1 = createTestWindow("app1");
        final WindowState app2 = createTestWindow("app2");

        makeWindowVisible(mImeWindow);
        final InsetsSourceProvider imeInsetsProvider = getController().getSourceProvider(ITYPE_IME);
        imeInsetsProvider.setWindowContainer(mImeWindow, null, null);
        imeInsetsProvider.updateSourceFrame(mImeWindow.getFrame());

        imeInsetsProvider.updateControlForTarget(app1, false);
        imeInsetsProvider.onPostLayout();
        final InsetsSourceControl control1 = imeInsetsProvider.getControl(app1);
        assertNotNull(control1);
        assertEquals(imeInsetsProvider.getSource().getFrame().height(),
                control1.getInsetsHint().bottom);

        // Simulate the IME control target updated from app1 to app2 when IME insets was invisible.
        imeInsetsProvider.setServerVisible(false);
        imeInsetsProvider.updateControlForTarget(app2, false);

        // Verify insetsHint of the new control is same as last IME source frame after the layout.
        imeInsetsProvider.onPostLayout();
        final InsetsSourceControl control2 = imeInsetsProvider.getControl(app2);
        assertNotNull(control2);
        assertEquals(imeInsetsProvider.getSource().getFrame().height(),
                control2.getInsetsHint().bottom);
    }

    private WindowState createTestWindow(String name) {
        final WindowState win = createWindow(null, TYPE_APPLICATION, name);
        win.setHasSurface(true);