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

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

Fix focus cleared and password keyboard shown during IME switching

When IME switches, InputMethodService will be rebound and re-initialize
input view, since it needs take time to update the layout, if the insets
calculation happens during the layout, the givenContentInsets are not ready
yet during this phases, then the insets size will abnormal
and may cause the IME target layout will be resized to zero height after
applied insets change.

If the view layout is focused, system will clear such 0-sized view
focus, since user can't easily aware and it's not safe to focus on invisible view
(refer CL[1]), then after IME switches, input connection will break because
the view focus lost.

Make sure to set the valid IME insets sources frame when the server side visible
set as true in InsetSourceProvider.

[1]: 5db64eb1

Fix: 153612876
Test: atest InsetsSourceProviderTest#testUpdateSourceFrameForIme
Test: atest InsetsSourceTest InsetsStateTest InsetsSourceProviderTest \
            InsetsControllerTest InsetsStateControllerTest \
            InsetsSourceConsumerTest
Test: atest ImeInsetsControllerTest

Change-Id: Id2c482e112c1d73cf7d5b3ba5e1a2d5775f47298
parent 672ebfc2
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -166,12 +166,19 @@ class InsetsSourceProvider {
            return;
        }

        // Make sure we set the valid source frame only when server visible is true, because the
        // frame may not yet determined that server side doesn't think the window is ready to
        // visible. (i.e. No surface, pending insets that were given during layout, etc..)
        if (mServerVisible) {
            mTmpRect.set(mWin.getFrameLw());
            if (mFrameProvider != null) {
                mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
            } else {
                mTmpRect.inset(mWin.mGivenContentInsets);
            }
        } else {
            mTmpRect.setEmpty();
        }
        mSource.setFrame(mTmpRect);

        if (mImeFrameProvider != null) {
+31 −0
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.server.wm;

import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,12 +46,17 @@ public class InsetsSourceProviderTest extends WindowTestsBase {

    private InsetsSource mSource = new InsetsSource(ITYPE_STATUS_BAR);
    private InsetsSourceProvider mProvider;
    private InsetsSource mImeSource = new InsetsSource(ITYPE_IME);
    private InsetsSourceProvider mImeProvider;

    @Before
    public void setUp() throws Exception {
        mSource.setVisible(true);
        mProvider = new InsetsSourceProvider(mSource,
                mDisplayContent.getInsetsStateController(), mDisplayContent);
        mProvider.setServerVisible(true);
        mImeProvider = new InsetsSourceProvider(mImeSource,
                mDisplayContent.getInsetsStateController(), mDisplayContent);
    }

    @Test
@@ -165,6 +172,30 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
        assertNull(mProvider.getControl(target));
    }

    @Test
    public void testUpdateSourceFrameForIme() {
        final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");

        inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500));

        mImeProvider.setWindow(inputMethod, null, null);
        mImeProvider.setServerVisible(false);
        mImeSource.setVisible(true);
        mImeProvider.updateSourceFrame();
        assertEquals(new Rect(0, 0, 0, 0), mImeSource.getFrame());
        Insets insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
                false /* ignoreVisibility */);
        assertEquals(Insets.of(0, 0, 0, 0), insets);

        mImeProvider.setServerVisible(true);
        mImeSource.setVisible(true);
        mImeProvider.updateSourceFrame();
        assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame());
        insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
                false /* ignoreVisibility */);
        assertEquals(Insets.of(0, 0, 0, 100), insets);
    }

    @Test
    public void testInsetsModified() {
        final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");