Loading core/java/android/app/ActivityThread.java +20 −8 Original line number Diff line number Diff line Loading @@ -387,7 +387,7 @@ public final class ActivityThread extends ClientTransactionHandler @UnsupportedAppUsage private ContextImpl mSystemContext; @GuardedBy("this") private ArrayList<WeakReference<ContextImpl>> mDisplaySystemUiContexts; private ArrayList<WeakReference<Context>> mDisplaySystemUiContexts; @UnsupportedAppUsage static volatile IPackageManager sPackageManager; Loading Loading @@ -3204,7 +3204,7 @@ public final class ActivityThread extends ClientTransactionHandler } @NonNull public ContextImpl getSystemUiContext() { public Context getSystemUiContext() { return getSystemUiContext(DEFAULT_DISPLAY); } Loading @@ -3214,7 +3214,7 @@ public final class ActivityThread extends ClientTransactionHandler * @see ContextImpl#createSystemUiContext(ContextImpl, int) */ @NonNull public ContextImpl getSystemUiContext(int displayId) { public Context getSystemUiContext(int displayId) { synchronized (this) { if (mDisplaySystemUiContexts == null) { mDisplaySystemUiContexts = new ArrayList<>(); Loading @@ -3222,7 +3222,7 @@ public final class ActivityThread extends ClientTransactionHandler mDisplaySystemUiContexts.removeIf(contextRef -> contextRef.refersTo(null)); ContextImpl context = getSystemUiContextNoCreateLocked(displayId); Context context = getSystemUiContextNoCreateLocked(displayId); if (context != null) { return context; } Loading @@ -3233,9 +3233,20 @@ public final class ActivityThread extends ClientTransactionHandler } } /** * Creates a {@code SystemUiContext} for testing. * <p> * DO NOT use it in production code. */ @VisibleForTesting @NonNull public Context createSystemUiContextForTesting(int displayId) { return ContextImpl.createSystemUiContext(getSystemContext(), displayId); } @Nullable @Override public ContextImpl getSystemUiContextNoCreate() { public Context getSystemUiContextNoCreate() { synchronized (this) { if (mDisplaySystemUiContexts == null) { return null; Loading @@ -3246,9 +3257,9 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("this") @Nullable private ContextImpl getSystemUiContextNoCreateLocked(int displayId) { private Context getSystemUiContextNoCreateLocked(int displayId) { for (int i = 0; i < mDisplaySystemUiContexts.size(); i++) { ContextImpl context = mDisplaySystemUiContexts.get(i).get(); Context context = mDisplaySystemUiContexts.get(i).get(); if (context != null && context.getDisplayId() == displayId) { return context; } Loading @@ -3267,7 +3278,8 @@ public final class ActivityThread extends ClientTransactionHandler public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); getSystemUiContext().installSystemApplicationInfo(info, classLoader); final ContextImpl sysUiContextImpl = ContextImpl.getImpl(getSystemUiContext()); sysUiContextImpl.installSystemApplicationInfo(info, classLoader); // give ourselves a default profiler mProfiler = new Profiler(); Loading core/java/android/app/ActivityThreadInternal.java +2 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import android.content.ComponentCallbacks2; import android.content.Context; import java.util.ArrayList; Loading @@ -28,7 +29,7 @@ import java.util.ArrayList; interface ActivityThreadInternal { ContextImpl getSystemContext(); ContextImpl getSystemUiContextNoCreate(); Context getSystemUiContextNoCreate(); boolean isInDensityCompatMode(); Loading core/java/android/app/ConfigurationController.java +1 −1 Original line number Diff line number Diff line Loading @@ -169,7 +169,7 @@ class ConfigurationController { // Get theme outside of synchronization to avoid nested lock. final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate(); final Context systemUiContext = mActivityThread.getSystemUiContextNoCreate(); final Resources.Theme systemUiTheme = systemUiContext != null ? systemUiContext.getTheme() : null; synchronized (mResourcesManager) { Loading core/java/android/app/ContextImpl.java +17 −3 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; import android.view.autofill.AutofillManager.AutofillClient; import android.window.SystemUiContext; import android.window.WindowContext; import android.window.WindowTokenClient; import android.window.WindowTokenClientController; Loading Loading @@ -3477,15 +3478,28 @@ class ContextImpl extends Context { * {@link #createSystemContext(ActivityThread)}. * @param displayId The ID of the display where the UI is shown. */ static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { static Context createSystemUiContext(ContextImpl systemContext, int displayId) { // Step 1. Create a ContextImpl associated with its own resources. final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); token.attachContext(context); // Step 2. Create a SystemUiContext to wrap the ContextImpl, which enables to listen to // its config updates. final Context systemUiContext; if (com.android.window.flags.Flags.trackSystemUiContextBeforeWms()) { systemUiContext = new SystemUiContext(context); context.setOuterContext(systemUiContext); } else { systemUiContext = context; } token.attachContext(systemUiContext); // Step 3. Associate the SystemUiContext with the display specified with ID. WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; return context; return systemUiContext; } @UnsupportedAppUsage Loading core/java/android/window/SystemUiContext.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.content.ComponentCallbacks; import android.content.ComponentCallbacksController; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import com.android.window.flags.Flags; /** * System Context to be used for UI. This Context has resources that can be themed. * * @see android.app.ActivityThread#getSystemUiContext(int) * * @hide */ public class SystemUiContext extends ContextWrapper implements ConfigurationDispatcher { private final ComponentCallbacksController mCallbacksController = new ComponentCallbacksController(); public SystemUiContext(Context base) { super(base); if (!Flags.trackSystemUiContextBeforeWms()) { throw new UnsupportedOperationException("SystemUiContext can only be used after" + " flag is enabled."); } } @Override public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) { mCallbacksController.registerCallbacks(callback); } @Override public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) { mCallbacksController.unregisterCallbacks(callback); } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); } @Override public boolean shouldReportPrivateChanges() { // We should report all config changes to update fields obtained from resources. return true; } } Loading
core/java/android/app/ActivityThread.java +20 −8 Original line number Diff line number Diff line Loading @@ -387,7 +387,7 @@ public final class ActivityThread extends ClientTransactionHandler @UnsupportedAppUsage private ContextImpl mSystemContext; @GuardedBy("this") private ArrayList<WeakReference<ContextImpl>> mDisplaySystemUiContexts; private ArrayList<WeakReference<Context>> mDisplaySystemUiContexts; @UnsupportedAppUsage static volatile IPackageManager sPackageManager; Loading Loading @@ -3204,7 +3204,7 @@ public final class ActivityThread extends ClientTransactionHandler } @NonNull public ContextImpl getSystemUiContext() { public Context getSystemUiContext() { return getSystemUiContext(DEFAULT_DISPLAY); } Loading @@ -3214,7 +3214,7 @@ public final class ActivityThread extends ClientTransactionHandler * @see ContextImpl#createSystemUiContext(ContextImpl, int) */ @NonNull public ContextImpl getSystemUiContext(int displayId) { public Context getSystemUiContext(int displayId) { synchronized (this) { if (mDisplaySystemUiContexts == null) { mDisplaySystemUiContexts = new ArrayList<>(); Loading @@ -3222,7 +3222,7 @@ public final class ActivityThread extends ClientTransactionHandler mDisplaySystemUiContexts.removeIf(contextRef -> contextRef.refersTo(null)); ContextImpl context = getSystemUiContextNoCreateLocked(displayId); Context context = getSystemUiContextNoCreateLocked(displayId); if (context != null) { return context; } Loading @@ -3233,9 +3233,20 @@ public final class ActivityThread extends ClientTransactionHandler } } /** * Creates a {@code SystemUiContext} for testing. * <p> * DO NOT use it in production code. */ @VisibleForTesting @NonNull public Context createSystemUiContextForTesting(int displayId) { return ContextImpl.createSystemUiContext(getSystemContext(), displayId); } @Nullable @Override public ContextImpl getSystemUiContextNoCreate() { public Context getSystemUiContextNoCreate() { synchronized (this) { if (mDisplaySystemUiContexts == null) { return null; Loading @@ -3246,9 +3257,9 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("this") @Nullable private ContextImpl getSystemUiContextNoCreateLocked(int displayId) { private Context getSystemUiContextNoCreateLocked(int displayId) { for (int i = 0; i < mDisplaySystemUiContexts.size(); i++) { ContextImpl context = mDisplaySystemUiContexts.get(i).get(); Context context = mDisplaySystemUiContexts.get(i).get(); if (context != null && context.getDisplayId() == displayId) { return context; } Loading @@ -3267,7 +3278,8 @@ public final class ActivityThread extends ClientTransactionHandler public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); getSystemUiContext().installSystemApplicationInfo(info, classLoader); final ContextImpl sysUiContextImpl = ContextImpl.getImpl(getSystemUiContext()); sysUiContextImpl.installSystemApplicationInfo(info, classLoader); // give ourselves a default profiler mProfiler = new Profiler(); Loading
core/java/android/app/ActivityThreadInternal.java +2 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import android.content.ComponentCallbacks2; import android.content.Context; import java.util.ArrayList; Loading @@ -28,7 +29,7 @@ import java.util.ArrayList; interface ActivityThreadInternal { ContextImpl getSystemContext(); ContextImpl getSystemUiContextNoCreate(); Context getSystemUiContextNoCreate(); boolean isInDensityCompatMode(); Loading
core/java/android/app/ConfigurationController.java +1 −1 Original line number Diff line number Diff line Loading @@ -169,7 +169,7 @@ class ConfigurationController { // Get theme outside of synchronization to avoid nested lock. final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate(); final Context systemUiContext = mActivityThread.getSystemUiContextNoCreate(); final Resources.Theme systemUiTheme = systemUiContext != null ? systemUiContext.getTheme() : null; synchronized (mResourcesManager) { Loading
core/java/android/app/ContextImpl.java +17 −3 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; import android.view.autofill.AutofillManager.AutofillClient; import android.window.SystemUiContext; import android.window.WindowContext; import android.window.WindowTokenClient; import android.window.WindowTokenClientController; Loading Loading @@ -3477,15 +3478,28 @@ class ContextImpl extends Context { * {@link #createSystemContext(ActivityThread)}. * @param displayId The ID of the display where the UI is shown. */ static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { static Context createSystemUiContext(ContextImpl systemContext, int displayId) { // Step 1. Create a ContextImpl associated with its own resources. final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); token.attachContext(context); // Step 2. Create a SystemUiContext to wrap the ContextImpl, which enables to listen to // its config updates. final Context systemUiContext; if (com.android.window.flags.Flags.trackSystemUiContextBeforeWms()) { systemUiContext = new SystemUiContext(context); context.setOuterContext(systemUiContext); } else { systemUiContext = context; } token.attachContext(systemUiContext); // Step 3. Associate the SystemUiContext with the display specified with ID. WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; return context; return systemUiContext; } @UnsupportedAppUsage Loading
core/java/android/window/SystemUiContext.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.content.ComponentCallbacks; import android.content.ComponentCallbacksController; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import com.android.window.flags.Flags; /** * System Context to be used for UI. This Context has resources that can be themed. * * @see android.app.ActivityThread#getSystemUiContext(int) * * @hide */ public class SystemUiContext extends ContextWrapper implements ConfigurationDispatcher { private final ComponentCallbacksController mCallbacksController = new ComponentCallbacksController(); public SystemUiContext(Context base) { super(base); if (!Flags.trackSystemUiContextBeforeWms()) { throw new UnsupportedOperationException("SystemUiContext can only be used after" + " flag is enabled."); } } @Override public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) { mCallbacksController.registerCallbacks(callback); } @Override public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) { mCallbacksController.unregisterCallbacks(callback); } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); } @Override public boolean shouldReportPrivateChanges() { // We should report all config changes to update fields obtained from resources. return true; } }