diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 1471d1cbc74cd..d810fb8257a9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -234,12 +234,22 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged mExecutor.execute(() -> { final Point lastSurfacePosition = mImeSourceControl != null ? mImeSourceControl.getSurfacePosition() : null; + final boolean positionChanged = + !activeControl.getSurfacePosition().equals(lastSurfacePosition); + final boolean leashChanged = + !haveSameLeash(mImeSourceControl, activeControl); mImeSourceControl = activeControl; - if (!activeControl.getSurfacePosition().equals(lastSurfacePosition) - && mAnimation != null) { - startAnimation(mImeShowing, true /* forceRestart */); - } else if (!mImeShowing) { - removeImeSurface(); + if (mAnimation != null) { + if (positionChanged) { + startAnimation(mImeShowing, true /* forceRestart */); + } + } else { + if (leashChanged) { + applyVisibilityToLeash(); + } + if (!mImeShowing) { + removeImeSurface(); + } } }); } @@ -247,6 +257,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } + private void applyVisibilityToLeash() { + SurfaceControl leash = mImeSourceControl.getLeash(); + if (leash != null) { + SurfaceControl.Transaction t = mTransactionPool.acquire(); + if (mImeShowing) { + t.show(leash); + } else { + t.hide(leash); + } + t.apply(); + mTransactionPool.release(t); + } + } + @Override public void showInsets(int types, boolean fromIme) { if ((types & WindowInsets.Type.ime()) == 0) { @@ -502,4 +526,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged return IInputMethodManager.Stub.asInterface( ServiceManager.getService(Context.INPUT_METHOD_SERVICE)); } + + private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a.getLeash() == b.getLeash()) { + return true; + } + if (a.getLeash() == null || b.getLeash() == null) { + return false; + } + return a.getLeash().isSameSurface(b.getLeash()); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java new file mode 100644 index 0000000000000..080cddc58a092 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 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.wm.shell.common; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.InsetsState.ITYPE_IME; +import static android.view.Surface.ROTATION_0; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.graphics.Point; +import android.view.InsetsSourceControl; +import android.view.InsetsState; +import android.view.SurfaceControl; + +import androidx.test.filters.SmallTest; + +import com.android.internal.view.IInputMethodManager; + +import org.junit.Before; +import org.junit.Test; + +@SmallTest +public class DisplayImeControllerTest { + + private SurfaceControl.Transaction mT; + private DisplayImeController.PerDisplay mPerDisplay; + private IInputMethodManager mMock; + + @Before + public void setUp() throws Exception { + mT = mock(SurfaceControl.Transaction.class); + mMock = mock(IInputMethodManager.class); + mPerDisplay = new DisplayImeController(null, null, Runnable::run, new TransactionPool() { + @Override + public SurfaceControl.Transaction acquire() { + return mT; + } + + @Override + public void release(SurfaceControl.Transaction t) { + } + }) { + @Override + public IInputMethodManager getImms() { + return mMock; + } + }.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0); + } + + @Test + public void reappliesVisibilityToChangedLeash() { + verifyZeroInteractions(mT); + + mPerDisplay.mImeShowing = false; + mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] { + new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0)) + }); + + verify(mT).hide(any()); + + mPerDisplay.mImeShowing = true; + mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] { + new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0)) + }); + + verify(mT).show(any()); + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a680213c52a7f..ecf6aaee746d8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6112,7 +6112,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (inputMethodControlTarget != null) { pw.print(" inputMethodControlTarget in display# "); pw.print(displayId); - pw.print(' '); pw.println(inputMethodControlTarget.getWindow()); + pw.print(' '); pw.println(inputMethodControlTarget); } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode);