Merge "Fix IME switch dialog crash on Dual rootDA display" into sc-dev am: c8bf38ce25

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14305130

Change-Id: I014c3f314db5fe6c166e9833f5e8cadb15d01e96
This commit is contained in:
Charles Chen
2021-05-11 04:19:23 +00:00
committed by Automerger Merge Worker
10 changed files with 97 additions and 37 deletions

View File

@@ -37,7 +37,8 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/**
* Base class for presentations.
* <p>
@@ -153,7 +154,7 @@ public class Presentation extends Dialog {
private final Display mDisplay;
private final DisplayManager mDisplayManager;
private final Handler mHandler = new Handler(Preconditions.checkNotNull(Looper.myLooper(),
private final Handler mHandler = new Handler(Objects.requireNonNull(Looper.myLooper(),
"Presentation must be constructed on a looper thread."));
/**

View File

@@ -158,7 +158,7 @@ public class Preconditions {
* be converted to a string using {@link String#valueOf(Object)}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
* @deprecated - use {@link java.util.Objects.requireNonNull} instead.
* @deprecated - use {@link java.util.Objects#requireNonNull} instead.
*/
@Deprecated
@UnsupportedAppUsage

View File

@@ -74,8 +74,8 @@ public abstract class DisplayAreaPolicy {
*/
public abstract void addWindow(WindowToken token);
/** Gets the {@link DisplayArea} which a {@link WindowToken} is about to be attached to. */
public abstract DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
/** Gets the {@link DisplayArea} with given window type and launched options */
public abstract DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay);
/**

View File

@@ -756,7 +756,14 @@ class DisplayAreaPolicyBuilder {
@VisibleForTesting
DisplayArea.Tokens findAreaForToken(WindowToken token) {
return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions)
.findAreaForToken(token);
.findAreaForTokenInLayer(token);
}
@Override
public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
ownerCanManageAppTokens, roundedCornerOverlay);
}
@VisibleForTesting
@@ -794,13 +801,6 @@ class DisplayAreaPolicyBuilder {
public TaskDisplayArea getDefaultTaskDisplayArea() {
return mDefaultTaskDisplayArea;
}
@Override
public DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
return mSelectRootForWindowFunc.apply(type, options).findAreaForToken(type,
ownerCanManageAppTokens, roundedCornerOverlay);
}
}
static class PendingArea {

View File

@@ -1123,15 +1123,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
token.mDisplayContent = this;
// Add non-app token to container hierarchy on the display. App tokens are added through
// the parent container managing them (e.g. Tasks).
switch (token.windowType) {
case TYPE_INPUT_METHOD:
case TYPE_INPUT_METHOD_DIALOG:
mImeWindowsContainer.addChild(token);
break;
default:
mDisplayAreaPolicy.addWindow(token);
break;
}
final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
da.addChild(token);
}
}
@@ -5982,7 +5975,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mMagnificationSpec;
}
DisplayArea getAreaForWindowToken(int windowType, Bundle options,
DisplayArea findAreaForWindowType(int windowType, Bundle options,
boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
// TODO(b/159767464): figure out how to find an appropriate TDA.
if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
@@ -5994,10 +5987,28 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
return getImeContainer();
}
return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
ownerCanManageAppToken, roundedCornerOverlay);
}
/**
* Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
* <p>
* Note that the differences between this API and
* {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
* {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
* from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
* hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
* {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
* </p>
*
* @see DisplayContent#findAreaForTokenInLayer(WindowToken)
*/
DisplayArea findAreaForToken(WindowToken windowToken) {
return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
}
@Override
DisplayContent asDisplayContent() {
return this;

View File

@@ -101,15 +101,24 @@ class RootDisplayArea extends DisplayArea.Dimmable {
"There is no FEATURE_IME_PLACEHOLDER in this root to place the IME container");
}
/** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
/**
* Finds the {@link DisplayArea.Tokens} in {@code mAreaForLayer} that this type of window
* should be attached to.
* <p>
* Note that in most cases, users are expected to call
* {@link DisplayContent#findAreaForToken(WindowToken)} to find a {@link DisplayArea} in
* {@link DisplayContent} level instead of calling this inner method.
* </p>
*/
@Nullable
DisplayArea.Tokens findAreaForToken(WindowToken token) {
return findAreaForToken(token.windowType, token.mOwnerCanManageAppTokens,
DisplayArea.Tokens findAreaForTokenInLayer(WindowToken token) {
return findAreaForWindowTypeInLayer(token.windowType, token.mOwnerCanManageAppTokens,
token.mRoundedCornerOverlay);
}
/** @see #findAreaForTokenInLayer(WindowToken) */
@Nullable
DisplayArea.Tokens findAreaForToken(int windowType, boolean ownerCanManageAppTokens,
DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay) {
int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
ownerCanManageAppTokens, roundedCornerOverlay);

View File

@@ -201,7 +201,9 @@ class WindowContextListenerController {
return mContainer;
}
private void updateContainer(WindowContainer newContainer) {
private void updateContainer(@NonNull WindowContainer newContainer) {
Objects.requireNonNull(newContainer);
if (mContainer.equals(newContainer)) {
return;
}

View File

@@ -2688,7 +2688,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
// TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
// the feature b/155340867 is completed.
final DisplayArea da = dc.getAreaForWindowToken(type, options,
final DisplayArea da = dc.findAreaForWindowType(type, options,
callerCanManageAppTokens, false /* roundedCornerOverlay */);
mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
callingUid, type, options);

View File

@@ -268,7 +268,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
// By default, the ime container is attached to DC as defined in DAPolicy.
assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mDisplay);
assertThat(mDisplay.findAreaForToken(imeToken)).isEqualTo(imeContainer);
assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
final WindowState firstActivityWin =
createWindow(null /* parent */, TYPE_APPLICATION_STARTING, mFirstActivity,
@@ -290,9 +290,9 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mFirstRoot);
assertThat(imeContainer.getParent().asDisplayArea().mFeatureId)
.isEqualTo(FEATURE_IME_PLACEHOLDER);
assertThat(mDisplay.findAreaForToken(imeToken)).isNull();
assertThat(mFirstRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
assertThat(mSecondRoot.findAreaForToken(imeToken)).isNull();
assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isNull();
assertThat(mFirstRoot.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
assertThat(mSecondRoot.findAreaForTokenInLayer(imeToken)).isNull();
// secondActivityWin should be the target
doReturn(false).when(firstActivityWin).canBeImeTarget();
@@ -305,9 +305,9 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondRoot);
assertThat(imeContainer.getParent().asDisplayArea().mFeatureId)
.isEqualTo(FEATURE_IME_PLACEHOLDER);
assertThat(mDisplay.findAreaForToken(imeToken)).isNull();
assertThat(mFirstRoot.findAreaForToken(imeToken)).isNull();
assertThat(mSecondRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isNull();
assertThat(mFirstRoot.findAreaForTokenInLayer(imeToken)).isNull();
assertThat(mSecondRoot.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
}
@Test

View File

@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static com.google.common.truth.Truth.assertThat;
@@ -38,6 +39,7 @@ import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
/**
* Build/Install/Run:
@@ -185,6 +187,41 @@ public class WindowContextListenerControllerTests extends WindowTestsBase {
assertThat(mController.getContainer(mClientToken)).isEqualTo(da);
}
@Test
public void testImeSwitchDialogWindowTokenRemovedOnDualDisplayContent_ListenToImeContainer() {
// Let the Display to be created with the DualDisplay policy.
final DisplayAreaPolicy.Provider policyProvider =
new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
// Create a DisplayContent with dual RootDisplayArea
DualDisplayAreaGroupPolicyTest.DualDisplayContent dualDisplayContent =
new DualDisplayAreaGroupPolicyTest.DualDisplayContent
.Builder(mAtm, 1000, 1000).build();
final DisplayArea.Tokens imeContainer = dualDisplayContent.getImeContainer();
// Put the ImeContainer to the first sub-RootDisplayArea
dualDisplayContent.mFirstRoot.placeImeContainer(imeContainer);
assertThat(imeContainer.getRootDisplayArea()).isEqualTo(dualDisplayContent.mFirstRoot);
// Simulate the behavior to show IME switch dialog: its context switches to register to
// context created WindowToken.
WindowToken windowContextCreatedToken = new WindowToken.Builder(mWm, mClientToken,
TYPE_INPUT_METHOD_DIALOG)
.setDisplayContent(dualDisplayContent)
.setFromClientToken(true)
.build();
mController.registerWindowContainerListener(mClientToken, windowContextCreatedToken,
TEST_UID, TYPE_INPUT_METHOD_DIALOG, null /* options */);
assertThat(mController.getContainer(mClientToken)).isEqualTo(windowContextCreatedToken);
// Remove WindowToken
windowContextCreatedToken.removeImmediately();
// Now context should listen to ImeContainer.
assertThat(mController.getContainer(mClientToken)).isEqualTo(imeContainer);
}
private class TestWindowTokenClient extends IWindowToken.Stub {
private Configuration mConfiguration;
private int mDisplayId;