diff options
5 files changed, 102 insertions, 184 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1f95497a7dba..59b0dacd7cd7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -27,7 +27,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UiContext; -import android.app.servertransaction.WindowTokenClientController; import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; @@ -3277,8 +3276,7 @@ class ContextImpl extends Context { // if this Context is not a WindowContext. WindowContext finalization is handled in // WindowContext class. if (mToken instanceof WindowTokenClient && mOwnsToken) { - WindowTokenClientController.getInstance().detachIfNeeded( - (WindowTokenClient) mToken); + ((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded(); } super.finalize(); } @@ -3306,7 +3304,7 @@ class ContextImpl extends Context { final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); token.attachContext(context); - WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); + token.attachToDisplayContent(displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; diff --git a/core/java/android/app/servertransaction/WindowTokenClientController.java b/core/java/android/app/servertransaction/WindowTokenClientController.java deleted file mode 100644 index 28e2040de9d5..000000000000 --- a/core/java/android/app/servertransaction/WindowTokenClientController.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2023 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.app.servertransaction; - -import static android.view.WindowManager.LayoutParams.WindowType; -import static android.view.WindowManagerGlobal.getWindowManagerService; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.ArrayMap; -import android.view.IWindowManager; -import android.window.WindowContext; -import android.window.WindowTokenClient; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; - -/** - * Singleton controller to manage the attached {@link WindowTokenClient}s, and to dispatch - * corresponding window configuration change from server side. - * @hide - */ -public class WindowTokenClientController { - - private static WindowTokenClientController sController; - - private final Object mLock = new Object(); - - /** Mapping from a client defined token to the {@link WindowTokenClient} it represents. */ - @GuardedBy("mLock") - private final ArrayMap<IBinder, WindowTokenClient> mWindowTokenClientMap = new ArrayMap<>(); - - /** Gets the singleton controller. */ - public static WindowTokenClientController getInstance() { - synchronized (WindowTokenClientController.class) { - if (sController == null) { - sController = new WindowTokenClientController(); - } - return sController; - } - } - - /** Overrides the {@link #getInstance()} for test only. */ - @VisibleForTesting - public static void overrideInstance(@NonNull WindowTokenClientController controller) { - synchronized (WindowTokenClientController.class) { - sController = controller; - } - } - - private WindowTokenClientController() {} - - /** - * Attaches a {@link WindowTokenClient} to a {@link com.android.server.wm.DisplayArea}. - * - * @param client The {@link WindowTokenClient} to attach. - * @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 - * @return {@code true} if attaching successfully. - */ - public boolean attachToDisplayArea(@NonNull WindowTokenClient client, - @WindowType int type, int displayId, @Nullable Bundle options) { - final Configuration configuration; - try { - configuration = getWindowManagerService() - .attachWindowContextToDisplayArea(client, type, displayId, options); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - if (configuration == null) { - return false; - } - onWindowContainerTokenAttached(client, displayId, configuration); - return true; - } - - /** - * Attaches a {@link WindowTokenClient} to a {@code DisplayContent}. - * - * @param client The {@link WindowTokenClient} to attach. - * @param displayId The {@link Context#getDisplayId() ID of display} to associate with - * @return {@code true} if attaching successfully. - */ - public boolean attachToDisplayContent(@NonNull WindowTokenClient client, int displayId) { - final IWindowManager wms = getWindowManagerService(); - // #createSystemUiContext may call this method before WindowManagerService is initialized. - if (wms == null) { - return false; - } - final Configuration configuration; - try { - configuration = wms.attachToDisplayContent(client, displayId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - if (configuration == null) { - return false; - } - onWindowContainerTokenAttached(client, displayId, configuration); - return true; - } - - /** - * Attaches this {@link WindowTokenClient} to a {@code windowToken}. - * - * @param client The {@link WindowTokenClient} to attach. - * @param windowToken the window token to associated with - */ - public void attachToWindowToken(@NonNull WindowTokenClient client, - @NonNull IBinder windowToken) { - try { - getWindowManagerService().attachWindowContextToWindowToken(client, windowToken); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - // We don't report configuration change for now. - synchronized (mLock) { - mWindowTokenClientMap.put(client.asBinder(), client); - } - } - - /** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */ - public void detachIfNeeded(@NonNull WindowTokenClient client) { - synchronized (mLock) { - if (mWindowTokenClientMap.remove(client.asBinder()) == null) { - return; - } - } - try { - getWindowManagerService().detachWindowContextFromWindowContainer(client); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private void onWindowContainerTokenAttached(@NonNull WindowTokenClient client, int displayId, - @NonNull Configuration configuration) { - synchronized (mLock) { - mWindowTokenClientMap.put(client.asBinder(), client); - } - client.onConfigurationChanged(configuration, displayId, - false /* shouldReportConfigChange */); - } -} diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index eb270e2fb2f0..4b9a957f541d 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -21,7 +21,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.servertransaction.WindowTokenClientController; import android.content.Context; import android.os.Bundle; import android.os.IBinder; @@ -105,8 +104,7 @@ public class WindowContextController { throw new IllegalStateException("A Window Context can be only attached to " + "a DisplayArea once."); } - mAttachedToDisplayArea = WindowTokenClientController.getInstance().attachToDisplayArea( - mToken, type, displayId, options) + mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options) ? AttachStatus.STATUS_ATTACHED : AttachStatus.STATUS_FAILED; if (mAttachedToDisplayArea == AttachStatus.STATUS_FAILED) { Log.w(TAG, "attachToDisplayArea fail, type:" + type + ", displayId:" @@ -142,13 +140,13 @@ public class WindowContextController { throw new IllegalStateException("The Window Context should have been attached" + " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea); } - WindowTokenClientController.getInstance().attachToWindowToken(mToken, windowToken); + mToken.attachToWindowToken(windowToken); } /** Detaches the window context from the node it's currently associated with. */ public void detachIfNeeded() { if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) { - WindowTokenClientController.getInstance().detachIfNeeded(mToken); + mToken.detachFromWindowContainerIfNeeded(); mAttachedToDisplayArea = AttachStatus.STATUS_DETACHED; if (DEBUG_ATTACH) { Log.d(TAG, "Detach Window Context."); diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 55b823be3cb8..a208634abe78 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -23,10 +23,10 @@ import android.annotation.AnyThread; import android.annotation.BinderThread; import android.annotation.MainThread; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityThread; import android.app.IWindowToken; import android.app.ResourcesManager; -import android.app.servertransaction.WindowTokenClientController; import android.content.Context; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -36,9 +36,14 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; +import android.os.RemoteException; import android.util.Log; +import android.view.IWindowManager; +import android.view.WindowManager.LayoutParams.WindowType; +import android.view.WindowManagerGlobal; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import java.lang.ref.WeakReference; @@ -65,11 +70,15 @@ public class WindowTokenClient extends IWindowToken.Stub { private final ResourcesManager mResourcesManager = ResourcesManager.getInstance(); + private IWindowManager mWms; + @GuardedBy("itself") private final Configuration mConfiguration = new Configuration(); private boolean mShouldDumpConfigForIme; + private boolean mAttachToWindowContainer; + private final Handler mHandler = ActivityThread.currentActivityThread().getHandler(); /** @@ -92,6 +101,88 @@ public class WindowTokenClient extends IWindowToken.Stub { } /** + * Attaches this {@link WindowTokenClient} to a {@link com.android.server.wm.DisplayArea}. + * + * @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 + * @return {@code true} if attaching successfully. + */ + public boolean attachToDisplayArea(@WindowType int type, int displayId, + @Nullable Bundle options) { + try { + final Configuration configuration = getWindowManagerService() + .attachWindowContextToDisplayArea(this, type, displayId, options); + if (configuration == null) { + return false; + } + onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */); + mAttachToWindowContainer = true; + return true; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Attaches this {@link WindowTokenClient} to a {@code DisplayContent}. + * + * @param displayId The {@link Context#getDisplayId() ID of display} to associate with + * @return {@code true} if attaching successfully. + */ + public boolean attachToDisplayContent(int displayId) { + final IWindowManager wms = getWindowManagerService(); + // #createSystemUiContext may call this method before WindowManagerService is initialized. + if (wms == null) { + return false; + } + try { + final Configuration configuration = wms.attachToDisplayContent(this, displayId); + if (configuration == null) { + return false; + } + onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */); + mAttachToWindowContainer = true; + return true; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Attaches this {@link WindowTokenClient} to a {@code windowToken}. + * + * @param windowToken the window token to associated with + */ + public void attachToWindowToken(IBinder windowToken) { + try { + getWindowManagerService().attachWindowContextToWindowToken(this, windowToken); + mAttachToWindowContainer = true; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** Detaches this {@link WindowTokenClient} from associated WindowContainer if there's one. */ + public void detachFromWindowContainerIfNeeded() { + if (!mAttachToWindowContainer) { + return; + } + try { + getWindowManagerService().detachWindowContextFromWindowContainer(this); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private IWindowManager getWindowManagerService() { + if (mWms == null) { + mWms = WindowManagerGlobal.getWindowManagerService(); + } + return mWms; + } + + /** * Called when {@link Configuration} updates from the server side receive. * * @param newConfig the updated {@link Configuration} @@ -116,14 +207,15 @@ public class WindowTokenClient extends IWindowToken.Stub { * {@code shouldReportConfigChange} is {@code true}, which is usually from * {@link IWindowToken#onConfigurationChanged(Configuration, int)} * directly, while this method could be run on any thread if it is used to initialize - * Context's {@code Configuration} via {@link WindowTokenClientController#attachToDisplayArea} - * or {@link WindowTokenClientController#attachToDisplayContent}. + * Context's {@code Configuration} via {@link #attachToDisplayArea(int, int, Bundle)} + * or {@link #attachToDisplayContent(int)}. * * @param shouldReportConfigChange {@code true} to indicate that the {@code Configuration} * should be dispatched to listeners. * */ @AnyThread + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void onConfigurationChanged(Configuration newConfig, int newDisplayId, boolean shouldReportConfigChange) { final Context context = mContextRef.get(); diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java index 467d555f161f..a52d2e88145f 100644 --- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java +++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java @@ -24,13 +24,11 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import android.app.servertransaction.WindowTokenClientController; import android.os.Binder; import android.platform.test.annotations.Presubmit; @@ -58,8 +56,6 @@ import org.mockito.MockitoAnnotations; public class WindowContextControllerTest { private WindowContextController mController; @Mock - private WindowTokenClientController mWindowTokenClientController; - @Mock private WindowTokenClient mMockToken; @Before @@ -67,9 +63,7 @@ public class WindowContextControllerTest { MockitoAnnotations.initMocks(this); mController = new WindowContextController(mMockToken); doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean()); - WindowTokenClientController.overrideInstance(mWindowTokenClientController); - doReturn(true).when(mWindowTokenClientController).attachToDisplayArea( - eq(mMockToken), anyInt(), anyInt(), any()); + doReturn(true).when(mMockToken).attachToDisplayArea(anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) @@ -84,7 +78,7 @@ public class WindowContextControllerTest { public void testDetachIfNeeded_NotAttachedYet_DoNothing() { mController.detachIfNeeded(); - verify(mWindowTokenClientController, never()).detachIfNeeded(any()); + verify(mMockToken, never()).detachFromWindowContainerIfNeeded(); } @Test |