From e124ea53511460880a3448fab7c04b6f606d362a Mon Sep 17 00:00:00 2001 From: Wilson Wu Date: Sat, 7 Jan 2023 16:47:44 +0800 Subject: [PATCH] Introduce ImeTargetVisibilityPolicy This class provides ime target visibility utility functions from IMMS to WM as: -. update ime screenshot -. update ime parent This change only build the class and no module rely on it so it shouldn't have behavior changes. Bug: 258048231 Test: atest WmTests:ZOrderingTests#testImeScreenshotLayer Change-Id: Ie567ba578dca65be0a9a11d9a4aa27a13fe69900 --- .../com/android/server/wm/DisplayContent.java | 39 +++++++++++----- .../server/wm/ImeTargetVisibilityPolicy.java | 45 +++++++++++++++++++ .../server/wm/WindowManagerService.java | 43 ++++++++++++++++++ .../server/wm/SystemServicesTestRule.java | 1 + .../com/android/server/wm/ZOrderingTests.java | 27 +++++++++++ 5 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index eadb11e7c6e0d..dcceeb6affc04 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4320,6 +4320,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mImeTarget; } + @VisibleForTesting + SurfaceControl getImeScreenshotSurface() { + return mImeSurface; + } + private SurfaceControl createImeSurface(ScreenCapture.ScreenshotHardwareBuffer b, Transaction t) { final HardwareBuffer buffer = b.getHardwareBuffer(); @@ -4429,33 +4434,45 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - private void attachAndShowImeScreenshotOnTarget() { + private void attachImeScreenshotOnTargetIfNeeded() { // No need to attach screenshot if the IME target not exists or screen is off. if (!shouldImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) { return; } - final SurfaceControl.Transaction t = getPendingTransaction(); // Prepare IME screenshot for the target if it allows to attach into. if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) { - // Remove the obsoleted IME snapshot first in case the new snapshot happens to - // override the current one before the transition finish and the surface never be - // removed on the task. - removeImeSurfaceImmediately(); - mImeScreenshot = new ImeScreenshot( - mWmService.mSurfaceControlFactory.apply(null), mImeLayeringTarget); - mImeScreenshot.attachAndShow(t); + attachImeScreenshotOnTarget(mImeLayeringTarget); } } + private void attachImeScreenshotOnTarget(WindowState imeTarget) { + final SurfaceControl.Transaction t = getPendingTransaction(); + // Remove the obsoleted IME snapshot first in case the new snapshot happens to + // override the current one before the transition finish and the surface never be + // removed on the task. + removeImeSurfaceImmediately(); + mImeScreenshot = new ImeScreenshot( + mWmService.mSurfaceControlFactory.apply(null), imeTarget); + mImeScreenshot.attachAndShow(t); + } + /** - * Shows the IME screenshot and attach to the IME target window. + * Shows the IME screenshot and attach to the IME layering target window. * * Used when the IME target window with IME visible is transitioning to the next target. * e.g. App transitioning or swiping this the task of the IME target window to recents app. */ void showImeScreenshot() { - attachAndShowImeScreenshotOnTarget(); + attachImeScreenshotOnTargetIfNeeded(); + } + + /** + * Shows the IME screenshot and attach it to the given IME target window. + */ + @VisibleForTesting + void showImeScreenshot(WindowState imeTarget) { + attachImeScreenshotOnTarget(imeTarget); } /** diff --git a/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java new file mode 100644 index 0000000000000..83d0f6ca5ff67 --- /dev/null +++ b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java @@ -0,0 +1,45 @@ +/* + * 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.os.IBinder; + +/** + * A class for {@link com.android.server.inputmethod.InputMethodManagerService} to + * control IME visibility operations in {@link WindowManagerService}. + */ +public abstract class ImeTargetVisibilityPolicy { + + /** + * Shows the IME screenshot and attach it to the given IME target window. + * + * @param imeTarget The target window to show the IME screenshot. + * @param displayId A unique id to identify the display. + * @return {@code true} if success, {@code false} otherwise. + */ + public abstract boolean showImeScreenShot(IBinder imeTarget, int displayId); + + /** + * Updates the IME parent for target window. + * + * @param imeTarget The target window to update the IME parent. + * @param displayId A unique id to identify the display. + * @return {@code true} if success, {@code false} otherwise. + */ + public abstract boolean updateImeParent(IBinder imeTarget, 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 4e7613b66d733..cd03dd5478dbc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1333,6 +1333,8 @@ public class WindowManagerService extends IWindowManager.Stub mConstants.start(new HandlerExecutor(mH)); LocalServices.addService(WindowManagerInternal.class, new LocalService()); + LocalServices.addService( + ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl()); mEmbeddedWindowController = new EmbeddedWindowController(mAtmService); mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( @@ -8333,6 +8335,47 @@ public class WindowManagerService extends IWindowManager.Stub } } + private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { + + // TODO(b/258048231): Track IME visibility change in bugreport when invocations. + @Override + public boolean showImeScreenShot(@NonNull IBinder imeTarget, int displayId) { + synchronized (mGlobalLock) { + final WindowState imeTargetWindow = mWindowMap.get(imeTarget); + if (imeTargetWindow == null) { + return false; + } + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show ime screenshot"); + return false; + } + + dc.showImeScreenshot(imeTargetWindow); + return true; + } + } + + // TODO(b/258048231): Track IME visibility change in bugreport when invocations. + @Override + public boolean updateImeParent(@NonNull IBinder imeTarget, int displayId) { + synchronized (mGlobalLock) { + final WindowState imeTargetWindow = mWindowMap.get(imeTarget); + if (imeTargetWindow == null) { + return false; + } + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to update ime parent"); + return false; + } + + dc.updateImeParent(); + return true; + } + } + } + void registerAppFreezeListener(AppFreezeListener listener) { if (!mAppFreezeListeners.contains(listener)) { mAppFreezeListeners.add(listener); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 42bbd2d40f410..e464905672e69 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -419,6 +419,7 @@ public class SystemServicesTestRule implements TestRule { LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); LocalServices.removeServiceForTest(UserManagerInternal.class); + LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class); } Description getDescription() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 8c581580cf755..9cde7e38a3c42 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -45,16 +45,21 @@ import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; import android.view.IRecentsAnimationRunner; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.window.ScreenCapture; import androidx.test.filters.SmallTest; @@ -569,4 +574,26 @@ public class ZOrderingTests extends WindowTestsBase { assertZOrderGreaterThan(mTransaction, systemDialogWindow.getSurfaceControl(), mDisplayContent.getImeContainer().getSurfaceControl()); } + + @Test + public void testImeScreenshotLayer() { + final Task task = createTask(mDisplayContent); + final WindowState imeAppTarget = createAppWindow(task, TYPE_APPLICATION, "imeAppTarget"); + final Rect bounds = mImeWindow.getParentFrame(); + final ScreenCapture.ScreenshotHardwareBuffer imeBuffer = + ScreenCapture.captureLayersExcluding(mImeWindow.getSurfaceControl(), + bounds, 1.0f, PixelFormat.RGB_565, null); + + spyOn(mDisplayContent.mWmService.mTaskSnapshotController); + doReturn(imeBuffer).when(mDisplayContent.mWmService.mTaskSnapshotController) + .snapshotImeFromAttachedTask(task); + + mDisplayContent.showImeScreenshot(imeAppTarget); + + assertEquals(imeAppTarget, mDisplayContent.mImeScreenshot.getImeTarget()); + assertNotNull(mDisplayContent.mImeScreenshot); + assertZOrderGreaterThan(mTransaction, + mDisplayContent.mImeScreenshot.getImeScreenshotSurface(), + imeAppTarget.mSurfaceControl); + } }