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

Commit d5e2fc35 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Introduce WindowContextController" into sc-dev

parents 624a0f2d 9c614d10
Loading
Loading
Loading
Loading
+5 −22
Original line number Diff line number Diff line
@@ -27,10 +27,7 @@ import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import com.android.internal.annotations.VisibleForTesting;

@@ -48,13 +45,11 @@ import java.lang.ref.Reference;
@UiContext
public class WindowContext extends ContextWrapper {
    private final WindowManager mWindowManager;
    private final IWindowManager mWms;
    private final @NonNull IBinder mToken;
    private final @WindowManager.LayoutParams.WindowType int mType;
    private final @Nullable Bundle mOptions;
    private boolean mListenerRegistered;
    private final ComponentCallbacksController mCallbacksController =
            new ComponentCallbacksController();
    private final WindowContextController mController;

    /**
     * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
@@ -69,9 +64,9 @@ public class WindowContext extends ContextWrapper {

        mType = type;
        mOptions = options;
        mWms = WindowManagerGlobal.getWindowManagerService();
        mToken = getWindowContextToken();
        mWindowManager = createWindowContextWindowManager(this);
        IBinder token = getWindowContextToken();
        mController = new WindowContextController(token);

        Reference.reachabilityFence(this);
    }
@@ -81,12 +76,7 @@ public class WindowContext extends ContextWrapper {
     * to receive configuration changes of the associated {@link WindowManager} node.
     */
    public void registerWithServer() {
        try {
            mListenerRegistered = mWms.registerWindowContextListener(mToken, mType, getDisplayId(),
                    mOptions);
        }  catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mController.registerListener(mType, getDisplayId(), mOptions);
    }

    @Override
@@ -106,14 +96,7 @@ public class WindowContext extends ContextWrapper {
    /** Used for test to invoke because we can't invoke finalize directly. */
    @VisibleForTesting
    public void release() {
        if (mListenerRegistered) {
            mListenerRegistered = false;
            try {
                mWms.unregisterWindowContextListener(mToken);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        mController.unregisterListenerIfNeeded();
        destroy();
    }

+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IWindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
import android.view.WindowManagerGlobal;

import com.android.internal.annotations.VisibleForTesting;

/**
 * The controller to manage {@link WindowContext} listener, such as registering and unregistering
 * the listener.
 *
 * @hide
 */
public class WindowContextController {
    private final IWindowManager mWms;
    @VisibleForTesting
    public boolean mListenerRegistered;
    @NonNull
    private final IBinder mToken;

    /**
     * Window Context Controller constructor
     *
     * @param token The token to register to the window context listener. It is usually from
     *              {@link Context#getWindowContextToken()}.
     */
    public WindowContextController(@NonNull IBinder token) {
        mToken = token;
        mWms = WindowManagerGlobal.getWindowManagerService();
    }

    /** Used for test only. DO NOT USE it in production code. */
    @VisibleForTesting
    public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) {
        mToken = token;
        mWms = mockWms;
    }

    /**
     * Registers the {@code mToken} to the window context listener.
     *
     * @param type The window type of the {@link WindowContext}
     * @param displayId The {@link Context#getDisplayId() ID of display} to associate with
     * @param options The window context launched option
     */
    public void registerListener(@WindowType int type, int displayId,  @Nullable Bundle options) {
        if (mListenerRegistered) {
            throw new UnsupportedOperationException("A Window Context can only register a listener"
                    + " once.");
        }
        try {
            mListenerRegistered = mWms.registerWindowContextListener(mToken, type, displayId,
                    options);
        }  catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Unregisters the window context listener associated with the {@code mToken} if it has been
     * registered.
     */
    public void unregisterListenerIfNeeded() {
        if (mListenerRegistered) {
            try {
                mWms.unregisterWindowContextListener(mToken);
                mListenerRegistered = false;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
}
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.IWindowManager;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

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

/**
 * Tests for {@link WindowContextController}
 *
 * <p>Build/Install/Run:
 *  atest FrameworksCoreTests:WindowContextControllerTest
 *
 * <p>This test class is a part of Window Manager Service tests and specified in
 * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
 */
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class WindowContextControllerTest {
    private WindowContextController mController;
    private IWindowManager mMockWms;

    @Before
    public void setUp() throws Exception {
        mMockWms = mock(IWindowManager.class);
        mController = new WindowContextController(new Binder(), mMockWms);

        doReturn(true).when(mMockWms).registerWindowContextListener(
                any(), anyInt(), anyInt(), any());
    }

    @Test(expected = UnsupportedOperationException.class)
    public void testRegisterListenerTwiceThrowException() {
        mController.registerListener(TYPE_APPLICATION_OVERLAY, DEFAULT_DISPLAY,
                null /* options */);
        mController.registerListener(TYPE_APPLICATION_OVERLAY, DEFAULT_DISPLAY,
                null /* options */);
    }

    @Test
    public void testUnregisterListenerIfNeeded_NotRegisteredYet_DoNothing() throws Exception {
        mController.unregisterListenerIfNeeded();

        verify(mMockWms, never()).registerWindowContextListener(any(), anyInt(), anyInt(), any());
    }

    @Test
    public void testRegisterAndUnRegisterListener() {
        mController.registerListener(TYPE_APPLICATION_OVERLAY, DEFAULT_DISPLAY,
                null /* options */);

        assertThat(mController.mListenerRegistered).isTrue();

        mController.unregisterListenerIfNeeded();

        assertThat(mController.mListenerRegistered).isFalse();
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -61,7 +61,8 @@ public final class FrameworksTestsFilter extends SelectTest {
            "android.view.PendingInsetsControllerTest",
            "android.window.WindowContextTest",
            "android.window.WindowMetricsHelperTest",
            "android.app.activity.ActivityThreadTest"
            "android.app.activity.ActivityThreadTest",
            "android.window.WindowContextControllerTest"
    };

    public FrameworksTestsFilter(Bundle testArgs) {