Loading core/java/android/app/ContextImpl.java +19 −1 Original line number Diff line number Diff line Loading @@ -2409,17 +2409,35 @@ class ContextImpl extends Context { + "other visual contexts, such as Activity or one created with " + "Context#createDisplayContext(Display)"); } return new WindowContext(this, null /* token */, type, options); return new WindowContext(this, type, options); } ContextImpl createBaseWindowContext(IBinder token) { ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName, token, mUser, mFlags, mClassLoader, null); context.mIsUiContext = true; context.mIsAssociatedWithDisplay = true; return context; } Resources createWindowContextResources() { final String resDir = mPackageInfo.getResDir(); final String[] splitResDirs = mPackageInfo.getSplitResDirs(); final String[] overlayDirs = mPackageInfo.getOverlayDirs(); final String[] libDirs = mPackageInfo.getApplicationInfo().sharedLibraryFiles; final int displayId = getDisplayId(); final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY) ? mPackageInfo.getCompatibilityInfo() : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; final List<ResourcesLoader> loaders = mResources.getLoaders(); // TODO(b/128338354): Rename to createTokenResources return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs, overlayDirs, libDirs, displayId, null /* overrideConfig */, compatInfo, mClassLoader, loaders); } @Override public @NonNull Context createFeatureContext(@Nullable String featureId) { return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName, Loading core/java/android/app/IWindowToken.aidl 0 → 100644 +33 −0 Original line number Diff line number Diff line /* ** Copyright 2020, 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; import android.content.res.Configuration; import android.view.IWindow; /** * Callback to receive configuration changes from {@link com.android.server.WindowToken}. * WindowToken can be regarded to as a group of {@link android.view.IWindow} added from the same * visual context, such as {@link Activity} or one created with * {@link android.content.Context#createWindowContext(int)}. When WindowToken receives configuration * changes and/or when it is moved between displays, it will propagate the changes to client side * via this interface. * @see android.content.Context#createWindowContext(int) * {@hide} */ oneway interface IWindowToken { void onConfigurationChanged(in Configuration newConfig, int newDisplayId); } core/java/android/app/WindowContext.java +24 −33 Original line number Diff line number Diff line Loading @@ -15,10 +15,12 @@ */ package android.app; import static android.view.WindowManagerGlobal.ADD_OKAY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.ContextWrapper; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; Loading @@ -26,73 +28,62 @@ import android.view.IWindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerImpl; import java.lang.ref.Reference; /** * {@link WindowContext} is a context for non-activity windows such as * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system * windows. Its resources and configuration are adjusted to the area of the display that will be * used when a new window is added via {@link android.view.WindowManager.addView}. * used when a new window is added via {@link android.view.WindowManager#addView}. * * @see Context#createWindowContext(int, Bundle) * @hide */ // TODO(b/128338354): Handle config/display changes from server side. public class WindowContext extends ContextWrapper { private final WindowManagerImpl mWindowManager; private final IWindowManager mWms; private final IBinder mToken; private final int mDisplayId; private final WindowTokenClient mToken; private boolean mOwnsToken; /** * Default constructor. Can either accept an existing token or generate one and registers it * with the server if necessary. * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to * the token. * * @param base Base {@link Context} for this new instance. * @param token A valid {@link com.android.server.wm.WindowToken}. Pass {@code null} to generate * one. * @param type Window type to be used with this context. * @hide */ public WindowContext(Context base, IBinder token, int type, Bundle options) { public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { // Correct base context will be built once the token is resolved, so passing 'null' here. super(null /* base */); mWms = WindowManagerGlobal.getWindowManagerService(); if (token != null && !isWindowToken(token)) { throw new IllegalArgumentException("Token must be registered to server."); } mToken = token != null ? token : new Binder(); mToken = new WindowTokenClient(); final ContextImpl contextImpl = createBaseWindowContext(base, mToken); attachBaseContext(contextImpl); contextImpl.setOuterContext(this); mDisplayId = getDisplayId(); mToken.attachContext(this); mWindowManager = new WindowManagerImpl(this); mWindowManager.setDefaultToken(mToken); // TODO(b/128338354): Obtain the correct config from WM and adjust resources. if (token != null) { mOwnsToken = false; return; } int result; try { mWms.addWindowTokenWithOptions(mToken, type, mDisplayId, options, getPackageName()); // Register the token with WindowManager. This will also call back with the current // config back to the client. result = mWms.addWindowTokenWithOptions( mToken, type, getDisplayId(), options, getPackageName()); // TODO(window-context): remove token with a DeathObserver } catch (RemoteException e) { mOwnsToken = false; throw e.rethrowFromSystemServer(); } mOwnsToken = true; } /** Check if the passed window token is registered with the server. */ private boolean isWindowToken(@NonNull IBinder token) { try { return mWms.isWindowToken(token); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return false; mOwnsToken = result == ADD_OKAY; Reference.reachabilityFence(this); } private static ContextImpl createBaseWindowContext(Context outer, IBinder token) { Loading @@ -112,7 +103,7 @@ public class WindowContext extends ContextWrapper { protected void finalize() throws Throwable { if (mOwnsToken) { try { mWms.removeWindowToken(mToken, mDisplayId); mWms.removeWindowToken(mToken, getDisplayId()); mOwnsToken = false; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading core/java/android/app/WindowTokenClient.java 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import android.annotation.NonNull; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; /** * Client implementation of {@link IWindowToken}. It can receive configuration change callbacks from * server when window token config is updated or when it is moved between displays, and update the * resources associated with this token on the client side. This will make sure that * {@link WindowContext} instances will have updated resources and configuration. * @hide */ public class WindowTokenClient extends IWindowToken.Stub { /** * Attached {@link Context} for this window token to update configuration and resources. * Initialized by {@link #attachContext(Context)}. */ private Context mContext = null; private final ResourcesManager mResourcesManager = ResourcesManager.getInstance(); /** * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. * <p>This method must be called before invoking * {@link android.view.IWindowManager#addWindowTokenWithOptions(IBinder, int, int, Bundle, * String)}.<p/> * * @param context context to be attached * @throws IllegalStateException if attached context has already existed. */ void attachContext(@NonNull Context context) { if (mContext != null) { throw new IllegalStateException("Context is already attached."); } mContext = context; ContextImpl impl = ContextImpl.getImpl(mContext); impl.setResources(impl.createWindowContextResources()); } @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { final int currentDisplayId = mContext.getDisplayId(); final boolean displayChanged = newDisplayId != currentDisplayId; final Configuration config = new Configuration(mContext.getResources() .getConfiguration()); final boolean configChanged = config.isOtherSeqNewer(newConfig) && config.updateFrom(newConfig) != 0; if (displayChanged || configChanged) { // TODO(ag/9789103): update resource manager logic to track non-activity tokens mResourcesManager.updateResourcesForActivity(asBinder(), config, newDisplayId, displayChanged); } if (displayChanged) { mContext.updateDisplay(newDisplayId); } } } core/java/android/view/WindowManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -458,7 +458,7 @@ public interface WindowManager extends ViewManager { } /** * Returns the largets {@link WindowMetrics} an app may expect in the current system state. * Returns the largest {@link WindowMetrics} an app may expect in the current system state. * <p> * The metrics describe the size of the largest potential area the window might occupy with * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets} Loading Loading
core/java/android/app/ContextImpl.java +19 −1 Original line number Diff line number Diff line Loading @@ -2409,17 +2409,35 @@ class ContextImpl extends Context { + "other visual contexts, such as Activity or one created with " + "Context#createDisplayContext(Display)"); } return new WindowContext(this, null /* token */, type, options); return new WindowContext(this, type, options); } ContextImpl createBaseWindowContext(IBinder token) { ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName, token, mUser, mFlags, mClassLoader, null); context.mIsUiContext = true; context.mIsAssociatedWithDisplay = true; return context; } Resources createWindowContextResources() { final String resDir = mPackageInfo.getResDir(); final String[] splitResDirs = mPackageInfo.getSplitResDirs(); final String[] overlayDirs = mPackageInfo.getOverlayDirs(); final String[] libDirs = mPackageInfo.getApplicationInfo().sharedLibraryFiles; final int displayId = getDisplayId(); final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY) ? mPackageInfo.getCompatibilityInfo() : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; final List<ResourcesLoader> loaders = mResources.getLoaders(); // TODO(b/128338354): Rename to createTokenResources return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs, overlayDirs, libDirs, displayId, null /* overrideConfig */, compatInfo, mClassLoader, loaders); } @Override public @NonNull Context createFeatureContext(@Nullable String featureId) { return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName, Loading
core/java/android/app/IWindowToken.aidl 0 → 100644 +33 −0 Original line number Diff line number Diff line /* ** Copyright 2020, 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; import android.content.res.Configuration; import android.view.IWindow; /** * Callback to receive configuration changes from {@link com.android.server.WindowToken}. * WindowToken can be regarded to as a group of {@link android.view.IWindow} added from the same * visual context, such as {@link Activity} or one created with * {@link android.content.Context#createWindowContext(int)}. When WindowToken receives configuration * changes and/or when it is moved between displays, it will propagate the changes to client side * via this interface. * @see android.content.Context#createWindowContext(int) * {@hide} */ oneway interface IWindowToken { void onConfigurationChanged(in Configuration newConfig, int newDisplayId); }
core/java/android/app/WindowContext.java +24 −33 Original line number Diff line number Diff line Loading @@ -15,10 +15,12 @@ */ package android.app; import static android.view.WindowManagerGlobal.ADD_OKAY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.ContextWrapper; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; Loading @@ -26,73 +28,62 @@ import android.view.IWindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerImpl; import java.lang.ref.Reference; /** * {@link WindowContext} is a context for non-activity windows such as * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system * windows. Its resources and configuration are adjusted to the area of the display that will be * used when a new window is added via {@link android.view.WindowManager.addView}. * used when a new window is added via {@link android.view.WindowManager#addView}. * * @see Context#createWindowContext(int, Bundle) * @hide */ // TODO(b/128338354): Handle config/display changes from server side. public class WindowContext extends ContextWrapper { private final WindowManagerImpl mWindowManager; private final IWindowManager mWms; private final IBinder mToken; private final int mDisplayId; private final WindowTokenClient mToken; private boolean mOwnsToken; /** * Default constructor. Can either accept an existing token or generate one and registers it * with the server if necessary. * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to * the token. * * @param base Base {@link Context} for this new instance. * @param token A valid {@link com.android.server.wm.WindowToken}. Pass {@code null} to generate * one. * @param type Window type to be used with this context. * @hide */ public WindowContext(Context base, IBinder token, int type, Bundle options) { public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { // Correct base context will be built once the token is resolved, so passing 'null' here. super(null /* base */); mWms = WindowManagerGlobal.getWindowManagerService(); if (token != null && !isWindowToken(token)) { throw new IllegalArgumentException("Token must be registered to server."); } mToken = token != null ? token : new Binder(); mToken = new WindowTokenClient(); final ContextImpl contextImpl = createBaseWindowContext(base, mToken); attachBaseContext(contextImpl); contextImpl.setOuterContext(this); mDisplayId = getDisplayId(); mToken.attachContext(this); mWindowManager = new WindowManagerImpl(this); mWindowManager.setDefaultToken(mToken); // TODO(b/128338354): Obtain the correct config from WM and adjust resources. if (token != null) { mOwnsToken = false; return; } int result; try { mWms.addWindowTokenWithOptions(mToken, type, mDisplayId, options, getPackageName()); // Register the token with WindowManager. This will also call back with the current // config back to the client. result = mWms.addWindowTokenWithOptions( mToken, type, getDisplayId(), options, getPackageName()); // TODO(window-context): remove token with a DeathObserver } catch (RemoteException e) { mOwnsToken = false; throw e.rethrowFromSystemServer(); } mOwnsToken = true; } /** Check if the passed window token is registered with the server. */ private boolean isWindowToken(@NonNull IBinder token) { try { return mWms.isWindowToken(token); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return false; mOwnsToken = result == ADD_OKAY; Reference.reachabilityFence(this); } private static ContextImpl createBaseWindowContext(Context outer, IBinder token) { Loading @@ -112,7 +103,7 @@ public class WindowContext extends ContextWrapper { protected void finalize() throws Throwable { if (mOwnsToken) { try { mWms.removeWindowToken(mToken, mDisplayId); mWms.removeWindowToken(mToken, getDisplayId()); mOwnsToken = false; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading
core/java/android/app/WindowTokenClient.java 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import android.annotation.NonNull; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; /** * Client implementation of {@link IWindowToken}. It can receive configuration change callbacks from * server when window token config is updated or when it is moved between displays, and update the * resources associated with this token on the client side. This will make sure that * {@link WindowContext} instances will have updated resources and configuration. * @hide */ public class WindowTokenClient extends IWindowToken.Stub { /** * Attached {@link Context} for this window token to update configuration and resources. * Initialized by {@link #attachContext(Context)}. */ private Context mContext = null; private final ResourcesManager mResourcesManager = ResourcesManager.getInstance(); /** * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. * <p>This method must be called before invoking * {@link android.view.IWindowManager#addWindowTokenWithOptions(IBinder, int, int, Bundle, * String)}.<p/> * * @param context context to be attached * @throws IllegalStateException if attached context has already existed. */ void attachContext(@NonNull Context context) { if (mContext != null) { throw new IllegalStateException("Context is already attached."); } mContext = context; ContextImpl impl = ContextImpl.getImpl(mContext); impl.setResources(impl.createWindowContextResources()); } @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { final int currentDisplayId = mContext.getDisplayId(); final boolean displayChanged = newDisplayId != currentDisplayId; final Configuration config = new Configuration(mContext.getResources() .getConfiguration()); final boolean configChanged = config.isOtherSeqNewer(newConfig) && config.updateFrom(newConfig) != 0; if (displayChanged || configChanged) { // TODO(ag/9789103): update resource manager logic to track non-activity tokens mResourcesManager.updateResourcesForActivity(asBinder(), config, newDisplayId, displayChanged); } if (displayChanged) { mContext.updateDisplay(newDisplayId); } } }
core/java/android/view/WindowManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -458,7 +458,7 @@ public interface WindowManager extends ViewManager { } /** * Returns the largets {@link WindowMetrics} an app may expect in the current system state. * Returns the largest {@link WindowMetrics} an app may expect in the current system state. * <p> * The metrics describe the size of the largest potential area the window might occupy with * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets} Loading