summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Li <lihongyu@google.com> 2022-09-15 15:43:08 +0800
committer Chris Li <lihongyu@google.com> 2022-09-21 10:29:43 +0800
commit61c1234ea27337b28a8d4fe796697971c23c7d91 (patch)
tree167c08d31a4f9d1edf17d3b22ecc151c293d5350
parent624f3aef5e54669718fa4a317a8c2d4a44ca0975 (diff)
Fix IME container surface parent for dual-display-area
1. Loose the requirement of FEATURE_IME_PLACEHOLDER that the device can choose to not reparent the IME container based on their UX design. 2. Make sure the IME surface parent is up-to-date if the IME container window is reparented. Bug: 243842191 Test: atest WmTests:DualDisplayAreaGroupPolicyTest Change-Id: Ie51548a007a8eabd274a35db7dbfc26e3c956216
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java14
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java91
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java2
5 files changed, 106 insertions, 27 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 28093074303d..c6fe017b1917 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4164,7 +4164,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
- final boolean layeringTargetChanged = target != mImeLayeringTarget;
+ boolean shouldUpdateImeParent = target != mImeLayeringTarget;
mImeLayeringTarget = target;
// 1. Reparent the IME container window to the target root DA to get the correct bounds and
@@ -4172,10 +4172,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// 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
- // config.
- targetRoot.placeImeContainer(mImeWindowsContainer);
+ if (targetRoot != null && targetRoot != mImeWindowsContainer.getRootDisplayArea()
+ // Try reparent the IME container to the target root to get the bounds and
+ // config that match the target window.
+ && targetRoot.placeImeContainer(mImeWindowsContainer)) {
+ // Update the IME surface parent since the IME container window has been reparented.
+ shouldUpdateImeParent = true;
// Directly hide the IME window so it doesn't flash immediately after reparenting.
// InsetsController will make IME visible again before animating it.
if (mInputMethodWindow != null) {
@@ -4192,7 +4194,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// 4. Update the IME control target to apply any inset change and animation.
// 5. Reparent the IME container surface to either the input target app, or the IME window
// parent.
- updateImeControlTarget(layeringTargetChanged);
+ updateImeControlTarget(shouldUpdateImeParent);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index d94bb9e89252..092adc37d497 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -22,8 +22,10 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
+import android.util.Slog;
import com.android.server.policy.WindowManagerPolicy;
@@ -76,8 +78,10 @@ class RootDisplayArea extends DisplayArea.Dimmable {
/**
* Places the IME container below this root, so that it's bounds and config will be updated to
* match the root.
+ *
+ * @return {@code true} if the IME container is reparented to this root.
*/
- void placeImeContainer(DisplayArea.Tokens imeContainer) {
+ boolean placeImeContainer(DisplayArea.Tokens imeContainer) {
final RootDisplayArea previousRoot = imeContainer.getRootDisplayArea();
List<Feature> features = mFeatures;
@@ -94,11 +98,23 @@ class RootDisplayArea extends DisplayArea.Dimmable {
previousRoot.updateImeContainerForLayers(null /* imeContainer */);
imeContainer.reparent(imeDisplayAreas.get(0), POSITION_TOP);
updateImeContainerForLayers(imeContainer);
- return;
+ return true;
}
}
- throw new IllegalStateException(
- "There is no FEATURE_IME_PLACEHOLDER in this root to place the IME container");
+
+ // Some device UX may not have the need to update the IME bounds and position for IME target
+ // in a child DisplayArea, so instead of throwing exception, we just allow the IME container
+ // to remain in its previous root.
+ if (!isDescendantOf(previousRoot)) {
+ // When this RootDisplayArea is a descendant of the current RootDisplayArea, it will be
+ // at the APPLICATION_LAYER, and the IME container will always be on top and have bounds
+ // equal or larger than the input target.
+ // If it is not a descendant, the DisplayAreaPolicy owner should make sure the IME is
+ // working correctly. Print a warning in case they are not.
+ Slog.w(TAG_WM, "The IME target is not in the same root as the IME container, but there "
+ + "is no DisplayArea of FEATURE_IME_PLACEHOLDER in the target RootDisplayArea");
+ }
+ return false;
}
/**
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 2956c14155b9..ac3d0f0d3f28 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -46,6 +46,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -55,6 +56,8 @@ import android.window.IDisplayAreaOrganizer;
import androidx.test.filters.SmallTest;
+import com.google.android.collect.Lists;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -90,7 +93,11 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
@Before
public void setUp() {
// Let the Display to be created with the DualDisplay policy.
- final DisplayAreaPolicy.Provider policyProvider = new DualDisplayTestPolicyProvider();
+ setupDisplay(new DualDisplayTestPolicyProvider(mWm));
+ }
+
+ /** Populates fields for the test display. */
+ private void setupDisplay(@NonNull DisplayAreaPolicy.Provider policyProvider) {
doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
// Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait).
@@ -383,6 +390,36 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
}
@Test
+ public void testPlaceImeContainer_noReparentIfRootDoesNotHaveImePlaceholder() {
+ // Define the DualDisplayArea hierarchy without IME_PLACEHOLDER in DAGs.
+ setupDisplay(new DualDisplayTestPolicyProvider(new ArrayList<>(), new ArrayList<>()));
+ 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);
+
+ // firstActivityWin should be the target
+ final WindowState firstActivityWin =
+ createWindow(null /* parent */, TYPE_APPLICATION_STARTING, mFirstActivity,
+ "firstActivityWin");
+ spyOn(firstActivityWin);
+ doReturn(true).when(firstActivityWin).canBeImeTarget();
+ WindowState imeTarget = mDisplay.computeImeTarget(true /* updateImeTarget */);
+
+ // There is no IME_PLACEHOLDER in the firstRoot, so the ImeContainer will not be reparented.
+ assertThat(imeTarget).isEqualTo(firstActivityWin);
+ verify(mFirstRoot).placeImeContainer(imeContainer);
+ assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mDisplay);
+ assertThat(imeContainer.getParent().asDisplayArea().mFeatureId)
+ .isEqualTo(FEATURE_IME_PLACEHOLDER);
+ assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
+ assertThat(mFirstRoot.findAreaForTokenInLayer(imeToken)).isNull();
+ assertThat(mSecondRoot.findAreaForTokenInLayer(imeToken)).isNull();
+ }
+
+ @Test
public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() {
mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
@@ -523,9 +560,37 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
/** Policy to create a dual {@link DisplayAreaGroup} policy in test. */
static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider {
+ @NonNull
+ private final List<DisplayAreaPolicyBuilder.Feature> mFirstRootFeatures = new ArrayList<>();
+ @NonNull
+ private final List<DisplayAreaPolicyBuilder.Feature> mSecondRootFeatures =
+ new ArrayList<>();
+
+ DualDisplayTestPolicyProvider(@NonNull WindowManagerService wmService) {
+ // Add IME_PLACEHOLDER by default.
+ this(Lists.newArrayList(new DisplayAreaPolicyBuilder.Feature.Builder(
+ wmService.mPolicy,
+ "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
+ .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
+ .build()),
+ Lists.newArrayList(new DisplayAreaPolicyBuilder.Feature.Builder(
+ wmService.mPolicy,
+ "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
+ .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
+ .build()));
+ }
+
+ DualDisplayTestPolicyProvider(
+ @NonNull List<DisplayAreaPolicyBuilder.Feature> firstRootFeatures,
+ @NonNull List<DisplayAreaPolicyBuilder.Feature> secondRootFeatures) {
+ mFirstRootFeatures.addAll(firstRootFeatures);
+ mSecondRootFeatures.addAll(secondRootFeatures);
+ }
+
@Override
- public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
- RootDisplayArea root, DisplayArea.Tokens imeContainer) {
+ public DisplayAreaPolicy instantiate(@NonNull WindowManagerService wmService,
+ @NonNull DisplayContent content, @NonNull RootDisplayArea root,
+ @NonNull DisplayArea.Tokens imeContainer) {
// Root
// Include FEATURE_WINDOWED_MAGNIFICATION because it will be used as the screen rotation
// layer
@@ -554,12 +619,10 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
firstTdaList.add(firstTaskDisplayArea);
DisplayAreaPolicyBuilder.HierarchyBuilder firstHierarchy =
new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
- .setTaskDisplayAreas(firstTdaList)
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(
- wmService.mPolicy,
- "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
- .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
- .build());
+ .setTaskDisplayAreas(firstTdaList);
+ for (DisplayAreaPolicyBuilder.Feature feature : mFirstRootFeatures) {
+ firstHierarchy.addFeature(feature);
+ }
// Second
final RootDisplayArea secondRoot = new DisplayAreaGroup(wmService, "SecondRoot",
@@ -570,12 +633,10 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
secondTdaList.add(secondTaskDisplayArea);
DisplayAreaPolicyBuilder.HierarchyBuilder secondHierarchy =
new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
- .setTaskDisplayAreas(secondTdaList)
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(
- wmService.mPolicy,
- "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
- .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
- .build());
+ .setTaskDisplayAreas(secondTdaList);
+ for (DisplayAreaPolicyBuilder.Feature feature : mSecondRootFeatures) {
+ secondHierarchy.addFeature(feature);
+ }
return new DisplayAreaPolicyBuilder()
.setRootHierarchy(rootHierarchy)
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
index d48711375d5c..3090590938c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
@@ -78,7 +78,7 @@ public class InputMethodDialogWindowContextTest extends WindowTestsBase {
public void setUp() throws Exception {
// Let the Display be created with the DualDisplay policy.
final DisplayAreaPolicy.Provider policyProvider =
- new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
+ new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(mWm);
Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
mWindowContext = new InputMethodDialogWindowContext();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
index 168567332795..f6d0bf110047 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
@@ -213,7 +213,7 @@ public class WindowContextListenerControllerTests extends WindowTestsBase {
public void testImeSwitchDialogWindowTokenRemovedOnDualDisplayContent_ListenToImeContainer() {
// Let the Display to be created with the DualDisplay policy.
final DisplayAreaPolicy.Provider policyProvider =
- new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
+ new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(mWm);
doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
// Create a DisplayContent with dual RootDisplayArea
DualDisplayAreaGroupPolicyTest.DualDisplayContent dualDisplayContent =