Loading core/java/android/app/ContextImpl.java +4 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ 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; Loading Loading @@ -3276,7 +3277,8 @@ class ContextImpl extends Context { // if this Context is not a WindowContext. WindowContext finalization is handled in // WindowContext class. if (mToken instanceof WindowTokenClient && mOwnsToken) { ((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded(); WindowTokenClientController.getInstance().detachIfNeeded( (WindowTokenClient) mToken); } super.finalize(); } Loading Loading @@ -3304,7 +3306,7 @@ class ContextImpl extends Context { final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); token.attachContext(context); token.attachToDisplayContent(displayId); WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; Loading core/java/android/app/servertransaction/WindowTokenClientController.java 0 → 100644 +164 −0 Original line number Diff line number Diff line /* * 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 */); } } core/java/android/window/WindowContextController.java +5 −3 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ 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; Loading Loading @@ -104,7 +105,8 @@ public class WindowContextController { throw new IllegalStateException("A Window Context can be only attached to " + "a DisplayArea once."); } mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options) mAttachedToDisplayArea = WindowTokenClientController.getInstance().attachToDisplayArea( mToken, type, displayId, options) ? AttachStatus.STATUS_ATTACHED : AttachStatus.STATUS_FAILED; if (mAttachedToDisplayArea == AttachStatus.STATUS_FAILED) { Log.w(TAG, "attachToDisplayArea fail, type:" + type + ", displayId:" Loading Loading @@ -140,13 +142,13 @@ public class WindowContextController { throw new IllegalStateException("The Window Context should have been attached" + " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea); } mToken.attachToWindowToken(windowToken); WindowTokenClientController.getInstance().attachToWindowToken(mToken, windowToken); } /** Detaches the window context from the node it's currently associated with. */ public void detachIfNeeded() { if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) { mToken.detachFromWindowContainerIfNeeded(); WindowTokenClientController.getInstance().detachIfNeeded(mToken); mAttachedToDisplayArea = AttachStatus.STATUS_DETACHED; if (DEBUG_ATTACH) { Log.d(TAG, "Detach Window Context."); Loading core/java/android/window/WindowTokenClient.java +3 −95 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -36,14 +36,9 @@ 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; Loading @@ -70,15 +65,11 @@ 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(); /** Loading @@ -100,88 +91,6 @@ public class WindowTokenClient extends IWindowToken.Stub { && context instanceof AbstractInputMethodService; } /** * 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. * Loading @@ -207,15 +116,14 @@ 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 #attachToDisplayArea(int, int, Bundle)} * or {@link #attachToDisplayContent(int)}. * Context's {@code Configuration} via {@link WindowTokenClientController#attachToDisplayArea} * or {@link WindowTokenClientController#attachToDisplayContent}. * * @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(); Loading core/tests/coretests/src/android/window/WindowContextControllerTest.java +8 −2 Original line number Diff line number Diff line Loading @@ -24,11 +24,13 @@ 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; Loading Loading @@ -56,6 +58,8 @@ import org.mockito.MockitoAnnotations; public class WindowContextControllerTest { private WindowContextController mController; @Mock private WindowTokenClientController mWindowTokenClientController; @Mock private WindowTokenClient mMockToken; @Before Loading @@ -63,7 +67,9 @@ public class WindowContextControllerTest { MockitoAnnotations.initMocks(this); mController = new WindowContextController(mMockToken); doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean()); doReturn(true).when(mMockToken).attachToDisplayArea(anyInt(), anyInt(), any()); WindowTokenClientController.overrideInstance(mWindowTokenClientController); doReturn(true).when(mWindowTokenClientController).attachToDisplayArea( eq(mMockToken), anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) Loading @@ -78,7 +84,7 @@ public class WindowContextControllerTest { public void testDetachIfNeeded_NotAttachedYet_DoNothing() { mController.detachIfNeeded(); verify(mMockToken, never()).detachFromWindowContainerIfNeeded(); verify(mWindowTokenClientController, never()).detachIfNeeded(any()); } @Test Loading Loading
core/java/android/app/ContextImpl.java +4 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ 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; Loading Loading @@ -3276,7 +3277,8 @@ class ContextImpl extends Context { // if this Context is not a WindowContext. WindowContext finalization is handled in // WindowContext class. if (mToken instanceof WindowTokenClient && mOwnsToken) { ((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded(); WindowTokenClientController.getInstance().detachIfNeeded( (WindowTokenClient) mToken); } super.finalize(); } Loading Loading @@ -3304,7 +3306,7 @@ class ContextImpl extends Context { final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); token.attachContext(context); token.attachToDisplayContent(displayId); WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; Loading
core/java/android/app/servertransaction/WindowTokenClientController.java 0 → 100644 +164 −0 Original line number Diff line number Diff line /* * 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 */); } }
core/java/android/window/WindowContextController.java +5 −3 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ 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; Loading Loading @@ -104,7 +105,8 @@ public class WindowContextController { throw new IllegalStateException("A Window Context can be only attached to " + "a DisplayArea once."); } mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options) mAttachedToDisplayArea = WindowTokenClientController.getInstance().attachToDisplayArea( mToken, type, displayId, options) ? AttachStatus.STATUS_ATTACHED : AttachStatus.STATUS_FAILED; if (mAttachedToDisplayArea == AttachStatus.STATUS_FAILED) { Log.w(TAG, "attachToDisplayArea fail, type:" + type + ", displayId:" Loading Loading @@ -140,13 +142,13 @@ public class WindowContextController { throw new IllegalStateException("The Window Context should have been attached" + " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea); } mToken.attachToWindowToken(windowToken); WindowTokenClientController.getInstance().attachToWindowToken(mToken, windowToken); } /** Detaches the window context from the node it's currently associated with. */ public void detachIfNeeded() { if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) { mToken.detachFromWindowContainerIfNeeded(); WindowTokenClientController.getInstance().detachIfNeeded(mToken); mAttachedToDisplayArea = AttachStatus.STATUS_DETACHED; if (DEBUG_ATTACH) { Log.d(TAG, "Detach Window Context."); Loading
core/java/android/window/WindowTokenClient.java +3 −95 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -36,14 +36,9 @@ 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; Loading @@ -70,15 +65,11 @@ 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(); /** Loading @@ -100,88 +91,6 @@ public class WindowTokenClient extends IWindowToken.Stub { && context instanceof AbstractInputMethodService; } /** * 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. * Loading @@ -207,15 +116,14 @@ 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 #attachToDisplayArea(int, int, Bundle)} * or {@link #attachToDisplayContent(int)}. * Context's {@code Configuration} via {@link WindowTokenClientController#attachToDisplayArea} * or {@link WindowTokenClientController#attachToDisplayContent}. * * @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(); Loading
core/tests/coretests/src/android/window/WindowContextControllerTest.java +8 −2 Original line number Diff line number Diff line Loading @@ -24,11 +24,13 @@ 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; Loading Loading @@ -56,6 +58,8 @@ import org.mockito.MockitoAnnotations; public class WindowContextControllerTest { private WindowContextController mController; @Mock private WindowTokenClientController mWindowTokenClientController; @Mock private WindowTokenClient mMockToken; @Before Loading @@ -63,7 +67,9 @@ public class WindowContextControllerTest { MockitoAnnotations.initMocks(this); mController = new WindowContextController(mMockToken); doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean()); doReturn(true).when(mMockToken).attachToDisplayArea(anyInt(), anyInt(), any()); WindowTokenClientController.overrideInstance(mWindowTokenClientController); doReturn(true).when(mWindowTokenClientController).attachToDisplayArea( eq(mMockToken), anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) Loading @@ -78,7 +84,7 @@ public class WindowContextControllerTest { public void testDetachIfNeeded_NotAttachedYet_DoNothing() { mController.detachIfNeeded(); verify(mMockToken, never()).detachFromWindowContainerIfNeeded(); verify(mWindowTokenClientController, never()).detachIfNeeded(any()); } @Test Loading