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 c18e9ce761539..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 @@ -43,6 +43,7 @@ import android.view.animation.PathInterpolator; import com.android.internal.view.IInputMethodManager; import java.util.ArrayList; +import java.util.concurrent.Executor; /** * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode. @@ -62,15 +63,21 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged private static final int FLOATING_IME_BOTTOM_INSET = -80; protected final IWindowManager mWmService; - protected final Handler mHandler; + protected final Executor mExecutor; private final TransactionPool mTransactionPool; private final DisplayController mDisplayController; private final SparseArray mImePerDisplay = new SparseArray<>(); private final ArrayList mPositionProcessors = new ArrayList<>(); + @Deprecated public DisplayImeController(IWindowManager wmService, DisplayController displayController, Handler mainHandler, TransactionPool transactionPool) { - mHandler = mainHandler; + this(wmService, displayController, mainHandler::post, transactionPool); + } + + public DisplayImeController(IWindowManager wmService, DisplayController displayController, + Executor mainExecutor, TransactionPool transactionPool) { + mExecutor = mainExecutor; mWmService = wmService; mTransactionPool = transactionPool; mDisplayController = displayController; @@ -197,7 +204,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged @Override public void insetsChanged(InsetsState insetsState) { - mHandler.post(() -> { + mExecutor.execute(() -> { if (mInsetsState.equals(insetsState)) { return; } @@ -224,15 +231,25 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged continue; } if (activeControl.getType() == InsetsState.ITYPE_IME) { - mHandler.post(() -> { + 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(); + } } }); } @@ -240,13 +257,27 @@ 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) { return; } if (DEBUG) Slog.d(TAG, "Got showInsets for ime"); - mHandler.post(() -> startAnimation(true /* show */, false /* forceRestart */)); + mExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */)); } @Override @@ -255,7 +286,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged return; } if (DEBUG) Slog.d(TAG, "Got hideInsets for ime"); - mHandler.post(() -> startAnimation(false /* show */, false /* forceRestart */)); + mExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */)); } @Override @@ -495,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/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java index b113d29f00e66..f2ca4956be07f 100644 --- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java +++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java @@ -50,6 +50,7 @@ public class DisplaySystemBarsController extends DisplayImeController { private final Context mContext; private final DisplayController mDisplayController; + private final Handler mHandler; private SparseArray mPerDisplaySparseArray; public DisplaySystemBarsController( @@ -58,9 +59,10 @@ public class DisplaySystemBarsController extends DisplayImeController { DisplayController displayController, @Main Handler mainHandler, TransactionPool transactionPool) { - super(wmService, displayController, mainHandler, transactionPool); + super(wmService, displayController, (r) -> mainHandler.post(r), transactionPool); mContext = context; mDisplayController = displayController; + mHandler = mainHandler; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java index a50de45e547b4..1e6a9e8dc007b 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java @@ -32,6 +32,8 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; +import java.util.concurrent.Executor; + import dagger.Module; import dagger.Provides; @@ -45,9 +47,10 @@ public class TvWMShellModule { @SysUISingleton @Provides static DisplayImeController provideDisplayImeController(IWindowManager wmService, - DisplayController displayController, @Main Handler mainHandler, + DisplayController displayController, @Main Executor mainExecutor, TransactionPool transactionPool) { - return new DisplayImeController(wmService, displayController, mainHandler, transactionPool); + return new DisplayImeController(wmService, displayController, mainExecutor, + transactionPool); } static SplitScreen provideSplitScreen(Context context, diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 3142c1e762e90..b4852b28619c6 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -45,6 +45,7 @@ import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.Optional; +import java.util.concurrent.Executor; import dagger.Module; import dagger.Provides; @@ -59,9 +60,10 @@ public class WMShellModule { @SysUISingleton @Provides static DisplayImeController provideDisplayImeController(IWindowManager wmService, - DisplayController displayController, @Main Handler mainHandler, + DisplayController displayController, @Main Executor mainExecutor, TransactionPool transactionPool) { - return new DisplayImeController(wmService, displayController, mainHandler, transactionPool); + return new DisplayImeController(wmService, displayController, mainExecutor, + transactionPool); } @SysUISingleton diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e653f9d809544..7d293ddecfd75 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6090,7 +6090,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);