Merge "Introduce WindowContextController" into sc-dev
diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java
index bff2252..375f4cf 100644
--- a/core/java/android/window/WindowContext.java
+++ b/core/java/android/window/WindowContext.java
@@ -27,10 +27,7 @@
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 @@
@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 @@
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 @@
* 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 @@
/** 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();
}
diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
new file mode 100644
index 0000000..6143414
--- /dev/null
+++ b/core/java/android/window/WindowContextController.java
@@ -0,0 +1,96 @@
+/*
+ * 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();
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
new file mode 100644
index 0000000..e4fc19c
--- /dev/null
+++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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();
+ }
+}
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 7a0be97..bcd6ed7 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -61,7 +61,8 @@
"android.view.PendingInsetsControllerTest",
"android.window.WindowContextTest",
"android.window.WindowMetricsHelperTest",
- "android.app.activity.ActivityThreadTest"
+ "android.app.activity.ActivityThreadTest",
+ "android.window.WindowContextControllerTest"
};
public FrameworksTestsFilter(Bundle testArgs) {