Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9854a1e3 authored by Charles Chen's avatar Charles Chen
Browse files

Migrate WindowContext to WindowContextListener mechanism

1. Use registerWindowContextListener instead of
   addWindowTokenWithOptions
2. Clean up the logic of sending the config to the client in WindowToken
3. Add a mechanism in WMS#addWindow, when a WindowContext adds a view,
   the server side will switch to register the WindowToken for the
   WindowContext.

In this way, we won't add a WindowToken until adding the fist view.
Also, we could apply an existing window token by overriding
WindowManager.LayoutParams.token.

Bug: 159767464
Bug: 153369119
Test: atest WindowContextTests WindowContextPolicyTests
Test: atest WindowContextTest
Test: atest WindowContextListenerControllerTests

Change-Id: I2396187c445306d18101706c4521edd9cf92facf
parent c43b7aac
Loading
Loading
Loading
Loading
+10 −22
Original line number Original line Diff line number Diff line
@@ -15,8 +15,7 @@
 */
 */
package android.app;
package android.app;


import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerImpl.createWindowContextWindowManager;
import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -28,8 +27,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.view.Display;
import android.view.Display;
import android.view.IWindowManager;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;


@@ -46,10 +45,10 @@ import java.lang.ref.Reference;
 */
 */
@UiContext
@UiContext
public class WindowContext extends ContextWrapper {
public class WindowContext extends ContextWrapper {
    private final WindowManagerImpl mWindowManager;
    private final WindowManager mWindowManager;
    private final IWindowManager mWms;
    private final IWindowManager mWms;
    private final WindowTokenClient mToken;
    private final WindowTokenClient mToken;
    private boolean mOwnsToken;
    private boolean mListenerRegistered;


    /**
    /**
     * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
     * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
@@ -86,25 +85,14 @@ public class WindowContext extends ContextWrapper {


        mToken.attachContext(this);
        mToken.attachContext(this);


        mWindowManager = new WindowManagerImpl(this);
        mWindowManager = createWindowContextWindowManager(this);
        mWindowManager.setDefaultToken(mToken);


        int result;
        try {
        try {
            // Register the token with WindowManager. This will also call back with the current
            mListenerRegistered = mWms.registerWindowContextListener(mToken, type, getDisplayId(),
            // config back to the client.
                    options);
            result = mWms.addWindowTokenWithOptions(
                    mToken, type, getDisplayId(), options, getPackageName());
        }  catch (RemoteException e) {
        }  catch (RemoteException e) {
            mOwnsToken = false;
            throw e.rethrowFromSystemServer();
            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);
        Reference.reachabilityFence(this);
    }
    }


@@ -131,10 +119,10 @@ public class WindowContext extends ContextWrapper {
    /** Used for test to invoke because we can't invoke finalize directly. */
    /** Used for test to invoke because we can't invoke finalize directly. */
    @VisibleForTesting
    @VisibleForTesting
    public void release() {
    public void release() {
        if (mOwnsToken) {
        if (mListenerRegistered) {
            mListenerRegistered = false;
            try {
            try {
                mWms.removeWindowToken(mToken, getDisplayId());
                mWms.unregisterWindowContextListener(mToken);
                mOwnsToken = false;
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
                throw e.rethrowFromSystemServer();
            }
            }
+45 −9
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@ import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayAdjustments;
import android.view.View;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewDebug;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
import android.view.WindowManager.LayoutParams.WindowType;
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.autofill.AutofillManager.AutofillClient;
@@ -6101,18 +6102,19 @@ public abstract class Context {
     *
     *
     * // WindowManager.LayoutParams initialization
     * // WindowManager.LayoutParams initialization
     * ...
     * ...
     * // The types used in addView and createWindowContext must match.
     * mParams.type = TYPE_APPLICATION_OVERLAY;
     * mParams.type = TYPE_APPLICATION_OVERLAY;
     * ...
     * ...
     *
     *
     * mWindowContext.getSystemService(WindowManager.class).addView(overlayView, mParams);
     * windowContext.getSystemService(WindowManager.class).addView(overlayView, mParams);
     * </pre>
     * </pre>
     *
     *
     * <p>
     * <p>
     * This context's configuration and resources are adjusted to a display area where the windows
     * This context's configuration and resources are adjusted to an area of the display where
     * with provided type will be added. <b>Note that all windows associated with the same context
     * the windows with provided type will be added. <b>Note that all windows associated with the
     * will have an affinity and can only be moved together between different displays or areas on a
     * same context will have an affinity and can only be moved together between different displays
     * display.</b> If there is a need to add different window types, or non-associated windows,
     * or areas on a display.</b> If there is a need to add different window types, or
     * separate Contexts should be used.
     * non-associated windows, separate Contexts should be used.
     * </p>
     * </p>
     * <p>
     * <p>
     * Creating a window context is an expensive operation. Misuse of this API may lead to a huge
     * Creating a window context is an expensive operation. Misuse of this API may lead to a huge
@@ -6120,7 +6122,43 @@ public abstract class Context {
     * An approach is to create one window context with specific window type and display and
     * An approach is to create one window context with specific window type and display and
     * use it everywhere it's needed.
     * use it everywhere it's needed.
     * </p>
     * </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 type Window type in {@link WindowManager.LayoutParams}
     * @param options A bundle used to pass window-related options
     * @param options A bundle used to pass window-related options
     * @return A {@link Context} that can be used to create
     * @return A {@link Context} that can be used to create
@@ -6132,9 +6170,7 @@ public abstract class Context {
     * @see #LAYOUT_INFLATER_SERVICE
     * @see #LAYOUT_INFLATER_SERVICE
     * @see #WALLPAPER_SERVICE
     * @see #WALLPAPER_SERVICE
     * @throws UnsupportedOperationException if this {@link Context} does not attach to a display,
     * @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},
     * 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>.
     */
     */
    @UiContext
    @UiContext
    @NonNull
    @NonNull
+3 −0
Original line number Original line Diff line number Diff line
@@ -148,6 +148,9 @@
    <!-- WindowMetricsTest permissions -->
    <!-- WindowMetricsTest permissions -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <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() -->
    <!-- Allow use of PendingIntent.getIntent() -->
    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />


+138 −14
Original line number Original line Diff line number Diff line
@@ -18,29 +18,38 @@ package android.app;


import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
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.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;


import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.Display;
import android.view.IWindowManager;
import android.view.IWindowManager;
import android.view.View;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;
import android.view.WindowManagerImpl;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


import org.junit.Rule;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
/**
 * Tests for {@link WindowContext}
 * Tests for {@link WindowContext}
 *
 *
@@ -54,41 +63,156 @@ import org.junit.runner.RunWith;
@SmallTest
@SmallTest
@Presubmit
@Presubmit
public class WindowContextTest {
public class WindowContextTest {
    @Rule
    public ActivityTestRule<EmptyActivity> mActivityRule =
            new ActivityTestRule<>(EmptyActivity.class, false /* initialTouchMode */,
                    false /* launchActivity */);

    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
    private final WindowContext mWindowContext = createWindowContext();
    private final WindowContext mWindowContext = createWindowContext();
    private final IWindowManager mWms = WindowManagerGlobal.getWindowManagerService();

    @Test
    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
    @Test
    public void testWindowContextRelease_doRemoveWindowToken() throws Throwable {
    public void testCreateWindowContextNewTokenFromClient() throws Throwable {
        final IBinder token = mWindowContext.getWindowContextToken();
        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();
        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
    @Test
    public void testCreateWindowContextWindowManagerAttachClientToken() {
    public void testCreateWindowContext_AttachActivity_TokenNotRemovedAfterRelease()
        final WindowManager windowContextWm = WindowManagerImpl
            throws Throwable {
                .createWindowContextWindowManager(mWindowContext);
        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 =
        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(() -> {
        mInstrumentation.runOnMainSync(() -> {
            final View view = new View(mWindowContext);
            windowContext.getSystemService(WindowManager.class).addView(testView, params);
            windowContextWm.addView(view, 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() {
    private WindowContext createWindowContext() {
        return createWindowContext(TYPE_APPLICATION_OVERLAY);
    }

    private WindowContext createWindowContext(@WindowType int type) {
        final Context instContext = mInstrumentation.getTargetContext();
        final Context instContext = mInstrumentation.getTargetContext();
        final Display display = instContext.getSystemService(DisplayManager.class)
        final Display display = instContext.getSystemService(DisplayManager.class)
                .getDisplay(DEFAULT_DISPLAY);
                .getDisplay(DEFAULT_DISPLAY);
        final Context context = instContext.createDisplayContext(display);
        return (WindowContext) instContext.createWindowContext(display, type,  null /* options */);
        return new WindowContext(context, TYPE_APPLICATION_OVERLAY,
                null /* options */);
    }
    }
}
}
+1 −103
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.server.wm;
package com.android.server.wm;


import static android.os.Process.INVALID_UID;
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.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
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_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
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_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.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
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.CallSuper;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.IWindowToken;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Rect;
@@ -58,7 +55,6 @@ import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.policy.WindowManagerPolicy;


@@ -112,17 +108,10 @@ class WindowToken extends WindowContainer<WindowState> {


    private FixedRotationTransformState mFixedRotationTransformState;
    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}
     * When set to {@code true}, this window token is created from {@link android.app.WindowContext}
     */
     */
    @VisibleForTesting
    private final boolean mFromClientToken;
    final boolean mFromClientToken;

    private DeathRecipient mDeathRecipient;
    private boolean mBinderDied = false;


    private final int mOwnerUid;
    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
     * 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.
     * second in terms of z-order and 1 otherwise.
@@ -266,17 +231,6 @@ class WindowToken extends WindowContainer<WindowState> {
        if (dc != null) {
        if (dc != null) {
            dc.addWindowToken(token, this);
            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() {
    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
        // 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.
        // duplicate removal of this window container from it's parent.
        super.removeImmediately();
        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
    @Override
@@ -441,51 +379,11 @@ class WindowToken extends WindowContainer<WindowState> {
        // to another display before the window behind
        // to another display before the window behind
        // it is ready.
        // it is ready.
        super.onDisplayChanged(dc);
        super.onDisplayChanged(dc);
        reportConfigToWindowTokenClient();
    }
    }


    @Override
    @Override
    public void onConfigurationChanged(Configuration newParentConfig) {
    public void onConfigurationChanged(Configuration newParentConfig) {
        super.onConfigurationChanged(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
    @Override