Loading core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,17 @@ flag { } } flag { name: "cache_window_style" namespace: "windowing_frontend" description: "Cache common window styles" bug: "350394503" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" Loading core/java/com/android/internal/policy/PhoneWindow.java +15 −7 Original line number Diff line number Diff line Loading @@ -470,6 +470,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { : info.isChangeEnabled(ENFORCE_EDGE_TO_EDGE)))); } /** * This is similar to {@link #isOptingOutEdgeToEdgeEnforcement} but the caller needs to check * whether the app declares style to opt out. */ public static boolean isOptOutEdgeToEdgeEnabled(ApplicationInfo info, boolean local) { final boolean disabled = Flags.disableOptOutEdgeToEdge() && (local // Calling this doesn't require a permission. ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) // Calling this requires permissions. : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); return !disabled; } /** * Returns whether the given application is opting out edge-to-edge enforcement. * Loading @@ -480,13 +494,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public static boolean isOptingOutEdgeToEdgeEnforcement(ApplicationInfo info, boolean local, TypedArray windowStyle) { final boolean disabled = Flags.disableOptOutEdgeToEdge() && (local // Calling this doesn't require a permission. ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) // Calling this requires permissions. : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); return !disabled && windowStyle.getBoolean( return isOptOutEdgeToEdgeEnabled(info, local) && windowStyle.getBoolean( R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false /* default */); } Loading services/core/java/com/android/server/wm/ActivityRecord.java +84 −33 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; Loading Loading @@ -352,7 +353,6 @@ import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.TransferPipe; import com.android.internal.policy.AttributeCache; import com.android.internal.policy.PhoneWindow; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.XmlUtils; Loading Loading @@ -479,6 +479,8 @@ final class ActivityRecord extends WindowToken { final String processName; // process where this component wants to run final String taskAffinity; // as per ActivityInfo.taskAffinity final boolean stateNotNeeded; // As per ActivityInfo.flags @Nullable final WindowStyle mWindowStyle; @VisibleForTesting int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity. @VisibleForTesting Loading Loading @@ -1926,22 +1928,17 @@ final class ActivityRecord extends WindowToken { ? android.R.style.Theme : android.R.style.Theme_Holo; } final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, realTheme, com.android.internal.R.styleable.Window, mUserId); if (ent != null) { final boolean styleTranslucent = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsTranslucent, false); final boolean styleFloating = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsFloating, false); mOccludesParent = !(styleTranslucent || styleFloating) final WindowStyle style = mAtmService.getWindowStyle(packageName, realTheme, mUserId); mWindowStyle = style; if (style != null) { mOccludesParent = !(style.isTranslucent() || style.isFloating()) // This style is propagated to the main window attributes with // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout. || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); || style.showWallpaper(); mStyleFillsParent = mOccludesParent; mNoDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); mOptOutEdgeToEdge = PhoneWindow.isOptingOutEdgeToEdgeEnforcement( aInfo.applicationInfo, false /* local */, ent.array); mNoDisplay = style.noDisplay(); mOptOutEdgeToEdge = style.optOutEdgeToEdge() && PhoneWindow.isOptOutEdgeToEdgeEnabled( aInfo.applicationInfo, false /* local */); } else { mStyleFillsParent = mOccludesParent = true; mNoDisplay = false; Loading Loading @@ -2272,21 +2269,17 @@ final class ActivityRecord extends WindowToken { return false; } final AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, com.android.internal.R.styleable.Window, mWmService.mCurrentUserId); if (ent == null) { final WindowStyle style = theme == this.theme ? mWindowStyle : mAtmService.getWindowStyle(pkg, theme, mUserId); if (style == null) { // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't // see that. return false; } final boolean windowIsTranslucent = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsTranslucent, false); final boolean windowIsFloating = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsFloating, false); final boolean windowShowWallpaper = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowShowWallpaper, false); final boolean windowDisableStarting = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowDisablePreview, false); final boolean windowIsTranslucent = style.isTranslucent(); final boolean windowIsFloating = style.isFloating(); final boolean windowShowWallpaper = style.showWallpaper(); final boolean windowDisableStarting = style.disablePreview(); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", windowIsTranslucent, windowIsFloating, windowShowWallpaper, Loading Loading @@ -7135,14 +7128,10 @@ final class ActivityRecord extends WindowToken { if (theme == 0) { return false; } final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, R.styleable.Window, mWmService.mCurrentUserId); if (ent != null) { if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) { return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior, SPLASH_SCREEN_BEHAVIOR_DEFAULT) == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; } final WindowStyle style = theme == this.theme ? mWindowStyle : mAtmService.getWindowStyle(packageName, theme, mUserId); if (style != null) { return style.mSplashScreenBehavior == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; } return false; } Loading Loading @@ -9814,6 +9803,68 @@ final class ActivityRecord extends WindowToken { int mBackgroundColor; } static class WindowStyle { private static final int FLAG_IS_TRANSLUCENT = 1; private static final int FLAG_IS_FLOATING = 1 << 1; private static final int FLAG_SHOW_WALLPAPER = 1 << 2; private static final int FLAG_NO_DISPLAY = 1 << 3; private static final int FLAG_DISABLE_PREVIEW = 1 << 4; private static final int FLAG_OPT_OUT_EDGE_TO_EDGE = 1 << 5; final int mFlags; @SplashScreenBehavior final int mSplashScreenBehavior; WindowStyle(TypedArray array) { int flags = 0; if (array.getBoolean(R.styleable.Window_windowIsTranslucent, false)) { flags |= FLAG_IS_TRANSLUCENT; } if (array.getBoolean(R.styleable.Window_windowIsFloating, false)) { flags |= FLAG_IS_FLOATING; } if (array.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { flags |= FLAG_SHOW_WALLPAPER; } if (array.getBoolean(R.styleable.Window_windowNoDisplay, false)) { flags |= FLAG_NO_DISPLAY; } if (array.getBoolean(R.styleable.Window_windowDisablePreview, false)) { flags |= FLAG_DISABLE_PREVIEW; } if (array.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false)) { flags |= FLAG_OPT_OUT_EDGE_TO_EDGE; } mFlags = flags; mSplashScreenBehavior = array.getInt(R.styleable.Window_windowSplashScreenBehavior, 0); } boolean isTranslucent() { return (mFlags & FLAG_IS_TRANSLUCENT) != 0; } boolean isFloating() { return (mFlags & FLAG_IS_FLOATING) != 0; } boolean showWallpaper() { return (mFlags & FLAG_SHOW_WALLPAPER) != 0; } boolean noDisplay() { return (mFlags & FLAG_NO_DISPLAY) != 0; } boolean disablePreview() { return (mFlags & FLAG_DISABLE_PREVIEW) != 0; } boolean optOutEdgeToEdge() { return (mFlags & FLAG_OPT_OUT_EDGE_TO_EDGE) != 0; } } static class Builder { private final ActivityTaskManagerService mAtmService; private WindowProcessController mCallerApp; Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +15 −0 Original line number Diff line number Diff line Loading @@ -286,6 +286,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.utils.WindowStyleCache; import com.android.wm.shell.Flags; import java.io.BufferedReader; Loading Loading @@ -500,6 +501,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean mSuppressResizeConfigChanges; private final WindowStyleCache<ActivityRecord.WindowStyle> mWindowStyleCache = new WindowStyleCache<>(ActivityRecord.WindowStyle::new); final UpdateConfigurationResult mTmpUpdateConfigurationResult = new UpdateConfigurationResult(); Loading Loading @@ -5570,6 +5573,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mUserManagerInternal; } @Nullable ActivityRecord.WindowStyle getWindowStyle(String packageName, int theme, int userId) { if (!com.android.window.flags.Flags.cacheWindowStyle()) { final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, com.android.internal.R.styleable.Window, userId); return ent != null ? new ActivityRecord.WindowStyle(ent.array) : null; } return mWindowStyleCache.get(packageName, theme, userId); } AppWarnings getAppWarningsLocked() { return mAppWarnings; } Loading Loading @@ -6518,6 +6531,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mCompatModePackages.handlePackageUninstalledLocked(name); mPackageConfigPersister.onPackageUninstall(name, userId); } mWindowStyleCache.invalidatePackage(name); } @Override Loading @@ -6534,6 +6548,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (mRootWindowContainer == null) return; mRootWindowContainer.updateActivityApplicationInfo(aInfo); } mWindowStyleCache.invalidatePackage(aInfo.packageName); } @Override Loading services/core/java/com/android/server/wm/utils/WindowStyleCache.java 0 → 100644 +81 −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 com.android.server.wm.utils; import android.content.res.TypedArray; import android.util.ArrayMap; import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.policy.AttributeCache; import java.util.function.Function; /** * A wrapper of AttributeCache to preserve more dedicated style caches. * @param <T> The type of style cache. */ public class WindowStyleCache<T> { @GuardedBy("itself") private final ArrayMap<String, SparseArray<T>> mCache = new ArrayMap<>(); private final Function<TypedArray, T> mEntryFactory; public WindowStyleCache(Function<TypedArray, T> entryFactory) { mEntryFactory = entryFactory; } /** Returns the cached entry. */ public T get(String packageName, int theme, int userId) { SparseArray<T> themeMap; synchronized (mCache) { themeMap = mCache.get(packageName); if (themeMap != null) { T style = themeMap.get(theme); if (style != null) { return style; } } } final AttributeCache attributeCache = AttributeCache.instance(); if (attributeCache == null) { return null; } final AttributeCache.Entry ent = attributeCache.get(packageName, theme, R.styleable.Window, userId); if (ent == null) { return null; } final T style = mEntryFactory.apply(ent.array); synchronized (mCache) { if (themeMap == null) { mCache.put(packageName, themeMap = new SparseArray<>()); } themeMap.put(theme, style); } return style; } /** Called when the package is updated or removed. */ public void invalidatePackage(String packageName) { synchronized (mCache) { mCache.remove(packageName); } } } Loading
core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,17 @@ flag { } } flag { name: "cache_window_style" namespace: "windowing_frontend" description: "Cache common window styles" bug: "350394503" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" Loading
core/java/com/android/internal/policy/PhoneWindow.java +15 −7 Original line number Diff line number Diff line Loading @@ -470,6 +470,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { : info.isChangeEnabled(ENFORCE_EDGE_TO_EDGE)))); } /** * This is similar to {@link #isOptingOutEdgeToEdgeEnforcement} but the caller needs to check * whether the app declares style to opt out. */ public static boolean isOptOutEdgeToEdgeEnabled(ApplicationInfo info, boolean local) { final boolean disabled = Flags.disableOptOutEdgeToEdge() && (local // Calling this doesn't require a permission. ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) // Calling this requires permissions. : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); return !disabled; } /** * Returns whether the given application is opting out edge-to-edge enforcement. * Loading @@ -480,13 +494,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public static boolean isOptingOutEdgeToEdgeEnforcement(ApplicationInfo info, boolean local, TypedArray windowStyle) { final boolean disabled = Flags.disableOptOutEdgeToEdge() && (local // Calling this doesn't require a permission. ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) // Calling this requires permissions. : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); return !disabled && windowStyle.getBoolean( return isOptOutEdgeToEdgeEnabled(info, local) && windowStyle.getBoolean( R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false /* default */); } Loading
services/core/java/com/android/server/wm/ActivityRecord.java +84 −33 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; Loading Loading @@ -352,7 +353,6 @@ import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.TransferPipe; import com.android.internal.policy.AttributeCache; import com.android.internal.policy.PhoneWindow; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.XmlUtils; Loading Loading @@ -479,6 +479,8 @@ final class ActivityRecord extends WindowToken { final String processName; // process where this component wants to run final String taskAffinity; // as per ActivityInfo.taskAffinity final boolean stateNotNeeded; // As per ActivityInfo.flags @Nullable final WindowStyle mWindowStyle; @VisibleForTesting int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity. @VisibleForTesting Loading Loading @@ -1926,22 +1928,17 @@ final class ActivityRecord extends WindowToken { ? android.R.style.Theme : android.R.style.Theme_Holo; } final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, realTheme, com.android.internal.R.styleable.Window, mUserId); if (ent != null) { final boolean styleTranslucent = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsTranslucent, false); final boolean styleFloating = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsFloating, false); mOccludesParent = !(styleTranslucent || styleFloating) final WindowStyle style = mAtmService.getWindowStyle(packageName, realTheme, mUserId); mWindowStyle = style; if (style != null) { mOccludesParent = !(style.isTranslucent() || style.isFloating()) // This style is propagated to the main window attributes with // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout. || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); || style.showWallpaper(); mStyleFillsParent = mOccludesParent; mNoDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); mOptOutEdgeToEdge = PhoneWindow.isOptingOutEdgeToEdgeEnforcement( aInfo.applicationInfo, false /* local */, ent.array); mNoDisplay = style.noDisplay(); mOptOutEdgeToEdge = style.optOutEdgeToEdge() && PhoneWindow.isOptOutEdgeToEdgeEnabled( aInfo.applicationInfo, false /* local */); } else { mStyleFillsParent = mOccludesParent = true; mNoDisplay = false; Loading Loading @@ -2272,21 +2269,17 @@ final class ActivityRecord extends WindowToken { return false; } final AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, com.android.internal.R.styleable.Window, mWmService.mCurrentUserId); if (ent == null) { final WindowStyle style = theme == this.theme ? mWindowStyle : mAtmService.getWindowStyle(pkg, theme, mUserId); if (style == null) { // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't // see that. return false; } final boolean windowIsTranslucent = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsTranslucent, false); final boolean windowIsFloating = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowIsFloating, false); final boolean windowShowWallpaper = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowShowWallpaper, false); final boolean windowDisableStarting = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowDisablePreview, false); final boolean windowIsTranslucent = style.isTranslucent(); final boolean windowIsFloating = style.isFloating(); final boolean windowShowWallpaper = style.showWallpaper(); final boolean windowDisableStarting = style.disablePreview(); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", windowIsTranslucent, windowIsFloating, windowShowWallpaper, Loading Loading @@ -7135,14 +7128,10 @@ final class ActivityRecord extends WindowToken { if (theme == 0) { return false; } final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, R.styleable.Window, mWmService.mCurrentUserId); if (ent != null) { if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) { return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior, SPLASH_SCREEN_BEHAVIOR_DEFAULT) == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; } final WindowStyle style = theme == this.theme ? mWindowStyle : mAtmService.getWindowStyle(packageName, theme, mUserId); if (style != null) { return style.mSplashScreenBehavior == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; } return false; } Loading Loading @@ -9814,6 +9803,68 @@ final class ActivityRecord extends WindowToken { int mBackgroundColor; } static class WindowStyle { private static final int FLAG_IS_TRANSLUCENT = 1; private static final int FLAG_IS_FLOATING = 1 << 1; private static final int FLAG_SHOW_WALLPAPER = 1 << 2; private static final int FLAG_NO_DISPLAY = 1 << 3; private static final int FLAG_DISABLE_PREVIEW = 1 << 4; private static final int FLAG_OPT_OUT_EDGE_TO_EDGE = 1 << 5; final int mFlags; @SplashScreenBehavior final int mSplashScreenBehavior; WindowStyle(TypedArray array) { int flags = 0; if (array.getBoolean(R.styleable.Window_windowIsTranslucent, false)) { flags |= FLAG_IS_TRANSLUCENT; } if (array.getBoolean(R.styleable.Window_windowIsFloating, false)) { flags |= FLAG_IS_FLOATING; } if (array.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { flags |= FLAG_SHOW_WALLPAPER; } if (array.getBoolean(R.styleable.Window_windowNoDisplay, false)) { flags |= FLAG_NO_DISPLAY; } if (array.getBoolean(R.styleable.Window_windowDisablePreview, false)) { flags |= FLAG_DISABLE_PREVIEW; } if (array.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false)) { flags |= FLAG_OPT_OUT_EDGE_TO_EDGE; } mFlags = flags; mSplashScreenBehavior = array.getInt(R.styleable.Window_windowSplashScreenBehavior, 0); } boolean isTranslucent() { return (mFlags & FLAG_IS_TRANSLUCENT) != 0; } boolean isFloating() { return (mFlags & FLAG_IS_FLOATING) != 0; } boolean showWallpaper() { return (mFlags & FLAG_SHOW_WALLPAPER) != 0; } boolean noDisplay() { return (mFlags & FLAG_NO_DISPLAY) != 0; } boolean disablePreview() { return (mFlags & FLAG_DISABLE_PREVIEW) != 0; } boolean optOutEdgeToEdge() { return (mFlags & FLAG_OPT_OUT_EDGE_TO_EDGE) != 0; } } static class Builder { private final ActivityTaskManagerService mAtmService; private WindowProcessController mCallerApp; Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +15 −0 Original line number Diff line number Diff line Loading @@ -286,6 +286,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.utils.WindowStyleCache; import com.android.wm.shell.Flags; import java.io.BufferedReader; Loading Loading @@ -500,6 +501,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean mSuppressResizeConfigChanges; private final WindowStyleCache<ActivityRecord.WindowStyle> mWindowStyleCache = new WindowStyleCache<>(ActivityRecord.WindowStyle::new); final UpdateConfigurationResult mTmpUpdateConfigurationResult = new UpdateConfigurationResult(); Loading Loading @@ -5570,6 +5573,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mUserManagerInternal; } @Nullable ActivityRecord.WindowStyle getWindowStyle(String packageName, int theme, int userId) { if (!com.android.window.flags.Flags.cacheWindowStyle()) { final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, com.android.internal.R.styleable.Window, userId); return ent != null ? new ActivityRecord.WindowStyle(ent.array) : null; } return mWindowStyleCache.get(packageName, theme, userId); } AppWarnings getAppWarningsLocked() { return mAppWarnings; } Loading Loading @@ -6518,6 +6531,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mCompatModePackages.handlePackageUninstalledLocked(name); mPackageConfigPersister.onPackageUninstall(name, userId); } mWindowStyleCache.invalidatePackage(name); } @Override Loading @@ -6534,6 +6548,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (mRootWindowContainer == null) return; mRootWindowContainer.updateActivityApplicationInfo(aInfo); } mWindowStyleCache.invalidatePackage(aInfo.packageName); } @Override Loading
services/core/java/com/android/server/wm/utils/WindowStyleCache.java 0 → 100644 +81 −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 com.android.server.wm.utils; import android.content.res.TypedArray; import android.util.ArrayMap; import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.policy.AttributeCache; import java.util.function.Function; /** * A wrapper of AttributeCache to preserve more dedicated style caches. * @param <T> The type of style cache. */ public class WindowStyleCache<T> { @GuardedBy("itself") private final ArrayMap<String, SparseArray<T>> mCache = new ArrayMap<>(); private final Function<TypedArray, T> mEntryFactory; public WindowStyleCache(Function<TypedArray, T> entryFactory) { mEntryFactory = entryFactory; } /** Returns the cached entry. */ public T get(String packageName, int theme, int userId) { SparseArray<T> themeMap; synchronized (mCache) { themeMap = mCache.get(packageName); if (themeMap != null) { T style = themeMap.get(theme); if (style != null) { return style; } } } final AttributeCache attributeCache = AttributeCache.instance(); if (attributeCache == null) { return null; } final AttributeCache.Entry ent = attributeCache.get(packageName, theme, R.styleable.Window, userId); if (ent == null) { return null; } final T style = mEntryFactory.apply(ent.array); synchronized (mCache) { if (themeMap == null) { mCache.put(packageName, themeMap = new SparseArray<>()); } themeMap.put(theme, style); } return style; } /** Called when the package is updated or removed. */ public void invalidatePackage(String packageName) { synchronized (mCache) { mCache.remove(packageName); } } }