Merge "Fix IME switch dialog crash on Dual rootDA display" into sc-dev
This commit is contained in:
@@ -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."));
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user