diff options
6 files changed, 96 insertions, 188 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index dba04656e48f..4d06f50d4d45 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -238,6 +238,33 @@ public abstract class InputMethodManagerInternal { public abstract void removeImeSurface(int displayId); /** + * Called when a non-IME-focusable overlay window being the IME layering target (e.g. a + * window with {@link android.view.WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} and + * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flags) + * has changed its window visibility. + * + * @param hasVisibleOverlay whether such an overlay window exists or not + * @param displayId the display ID where the overlay window exists + */ + public abstract void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, int displayId); + + /** + * Called when the visibility of IME input target window has changed. + * + * @param imeInputTarget the window token of the IME input target window + * @param visibleAndNotRemoved {@code true} when the new window is made visible by + * {@code imeInputTarget} and the IME input target window has not + * been removed. The new window is considered to be visible when + * switching to the new visible IME input target window and + * starting input, or the existing input target becomes visible. + * In contrast, {@code false} when closing the input target, or the + * existing input target becomes invisible + * @param displayId the display for which to update the IME window status + */ + public abstract void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, + boolean visibleAndNotRemoved, int displayId); + + /** * Updates the IME visibility, back disposition and show IME picker status for SystemUI. * TODO(b/189923292): Making SystemUI to be true IME icon controller vs. presenter that * controlled by IMMS. @@ -389,6 +416,16 @@ public abstract class InputMethodManagerInternal { public void removeImeSurface(int displayId) { } + @Override + public void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, + int displayId) { + } + + @Override + public void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, + boolean visibleAndNotRemoved, int displayId) { + } + @ImfLockFree @Override public void updateImeWindowStatus(boolean disableImeIcon, int displayId) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3f666a2675c7..1077c50e77f6 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -44,7 +44,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_OTHER; import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED; @@ -188,7 +187,6 @@ import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeS import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.utils.PriorityDump; -import com.android.server.wm.ImeTargetChangeListener; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; @@ -968,37 +966,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. InputMethodDrawsNavBarResourceMonitor.registerCallback(context, mService.mIoHandler, mService::onUpdateResourceOverlay); - // Also hook up ImeTargetChangeListener. - // TODO(b/356876005): Merge this into InputMethodManagerInternal. - final var windowManagerInternal = mService.mWindowManagerInternal; - windowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() { - @Override - public void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken, - @WindowManager.LayoutParams.WindowType int windowType, boolean visible, - boolean removed, int displayId) { - // Ignoring the starting window since it's ok to cover the IME target - // window in temporary without affecting the IME visibility. - final boolean hasOverlay = visible && !removed - && windowType != TYPE_APPLICATION_STARTING; - synchronized (ImfLock.class) { - final var userId = mService.resolveImeUserIdFromDisplayIdLocked(displayId); - mService.getUserData(userId).mVisibilityStateComputer - .setHasVisibleImeLayeringOverlay(hasOverlay); - } - } - - @Override - public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget, - boolean visibleRequested, boolean removed, int displayId) { - final boolean visibleAndNotRemoved = visibleRequested && !removed; - synchronized (ImfLock.class) { - final var userId = mService.resolveImeUserIdFromDisplayIdLocked(displayId); - mService.getUserData(userId).mVisibilityStateComputer - .onImeInputTargetVisibilityChanged(imeInputTarget, - visibleAndNotRemoved); - } - } - }); // Also schedule user init tasks onto an I/O thread. initializeUsersAsync(mService.mUserManagerInternal.getUserIds()); } @@ -6000,6 +5967,25 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget(); } + @Override + public void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, int displayId) { + synchronized (ImfLock.class) { + final var userId = resolveImeUserIdFromDisplayIdLocked(displayId); + getUserData(userId).mVisibilityStateComputer.setHasVisibleImeLayeringOverlay( + hasVisibleOverlay); + } + } + + @Override + public void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, + boolean visibleAndNotRemoved, int displayId) { + synchronized (ImfLock.class) { + final var userId = resolveImeUserIdFromDisplayIdLocked(displayId); + getUserData(userId).mVisibilityStateComputer.onImeInputTargetVisibilityChanged( + imeInputTarget, visibleAndNotRemoved); + } + } + @ImfLockFree @Override public void updateImeWindowStatus(boolean disableImeIcon, int displayId) { diff --git a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java deleted file mode 100644 index e94f17c37051..000000000000 --- a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2023 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.server.wm; - -import android.annotation.NonNull; -import android.os.IBinder; -import android.view.WindowManager; - -/** - * Callback the IME targeting window visibility change state for - * {@link com.android.server.inputmethod.InputMethodManagerService} to manage the IME surface - * visibility and z-ordering. - */ -public interface ImeTargetChangeListener { - /** - * Called when a non-IME-focusable overlay window being the IME layering target (e.g. a - * window with {@link android.view.WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} and - * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flags) - * has changed its window visibility. - * - * @param overlayWindowToken the window token of the overlay window. - * @param windowType the window type of the overlay window. - * @param visible the visibility of the overlay window, {@code true} means visible - * and {@code false} otherwise. - * @param removed Whether the IME target overlay window has being removed. - * @param displayId display ID where the overlay window exists. - */ - default void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken, - @WindowManager.LayoutParams.WindowType int windowType, - boolean visible, boolean removed, int displayId) { - } - - /** - * Called when the visibility of IME input target window has changed. - * - * @param imeInputTarget the window token of the IME input target window. - * @param visible the new window visibility made by {@code imeInputTarget}. visible is - * {@code true} when switching to the new visible IME input target - * window and started input, or the same input target relayout to - * visible from invisible. In contrast, visible is {@code false} when - * closing the input target, or the same input target relayout to - * invisible from visible. - * @param removed Whether the IME input target window has being removed. - * @param displayId display ID where the overlay window exists. - */ - default void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, boolean visible, - boolean removed, int displayId) { - } -} diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index a574845814e8..82d39a39d188 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -990,16 +990,6 @@ public abstract class WindowManagerInternal { } /** - * Sets by the {@link com.android.server.inputmethod.InputMethodManagerService} to monitor - * the visibility change of the IME targeted windows. - * - * @see ImeTargetChangeListener#onImeTargetOverlayVisibilityChanged - * @see ImeTargetChangeListener#onImeInputTargetVisibilityChanged - */ - public abstract void setInputMethodTargetChangeListener( - @NonNull ImeTargetChangeListener listener); - - /** * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}. */ public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index cf92f1bbb9cf..5749272376ac 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -789,7 +789,6 @@ public class WindowManagerService extends IWindowManager.Stub boolean mHardKeyboardAvailable; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; WindowManagerInternal.OnImeRequestedChangedListener mOnImeRequestedChangedListener; - @Nullable ImeTargetChangeListener mImeTargetChangeListener; SettingsObserver mSettingsObserver; final EmbeddedWindowController mEmbeddedWindowController; @@ -3517,29 +3516,28 @@ public class WindowManagerService extends IWindowManager.Stub void dispatchImeTargetOverlayVisibilityChanged(@NonNull IBinder token, @WindowManager.LayoutParams.WindowType int windowType, boolean visible, boolean removed, int displayId) { - if (mImeTargetChangeListener != null) { - if (DEBUG_INPUT_METHOD) { - Slog.d(TAG, "onImeTargetOverlayVisibilityChanged, win=" + mWindowMap.get(token) - + ", type=" + ViewDebug.intToString(WindowManager.LayoutParams.class, - "type", windowType) + "visible=" + visible + ", removed=" + removed - + ", displayId=" + displayId); - } - mH.post(() -> mImeTargetChangeListener.onImeTargetOverlayVisibilityChanged(token, - windowType, visible, removed, displayId)); + if (DEBUG_INPUT_METHOD) { + Slog.d(TAG, "onImeTargetOverlayVisibilityChanged, win=" + mWindowMap.get(token) + + ", type=" + ViewDebug.intToString(WindowManager.LayoutParams.class, + "type", windowType) + "visible=" + visible + ", removed=" + removed + + ", displayId=" + displayId); } + // Ignoring the starting window since it's ok to cover the IME target + // window in temporary without affecting the IME visibility. + final boolean hasOverlay = visible && !removed && windowType != TYPE_APPLICATION_STARTING; + mH.post(() -> InputMethodManagerInternal.get().setHasVisibleImeLayeringOverlay(hasOverlay, + displayId)); } void dispatchImeInputTargetVisibilityChanged(@NonNull IBinder token, boolean visible, boolean removed, int displayId) { - if (mImeTargetChangeListener != null) { - if (DEBUG_INPUT_METHOD) { - Slog.d(TAG, "onImeInputTargetVisibilityChanged, win=" + mWindowMap.get(token) - + "visible=" + visible + ", removed=" + removed - + ", displayId" + displayId); - } - mH.post(() -> mImeTargetChangeListener.onImeInputTargetVisibilityChanged(token, - visible, removed, displayId)); + if (DEBUG_INPUT_METHOD) { + Slog.d(TAG, "onImeInputTargetVisibilityChanged, win=" + mWindowMap.get(token) + + "visible=" + visible + ", removed=" + removed + ", displayId=" + displayId); } + final boolean visibleAndNotRemoved = visible && !removed; + mH.post(() -> InputMethodManagerInternal.get().onImeInputTargetVisibilityChanged(token, + visibleAndNotRemoved, displayId)); } @Override @@ -8675,13 +8673,6 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void setInputMethodTargetChangeListener(@NonNull ImeTargetChangeListener listener) { - synchronized (mGlobalLock) { - mImeTargetChangeListener = listener; - } - } - - @Override public void setOrientationRequestPolicy(boolean respected, int[] fromOrientations, int[] toOrientations) { synchronized (mGlobalLock) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 11df331ff398..39276a191fb9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -77,8 +77,10 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; import android.content.res.CompatibilityInfo; @@ -111,6 +113,7 @@ import android.window.TaskFragmentOrganizer; import androidx.test.filters.SmallTest; +import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.testutils.StubTransaction; import com.android.server.wm.SensitiveContentPackages.PackageInfo; @@ -1337,8 +1340,8 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testImeTargetChangeListener_OnImeInputTargetVisibilityChanged() { - final TestImeTargetChangeListener listener = new TestImeTargetChangeListener(); - mWm.mImeTargetChangeListener = listener; + final InputMethodManagerInternal immi = InputMethodManagerInternal.get(); + spyOn(immi); final WindowState imeTarget = createWindow(null /* parent */, TYPE_BASE_APPLICATION, createActivityRecord(mDisplayContent), "imeTarget"); @@ -1347,32 +1350,26 @@ public class WindowStateTests extends WindowTestsBase { makeWindowVisible(imeTarget); mDisplayContent.setImeInputTarget(imeTarget); waitHandlerIdle(mWm.mH); - - assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); - assertThat(listener.mIsRemoved).isFalse(); - assertThat(listener.mIsVisibleForImeInputTarget).isTrue(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(), + true /* visibleAndNotRemoved */, mDisplayContent.getDisplayId()); + reset(immi); imeTarget.mActivityRecord.setVisibleRequested(false); waitHandlerIdle(mWm.mH); - - assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); - assertThat(listener.mIsRemoved).isFalse(); - assertThat(listener.mIsVisibleForImeInputTarget).isFalse(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(), + false /* visibleAndNotRemoved */, mDisplayContent.getDisplayId()); + reset(immi); imeTarget.removeImmediately(); - assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); - assertThat(listener.mIsRemoved).isTrue(); - assertThat(listener.mIsVisibleForImeInputTarget).isFalse(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(), + false /* visibleAndNotRemoved */, mDisplayContent.getDisplayId()); } @SetupWindows(addWindows = {W_INPUT_METHOD}) @Test public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged() { - final TestImeTargetChangeListener listener = new TestImeTargetChangeListener(); - mWm.mImeTargetChangeListener = listener; + final InputMethodManagerInternal immi = InputMethodManagerInternal.get(); + spyOn(immi); // Scenario 1: test addWindow/relayoutWindow to add Ime layering overlay window as visible. final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY, @@ -1402,10 +1399,10 @@ public class WindowStateTests extends WindowTestsBase { final WindowState imeLayeringTargetOverlay = mDisplayContent.getWindow( w -> w.mClient.asBinder() == client.asBinder()); assertThat(imeLayeringTargetOverlay.isVisible()).isTrue(); - assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); - assertThat(listener.mIsRemoved).isFalse(); - assertThat(listener.mIsVisibleForImeTargetOverlay).isTrue(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi, atLeast(1)) + .setHasVisibleImeLayeringOverlay(true /* hasVisibleOverlay */, + mDisplayContent.getDisplayId()); + reset(immi); // Scenario 2: test relayoutWindow to let the Ime layering target overlay window invisible. mWm.relayoutWindow(session, client, params, 100, 200, View.GONE, 0, 0, 0, @@ -1413,19 +1410,16 @@ public class WindowStateTests extends WindowTestsBase { waitHandlerIdle(mWm.mH); assertThat(imeLayeringTargetOverlay.isVisible()).isFalse(); - assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); - assertThat(listener.mIsRemoved).isFalse(); - assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi).setHasVisibleImeLayeringOverlay(false /* hasVisibleOverlay */, + mDisplayContent.getDisplayId()); + reset(immi); // Scenario 3: test removeWindow to remove the Ime layering target overlay window. mWm.removeClientToken(session, client.asBinder()); waitHandlerIdle(mWm.mH); - assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); - assertThat(listener.mIsRemoved).isTrue(); - assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse(); - assertThat(listener.mDisplayId).isEqualTo(mDisplayContent.getDisplayId()); + verify(immi).setHasVisibleImeLayeringOverlay(false /* hasVisibleOverlay */, + mDisplayContent.getDisplayId()); } @Test @@ -1468,31 +1462,4 @@ public class WindowStateTests extends WindowTestsBase { mWm.mSensitiveContentPackages.removeBlockScreenCaptureForApps(blockedPackages); assertFalse(window.isSecureLocked()); } - - private static class TestImeTargetChangeListener implements ImeTargetChangeListener { - private IBinder mImeTargetToken; - private boolean mIsRemoved; - private boolean mIsVisibleForImeTargetOverlay; - private boolean mIsVisibleForImeInputTarget; - private int mDisplayId; - - @Override - public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, - @WindowManager.LayoutParams.WindowType int windowType, boolean visible, - boolean removed, int displayId) { - mImeTargetToken = overlayWindowToken; - mIsVisibleForImeTargetOverlay = visible; - mIsRemoved = removed; - mDisplayId = displayId; - } - - @Override - public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget, - boolean visibleRequested, boolean removed, int displayId) { - mImeTargetToken = imeInputTarget; - mIsVisibleForImeInputTarget = visibleRequested; - mIsRemoved = removed; - mDisplayId = displayId; - } - } } |