summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Li <lihongyu@google.com> 2021-11-18 08:07:52 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-11-18 08:07:52 +0000
commit44cc52baf20ad262a2ede388ef7d2db9db401120 (patch)
treef3ee4afcf30eb4b4b7cac8a94f2336c1e686545c
parent8216561843e771279dda445e2aaa4ea968053151 (diff)
parentf68fbed31124933773be699828b3c956d337b3cd (diff)
Merge "Enable vendors to organize ImeContainer"
-rw-r--r--core/java/android/window/DisplayAreaOrganizer.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java36
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 */);