diff options
9 files changed, 226 insertions, 168 deletions
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java index 14ed414da9d0..cbe2995f2467 100644 --- a/core/java/android/app/WindowContext.java +++ b/core/java/android/app/WindowContext.java @@ -15,8 +15,7 @@ */ package android.app; -import static android.view.WindowManagerGlobal.ADD_OKAY; -import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS; +import static android.view.WindowManagerImpl.createWindowContextWindowManager; import android.annotation.NonNull; import android.annotation.Nullable; @@ -28,8 +27,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.view.Display; import android.view.IWindowManager; +import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.view.WindowManagerImpl; import com.android.internal.annotations.VisibleForTesting; @@ -46,10 +45,10 @@ import java.lang.ref.Reference; */ @UiContext public class WindowContext extends ContextWrapper { - private final WindowManagerImpl mWindowManager; + private final WindowManager mWindowManager; private final IWindowManager mWms; private final WindowTokenClient mToken; - private boolean mOwnsToken; + private boolean mListenerRegistered; /** * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to @@ -86,25 +85,14 @@ public class WindowContext extends ContextWrapper { mToken.attachContext(this); - mWindowManager = new WindowManagerImpl(this); - mWindowManager.setDefaultToken(mToken); + mWindowManager = createWindowContextWindowManager(this); - int result; try { - // Register the token with WindowManager. This will also call back with the current - // config back to the client. - result = mWms.addWindowTokenWithOptions( - mToken, type, getDisplayId(), options, getPackageName()); + mListenerRegistered = mWms.registerWindowContextListener(mToken, type, getDisplayId(), + options); } catch (RemoteException e) { - mOwnsToken = false; throw e.rethrowFromSystemServer(); } - if (result == ADD_TOO_MANY_TOKENS) { - throw new UnsupportedOperationException("createWindowContext failed! Too many unused " - + "window contexts. Please see Context#createWindowContext documentation for " - + "detail."); - } - mOwnsToken = result == ADD_OKAY; Reference.reachabilityFence(this); } @@ -131,10 +119,10 @@ public class WindowContext extends ContextWrapper { /** Used for test to invoke because we can't invoke finalize directly. */ @VisibleForTesting public void release() { - if (mOwnsToken) { + if (mListenerRegistered) { + mListenerRegistered = false; try { - mWms.removeWindowToken(mToken, getDisplayId()); - mOwnsToken = false; + mWms.unregisterWindowContextListener(mToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 987de3fca6b1..5d28216756ae 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -75,6 +75,7 @@ import android.view.Display; import android.view.DisplayAdjustments; import android.view.View; import android.view.ViewDebug; +import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.view.autofill.AutofillManager.AutofillClient; @@ -6110,18 +6111,19 @@ public abstract class Context { * * // WindowManager.LayoutParams initialization * ... + * // The types used in addView and createWindowContext must match. * mParams.type = TYPE_APPLICATION_OVERLAY; * ... * - * mWindowContext.getSystemService(WindowManager.class).addView(overlayView, mParams); + * windowContext.getSystemService(WindowManager.class).addView(overlayView, mParams); * </pre> * * <p> - * This context's configuration and resources are adjusted to a display area where the windows - * with provided type will be added. <b>Note that all windows associated with the same context - * will have an affinity and can only be moved together between different displays or areas on a - * display.</b> If there is a need to add different window types, or non-associated windows, - * separate Contexts should be used. + * This context's configuration and resources are adjusted to an area of the display where + * the windows with provided type will be added. <b>Note that all windows associated with the + * same context will have an affinity and can only be moved together between different displays + * or areas on a display.</b> If there is a need to add different window types, or + * non-associated windows, separate Contexts should be used. * </p> * <p> * Creating a window context is an expensive operation. Misuse of this API may lead to a huge @@ -6129,7 +6131,43 @@ public abstract class Context { * An approach is to create one window context with specific window type and display and * use it everywhere it's needed. * </p> + * <p> + * After {@link Build.VERSION_CODES#S}, window context provides the capability to receive + * configuration changes for existing token by overriding the + * {@link android.view.WindowManager.LayoutParams#token token} of the + * {@link android.view.WindowManager.LayoutParams} passed in + * {@link WindowManager#addView(View, LayoutParams)}. This is useful when an application needs + * to attach its window to an existing activity for window token sharing use-case. + * </p> + * <p> + * Note that the window context in {@link Build.VERSION_CODES#R} didn't have this + * capability. This is a no-op for the window context in {@link Build.VERSION_CODES#R}. + * </p> + * Below is sample code to <b>attach an existing token to a window context:</b> + * <pre class="prettyprint"> + * final DisplayManager dm = anyContext.getSystemService(DisplayManager.class); + * final Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY); + * final Context windowContext = anyContext.createWindowContext(primaryDisplay, + * TYPE_APPLICATION, null); + * + * // Get an existing token. + * final IBinder existingToken = activity.getWindow().getAttributes().token; + * + * // The types used in addView() and createWindowContext() must match. + * final WindowManager.LayoutParams params = new WindowManager.LayoutParams(TYPE_APPLICATION); + * params.token = existingToken; * + * // After WindowManager#addView(), the server side will extract the provided token from + * // LayoutParams#token (existingToken in the sample code), and switch to propagate + * // configuration changes from the node associated with the provided token. + * windowContext.getSystemService(WindowManager.class).addView(overlayView, mParams); + * </pre> + * <p> + * Note that using {@link android.app.Application} or {@link android.app.Service} context for + * UI-related queries may result in layout or continuity issues on devices with variable screen + * sizes (e.g. foldables) or in multi-window modes, since these non-UI contexts may not reflect + * the {@link Configuration} changes for the visual container. + * </p> * @param type Window type in {@link WindowManager.LayoutParams} * @param options A bundle used to pass window-related options * @return A {@link Context} that can be used to create @@ -6141,9 +6179,7 @@ public abstract class Context { * @see #LAYOUT_INFLATER_SERVICE * @see #WALLPAPER_SERVICE * @throws UnsupportedOperationException if this {@link Context} does not attach to a display, - * such as {@link android.app.Application Application} or {@link android.app.Service Service}, - * or the current number of window contexts without adding any view by - * {@link WindowManager#addView} <b>exceeds five</b>. + * such as {@link android.app.Application Application} or {@link android.app.Service Service}. */ @UiContext @NonNull diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 784341153d69..ae8afca9b5c5 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -117,7 +117,7 @@ interface IWindowManager // These can only be called when holding the MANAGE_APP_TOKENS permission. void setEventDispatching(boolean enabled); - /** @return {@code true} if this binder is a registered window token. */ + /** Returns {@code true} if this binder is a registered window token. */ boolean isWindowToken(in IBinder binder); /** * Adds window token for a given type. diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index bb826deb4eff..f31233b29cd0 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -147,6 +147,9 @@ <!-- WindowMetricsTest permissions --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <!-- WindowContextTest permissions --> + <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" /> + <!-- Allow use of PendingIntent.getIntent() --> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" /> diff --git a/core/tests/coretests/src/android/app/WindowContextTest.java b/core/tests/coretests/src/android/app/WindowContextTest.java index dcf5e025f82b..da7304efbd3d 100644 --- a/core/tests/coretests/src/android/app/WindowContextTest.java +++ b/core/tests/coretests/src/android/app/WindowContextTest.java @@ -18,29 +18,38 @@ package android.app; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.content.Context; +import android.content.Intent; import android.hardware.display.DisplayManager; +import android.os.Binder; import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.IWindowManager; import android.view.View; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams.WindowType; import android.view.WindowManagerGlobal; import android.view.WindowManagerImpl; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Tests for {@link WindowContext} * @@ -54,41 +63,156 @@ import org.junit.runner.RunWith; @SmallTest @Presubmit public class WindowContextTest { + @Rule + public ActivityTestRule<EmptyActivity> mActivityRule = + new ActivityTestRule<>(EmptyActivity.class, false /* initialTouchMode */, + false /* launchActivity */); + private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); private final WindowContext mWindowContext = createWindowContext(); + private final IWindowManager mWms = WindowManagerGlobal.getWindowManagerService(); @Test - public void testWindowContextRelease_doRemoveWindowToken() throws Throwable { + public void testCreateWindowContextWindowManagerAttachClientToken() { + final WindowManager windowContextWm = WindowManagerImpl + .createWindowContextWindowManager(mWindowContext); + final WindowManager.LayoutParams params = + new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + mInstrumentation.runOnMainSync(() -> { + final View view = new View(mWindowContext); + windowContextWm.addView(view, params); + }); + + assertEquals(mWindowContext.getWindowContextToken(), params.mWindowContextToken); + } + + /** + * Test the {@link WindowContext} life cycle behavior to add a new window token: + * <ul> + * <li>The window token is created before adding the first view.</li> + * <li>The window token is registered after adding the first view.</li> + * <li>The window token is removed after {@link WindowContext}'s release.</li> + * </ul> + */ + @Test + public void testCreateWindowContextNewTokenFromClient() throws Throwable { final IBinder token = mWindowContext.getWindowContextToken(); - final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); - assertTrue("Token must be registered to WMS", wms.isWindowToken(token)); + // Test that the window token is not created yet. + assertFalse("Token must not be registered until adding the first window", + mWms.isWindowToken(token)); + + final WindowManager.LayoutParams params = + new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + final View testView = new View(mWindowContext); + + final CountDownLatch latch = new CountDownLatch(1); + testView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + latch.countDown(); + } + + @Override + public void onViewDetachedFromWindow(View v) {} + }); + + mInstrumentation.runOnMainSync(() -> { + mWindowContext.getSystemService(WindowManager.class).addView(testView, params); + + assertEquals(token, params.mWindowContextToken); + }); + + + assertTrue(latch.await(4, TimeUnit.SECONDS)); + + + // Verify that the window token of the window context is created after first addView(). + assertTrue("Token must exist after adding the first view.", + mWms.isWindowToken(token)); mWindowContext.release(); - assertFalse("Token must be unregistered to WMS", wms.isWindowToken(token)); + // After the window context's release, the window token is also removed. + assertFalse("Token must be removed after release.", mWms.isWindowToken(token)); } + /** + * Verifies the behavior when window context attaches an {@link Activity} by override + * {@link WindowManager.LayoutParams#token}. + * + * The window context token should be overridden to + * {@link android.view.WindowManager.LayoutParams} and the {@link Activity}'s token must + * not be removed regardless of the release of window context. + */ @Test - public void testCreateWindowContextWindowManagerAttachClientToken() { - final WindowManager windowContextWm = WindowManagerImpl - .createWindowContextWindowManager(mWindowContext); + public void testCreateWindowContext_AttachActivity_TokenNotRemovedAfterRelease() + throws Throwable { + mActivityRule.launchActivity(new Intent()); + final Activity activity = mActivityRule.getActivity(); + final WindowManager.LayoutParams params = activity.getWindow().getAttributes(); + + final WindowContext windowContext = createWindowContext(params.type); + final IBinder token = windowContext.getWindowContextToken(); + + final View testView = new View(windowContext); + + mInstrumentation.runOnMainSync(() -> { + windowContext.getSystemService(WindowManager.class).addView(testView, params); + + assertEquals(token, params.mWindowContextToken); + }); + windowContext.release(); + + // Even if the window context is released, the activity should still exist. + assertTrue("Token must exist even if the window context is released.", + mWms.isWindowToken(activity.getActivityToken())); + } + + /** + * Verifies the behavior when window context attaches an existing token by override + * {@link WindowManager.LayoutParams#token}. + * + * The window context token should be overridden to + * {@link android.view.WindowManager.LayoutParams} and the {@link Activity}'s token must not be + * removed regardless of release of window context. + */ + @Test + public void testCreateWindowContext_AttachWindowToken_TokenNotRemovedAfterRelease() + throws Throwable { + final WindowContext windowContext = createWindowContext(TYPE_INPUT_METHOD); + final IBinder token = windowContext.getWindowContextToken(); + + final IBinder existingToken = new Binder(); + mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId()); + final WindowManager.LayoutParams params = - new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + new WindowManager.LayoutParams(TYPE_INPUT_METHOD); + params.token = existingToken; + final View testView = new View(windowContext); + mInstrumentation.runOnMainSync(() -> { - final View view = new View(mWindowContext); - windowContextWm.addView(view, params); + windowContext.getSystemService(WindowManager.class).addView(testView, params); + + assertEquals(token, params.mWindowContextToken); }); + windowContext.release(); - assertEquals(mWindowContext.getWindowContextToken(), params.mWindowContextToken); + // Even if the window context is released, the existing token should still exist. + assertTrue("Token must exist even if the window context is released.", + mWms.isWindowToken(existingToken)); + + mWms.removeWindowToken(existingToken, DEFAULT_DISPLAY); } private WindowContext createWindowContext() { + return createWindowContext(TYPE_APPLICATION_OVERLAY); + } + + private WindowContext createWindowContext(@WindowType int type) { final Context instContext = mInstrumentation.getTargetContext(); final Display display = instContext.getSystemService(DisplayManager.class) .getDisplay(DEFAULT_DISPLAY); - final Context context = instContext.createDisplayContext(display); - return new WindowContext(context, TYPE_APPLICATION_OVERLAY, - null /* options */); + return (WindowContext) instContext.createWindowContext(display, type, null /* options */); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java index 02a36dc74d68..f646d5d22263 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java @@ -220,7 +220,8 @@ public class InputMethodMenuController { */ @VisibleForTesting public Context getSettingsContext(int displayId) { - if (mSettingsContext == null) { + // TODO(b/178462039): Cover the case when IME is moved to another ImeContainer. + if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .createSystemUiContext(displayId); final Context windowContext = systemUiContext.createWindowContext( @@ -229,11 +230,6 @@ public class InputMethodMenuController { windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings); mSwitchingDialogToken = mSettingsContext.getWindowContextToken(); } - // TODO(b/159767464): register the listener to another display again if window token is not - // yet created. - if (mSettingsContext.getDisplayId() != displayId) { - mWindowManagerInternal.moveWindowTokenToDisplay(mSwitchingDialogToken, displayId); - } return mSettingsContext; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 673c6a5fb470..6319c80dc9bd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -770,7 +770,8 @@ public class WindowManagerService extends IWindowManager.Stub final AnrController mAnrController; private final ScreenshotHashController mScreenshotHashController; - private final WindowContextListenerController mWindowContextListenerController = + @VisibleForTesting + final WindowContextListenerController mWindowContextListenerController = new WindowContextListenerController(); @VisibleForTesting @@ -2794,6 +2795,17 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_OKAY; } + /** + * Registers a listener for a {@link android.app.WindowContext} to subscribe to configuration + * changes of a {@link DisplayArea}. + * + * @param clientToken the window context's token + * @param type Window type of the window context + * @param displayId The display associated with the window context + * @param options A bundle used to pass window-related options and choose the right DisplayArea + * + * @return {@code true} if the listener was registered successfully. + */ @Override public boolean registerWindowContextListener(IBinder clientToken, int type, int displayId, Bundle options) { @@ -2849,6 +2861,7 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** Returns {@code true} if this binder is a registered window token. */ @Override public boolean isWindowToken(IBinder binder) { synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 8a512bc8834b..cd18311d7d54 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static android.os.Process.INVALID_UID; -import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; @@ -26,7 +25,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; -import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -41,7 +39,6 @@ import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER; import android.annotation.CallSuper; import android.annotation.Nullable; -import android.app.IWindowToken; import android.app.servertransaction.FixedRotationAdjustmentsItem; import android.content.res.Configuration; import android.graphics.Rect; @@ -58,7 +55,6 @@ import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowManager; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; @@ -112,17 +108,10 @@ class WindowToken extends WindowContainer<WindowState> { private FixedRotationTransformState mFixedRotationTransformState; - private Configuration mLastReportedConfig; - private int mLastReportedDisplay = INVALID_DISPLAY; - /** * When set to {@code true}, this window token is created from {@link android.app.WindowContext} */ - @VisibleForTesting - final boolean mFromClientToken; - - private DeathRecipient mDeathRecipient; - private boolean mBinderDied = false; + private final boolean mFromClientToken; private final int mOwnerUid; @@ -188,30 +177,6 @@ class WindowToken extends WindowContainer<WindowState> { } } - private class DeathRecipient implements IBinder.DeathRecipient { - private boolean mHasUnlinkToDeath = false; - - @Override - public void binderDied() { - synchronized (mWmService.mGlobalLock) { - mBinderDied = true; - removeImmediately(); - } - } - - void linkToDeath() throws RemoteException { - token.linkToDeath(DeathRecipient.this, 0); - } - - void unlinkToDeath() { - if (mHasUnlinkToDeath) { - return; - } - token.unlinkToDeath(DeathRecipient.this, 0); - mHasUnlinkToDeath = true; - } - } - /** * Compares two child window of this token and returns -1 if the first is lesser than the * second in terms of z-order and 1 otherwise. @@ -266,17 +231,6 @@ class WindowToken extends WindowContainer<WindowState> { if (dc != null) { dc.addWindowToken(token, this); } - if (shouldReportToClient()) { - try { - mDeathRecipient = new DeathRecipient(); - mDeathRecipient.linkToDeath(); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to add window token with type " + windowType + " on " - + "display " + dc.getDisplayId(), e); - mDeathRecipient = null; - return; - } - } } void removeAllWindowsIfPossible() { @@ -414,22 +368,6 @@ class WindowToken extends WindowContainer<WindowState> { // Needs to occur after the token is removed from the display above to avoid attempt at // duplicate removal of this window container from it's parent. super.removeImmediately(); - - reportWindowTokenRemovedToClient(); - } - - // TODO(b/159767464): Remove after we migrate to listener approach. - private void reportWindowTokenRemovedToClient() { - if (!shouldReportToClient()) { - return; - } - mDeathRecipient.unlinkToDeath(); - IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(token); - try { - windowTokenClient.onWindowTokenRemoved(); - } catch (RemoteException e) { - ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client."); - } } @Override @@ -441,51 +379,11 @@ class WindowToken extends WindowContainer<WindowState> { // to another display before the window behind // it is ready. super.onDisplayChanged(dc); - reportConfigToWindowTokenClient(); } @Override public void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); - reportConfigToWindowTokenClient(); - } - - void reportConfigToWindowTokenClient() { - if (!shouldReportToClient()) { - return; - } - if (mLastReportedConfig == null) { - mLastReportedConfig = new Configuration(); - } - final Configuration config = getConfiguration(); - final int displayId = getDisplayContent().getDisplayId(); - if (config.diff(mLastReportedConfig) == 0 && displayId == mLastReportedDisplay) { - // No changes since last reported time. - return; - } - - mLastReportedConfig.setTo(config); - mLastReportedDisplay = displayId; - - IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(token); - try { - windowTokenClient.onConfigurationChanged(config, displayId); - } catch (RemoteException e) { - ProtoLog.w(WM_ERROR, - "Could not report config changes to the window token client."); - } - } - - /** - * @return {@code true} if this {@link WindowToken} is not an {@link ActivityRecord} and - * registered from client side. - */ - private boolean shouldReportToClient() { - // Only report to client for WindowToken because Activities are updated through ATM - // callbacks. - return asActivityRecord() == null - // Report to {@link android.view.WindowTokenClient} if this token was registered from it. - && mFromClientToken && !mBinderDied; } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java index f75c98f39323..78074d6e1492 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -26,7 +27,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -70,13 +70,15 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { spyOn(wms); doAnswer(invocation -> { Object[] args = invocation.getArguments(); - final IBinder token = (IBinder) args[0]; - final int windowType = (int) args[1]; - new WindowToken(mWm, token, windowType, true /* persistOnEmpty */, - mDefaultDisplay, true /* ownerCanManageAppTokens */, 1000 /* ownerUid */, - false /* roundedCornerOverlay */, true /* fromClientToken */); - return WindowManagerGlobal.ADD_OKAY; - }).when(wms).addWindowTokenWithOptions(any(), anyInt(), anyInt(), any(), anyString()); + IBinder clientToken = (IBinder) args[0]; + int displayId = (int) args[2]; + DisplayContent dc = mWm.mRoot.getDisplayContent(displayId); + mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken, + dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG, + null /* options */); + return true; + }).when(wms).registerWindowContextListener(any(), eq(TYPE_INPUT_METHOD_DIALOG), + anyInt(), any()); mSecondaryDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1000).build(); @@ -95,14 +97,12 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay); - // Obtain the context again and check they are the same instance and match the display - // metrics of the secondary display. + // Obtain the context again and check if the window metrics match the IME container bounds + // of the secondary display. final Context contextOnSecondaryDisplay = mController.getSettingsContext( mSecondaryDisplay.getDisplayId()); assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay); - assertThat(contextOnDefaultDisplay.getWindowContextToken()) - .isEqualTo(contextOnSecondaryDisplay.getWindowContextToken()); } private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) { |