diff options
| author | 2021-11-18 08:07:52 +0000 | |
|---|---|---|
| committer | 2021-11-18 08:07:52 +0000 | |
| commit | 44cc52baf20ad262a2ede388ef7d2db9db401120 (patch) | |
| tree | f3ee4afcf30eb4b4b7cac8a94f2336c1e686545c | |
| parent | 8216561843e771279dda445e2aaa4ea968053151 (diff) | |
| parent | f68fbed31124933773be699828b3c956d337b3cd (diff) | |
Merge "Enable vendors to organize ImeContainer"
5 files changed, 117 insertions, 5 deletions
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index 6758a3b411a2..974a1dd50cf5 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -109,6 +109,18 @@ public class DisplayAreaOrganizer extends WindowOrganizer { public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8; /** + * Display area hosting IME window tokens (@see ImeContainer). By default, IMEs are parented + * to FEATURE_IME_PLACEHOLDER but can be reparented under other RootDisplayArea. + * + * This feature can register organizers in order to disable the reparenting logic and manage + * the position and settings of the container manually. This is useful for foldable devices + * which require custom UX rules for the IME position (e.g. IME on one screen and the focused + * app on another screen). + * @hide + */ + public static final int FEATURE_IME = FEATURE_SYSTEM_FIRST + 9; + + /** * The last boundary of display area for system features */ public static final int FEATURE_SYSTEM_LAST = 10_000; diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 63fb7939ae60..132396bbf441 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -586,7 +586,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { }; Tokens(WindowManagerService wms, Type type, String name) { - super(wms, type, name, FEATURE_WINDOW_TOKENS); + this(wms, type, name, FEATURE_WINDOW_TOKENS); + } + + Tokens(WindowManagerService wms, Type type, String name, int featureId) { + super(wms, type, name, featureId); } void addChild(WindowToken token) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4cb70fd011ed..42c81248da34 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -78,6 +78,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.DisplayAreaOrganizer.FEATURE_IME; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; @@ -632,7 +633,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @interface InputMethodTarget {} /** The surface parent of the IME container. */ - private SurfaceControl mInputMethodSurfaceParent; + @VisibleForTesting + SurfaceControl mInputMethodSurfaceParent; /** The screenshot IME surface to place on the task while transitioning to the next task. */ SurfaceControl mImeScreenshot; @@ -3831,6 +3833,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } boolean shouldImeAttachedToApp() { + if (mImeWindowsContainer.isOrganized()) { + return false; + } + // Force attaching IME to the display when magnifying, or it would be magnified with // target app together. final boolean allowAttachToApp = (mMagnificationSpec == null); @@ -3959,8 +3965,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mImeLayeringTarget = target; // 1. Reparent the IME container window to the target root DA to get the correct bounds and - // config. (Only happens when the target window is in a different root DA) - if (target != null) { + // config. Only happens when the target window is in a different root DA and ImeContainer + // is not organized (see FEATURE_IME and updateImeParent). + if (target != null && !mImeWindowsContainer.isOrganized()) { RootDisplayArea targetRoot = target.getRootDisplayArea(); if (targetRoot != null && targetRoot != mImeWindowsContainer.getRootDisplayArea()) { // Reposition the IME container to the target root to get the correct bounds and @@ -4144,6 +4151,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void updateImeParent() { + if (mImeWindowsContainer.isOrganized()) { + if (DEBUG_INPUT_METHOD) { + Slog.i(TAG_WM, "ImeContainer is organized. Skip updateImeParent."); + } + // Leave the ImeContainer where the DisplayAreaPolicy placed it. + // FEATURE_IME is organized by vendor so they are responible for placing the surface. + mInputMethodSurfaceParent = null; + return; + } + final SurfaceControl newParent = computeImeParent(); if (newParent != null && newParent != mInputMethodSurfaceParent) { mInputMethodSurfaceParent = newParent; @@ -4750,7 +4767,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp boolean mNeedsLayer = false; ImeContainer(WindowManagerService wms) { - super(wms, Type.ABOVE_TASKS, "ImeContainer"); + super(wms, Type.ABOVE_TASKS, "ImeContainer", FEATURE_IME); } public void setNeedsLayer() { @@ -4811,6 +4828,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp super.assignRelativeLayer(t, relativeTo, layer, forceUpdate); mNeedsLayer = false; } + + @Override + void setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared) { + super.setOrganizer(organizer, skipDisplayAreaAppeared); + mDisplayContent.updateImeParent(); + } } @Override @@ -4909,6 +4932,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private void assignRelativeLayerForIme(SurfaceControl.Transaction t, boolean forceUpdate) { + if (mImeWindowsContainer.isOrganized()) { + if (DEBUG_INPUT_METHOD) { + Slog.i(TAG_WM, "ImeContainer is organized. Skip assignRelativeLayerForIme."); + } + // Leave the ImeContainer where the DisplayAreaPolicy placed it. + // When using FEATURE_IME, Organizer assumes the responsibility for placing the surface. + return; + } + mImeWindowsContainer.setNeedsLayer(); final WindowState imeTarget = mImeLayeringTarget; // In the case where we have an IME target that is not in split-screen mode IME diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 562e95855001..08be15e16b37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -102,6 +102,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.when; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; @@ -134,6 +135,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.View; import android.view.WindowManager; +import android.window.IDisplayAreaOrganizer; import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; @@ -390,6 +392,32 @@ public class DisplayContentTests extends WindowTestsBase { assertNull("computeImeParent() should be null", mDisplayContent.computeImeParent()); } + @Test + public void testUpdateImeParent_skipForOrganizedImeContainer() { + final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); + final ActivityRecord activity = createActivityRecord(mDisplayContent); + + final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, + "startingWin"); + startingWin.setHasSurface(true); + assertTrue(startingWin.canBeImeTarget()); + final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class); + doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent(); + + // Main precondition for this test: organize the ImeContainer. + final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class); + when(mockImeOrganizer.asBinder()).thenReturn(new Binder()); + imeContainer.setOrganizer(mockImeOrganizer); + + mDisplayContent.updateImeParent(); + + assertNull("Don't reparent the surface of an organized ImeContainer.", + mDisplayContent.mInputMethodSurfaceParent); + + // Clean up organizer. + imeContainer.setOrganizer(null); + } + /** * This tests root task movement between displays and proper root task's, task's and app token's * display container references updates. diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java index 4509ff48206e..dbb7fae548b7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -41,14 +41,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.Display; +import android.window.IDisplayAreaOrganizer; import androidx.test.filters.SmallTest; @@ -346,6 +349,39 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { } @Test + public void testPlaceImeContainer_skipReparentForOrganizedImeContainer() { + setupImeWindow(); + final DisplayArea.Tokens imeContainer = mDisplay.getImeContainer(); + final WindowToken imeToken = tokenOfType(TYPE_INPUT_METHOD); + + // By default, the ime container is attached to DC as defined in DAPolicy. + assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mDisplay); + assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer); + + final WindowState firstActivityWin = + createWindow(null /* parent */, TYPE_APPLICATION_STARTING, mFirstActivity, + "firstActivityWin"); + spyOn(firstActivityWin); + // firstActivityWin should be the target + doReturn(true).when(firstActivityWin).canBeImeTarget(); + + // Main precondition for this test: organize the ImeContainer. + final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class); + when(mockImeOrganizer.asBinder()).thenReturn(new Binder()); + imeContainer.setOrganizer(mockImeOrganizer); + + WindowState imeTarget = mDisplay.computeImeTarget(true /* updateImeTarget */); + + // The IME target must be updated but the don't reparent organized ImeContainers. + // See DisplayAreaOrganizer#FEATURE_IME. + assertThat(imeTarget).isEqualTo(firstActivityWin); + verify(mFirstRoot, never()).placeImeContainer(imeContainer); + + // Clean up organizer. + imeContainer.setOrganizer(null); + } + + @Test public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() { mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); |