From cf05d9265081e2dfaa45230eaa3beb381da8577e Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Fri, 25 Dec 2020 17:50:09 +0800 Subject: [PATCH] Allow ShortcutInfo to specify a theme for splash screen.(5/N) Provides new APIs so that shortcuts can preset the theme of the splash screen window. - Static way: android:splashScreenTheme Preset the splash screen theme from xml. - Dynamic way: ShortcutInfo.Builder#setStartingTheme Preset the splash screen theme when construct the ShortcutInfo programmatically. Bug: 73289295 Test: build/flash Test: atest AppWindowTokenTests ActivityRecordTests Change-Id: Ie5e73f9b22fea22659e496c12198c942f4bc93cd --- core/api/current.txt | 2 + core/java/android/app/ActivityOptions.java | 19 +++ .../content/pm/AppSearchShortcutInfo.java | 2 +- .../java/android/content/pm/ShortcutInfo.java | 37 ++++- .../content/pm/ShortcutServiceInternal.java | 7 + .../android/window/StartingWindowInfo.java | 11 +- core/res/res/values/attrs.xml | 1 + core/res/res/values/public.xml | 1 + data/etc/services.core.protolog.json | 12 +- .../StartingSurfaceDrawer.java | 17 ++- .../server/pm/LauncherAppsService.java | 12 ++ .../android/server/pm/ShortcutPackage.java | 8 +- .../com/android/server/pm/ShortcutParser.java | 10 +- .../android/server/pm/ShortcutService.java | 26 ++++ .../com/android/server/wm/ActivityRecord.java | 142 ++++++++++++------ .../android/server/wm/ActivityStarter.java | 3 +- .../server/wm/ActivityTaskManagerService.java | 3 +- .../server/wm/RootWindowContainer.java | 2 +- .../server/wm/StartingSurfaceController.java | 5 +- .../core/java/com/android/server/wm/Task.java | 13 +- .../server/wm/TaskOrganizerController.java | 13 +- .../NotificationListenerServiceTest.java | 2 +- 22 files changed, 262 insertions(+), 86 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 50d46be869d4f..902d9a772782f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1295,6 +1295,7 @@ package android { field public static final int spinnerMode = 16843505; // 0x10102f1 field public static final int spinnerStyle = 16842881; // 0x1010081 field public static final int spinnersShown = 16843595; // 0x101034b + field public static final int splashScreenTheme = 16844336; // 0x1010630 field public static final int splitMotionEvents = 16843503; // 0x10102ef field public static final int splitName = 16844105; // 0x1010549 field public static final int splitTrack = 16843852; // 0x101044c @@ -12783,6 +12784,7 @@ package android.content.pm { method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]); method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int); method @NonNull public android.content.pm.ShortcutInfo.Builder setShortLabel(@NonNull CharSequence); + method @NonNull public android.content.pm.ShortcutInfo.Builder setStartingTheme(int); } public class ShortcutManager { diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 28da1c3a3eb7e..73cc13c82bcb2 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -159,6 +159,12 @@ public class ActivityOptions { */ public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener"; + /** + * Specific a theme for a splash screen window. + * @hide + */ + public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme"; + /** * Callback for when the last frame of the animation is played. * @hide @@ -398,6 +404,7 @@ public class ActivityOptions { private IBinder mLaunchCookie; private IRemoteTransition mRemoteTransition; private boolean mOverrideTaskTransition; + private int mSplashScreenThemeResId; /** * Create an ActivityOptions specifying a custom animation to run when @@ -1147,6 +1154,7 @@ public class ActivityOptions { mRemoteTransition = IRemoteTransition.Stub.asInterface(opts.getBinder( KEY_REMOTE_TRANSITION)); mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION); + mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME); } /** @@ -1332,6 +1340,14 @@ public class ActivityOptions { return mLockTaskMode; } + /** + * Gets whether the activity want to be launched as other theme for the splash screen. + * @hide + */ + public int getSplashScreenThemeResId() { + return mSplashScreenThemeResId; + } + /** * Sets whether the activity is to be launched into LockTask mode. * @@ -1838,6 +1854,9 @@ public class ActivityOptions { if (mOverrideTaskTransition) { b.putBoolean(KEY_OVERRIDE_TASK_TRANSITION, mOverrideTaskTransition); } + if (mSplashScreenThemeResId != 0) { + b.putInt(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResId); + } return b; } diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java index 85549d854c6d6..ebe202b2a3fa6 100644 --- a/core/java/android/content/pm/AppSearchShortcutInfo.java +++ b/core/java/android/content/pm/AppSearchShortcutInfo.java @@ -273,7 +273,7 @@ public class AppSearchShortcutInfo extends GenericDocument { text, 0, null, disabledMessage, 0, null, categoriesSet, intents, rank, extras, getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri, - disabledReason, persons, locusId); + disabledReason, persons, locusId, 0); } /** @hide */ diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 522f4ca88519e..ce0547f5d0f42 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -434,6 +434,8 @@ public final class ShortcutInfo implements Parcelable { private int mDisabledReason; + private int mStartingThemeResId; + private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); @@ -462,6 +464,7 @@ public final class ShortcutInfo implements Parcelable { mLocusId = b.mLocusId; updateTimestamp(); + mStartingThemeResId = b.mStartingThemeResId; } /** @@ -608,6 +611,7 @@ public final class ShortcutInfo implements Parcelable { // Set this bit. mFlags |= FLAG_KEY_FIELDS_ONLY; } + mStartingThemeResId = source.mStartingThemeResId; } /** @@ -931,6 +935,9 @@ public final class ShortcutInfo implements Parcelable { if (source.mLocusId != null) { mLocusId = source.mLocusId; } + if (source.mStartingThemeResId != 0) { + mStartingThemeResId = source.mStartingThemeResId; + } } /** @@ -1000,6 +1007,8 @@ public final class ShortcutInfo implements Parcelable { private LocusId mLocusId; + private int mStartingThemeResId; + /** * Old style constructor. * @hide @@ -1101,6 +1110,15 @@ public final class ShortcutInfo implements Parcelable { return this; } + /** + * Sets a theme resource id for the splash screen. + */ + @NonNull + public Builder setStartingTheme(int themeResId) { + mStartingThemeResId = themeResId; + return this; + } + /** * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests * use it.) @@ -1420,6 +1438,14 @@ public final class ShortcutInfo implements Parcelable { return mIcon; } + /** + * Returns the theme resource id used for the splash screen. + * @hide + */ + public int getStartingThemeResId() { + return mStartingThemeResId; + } + /** @hide -- old signature, the internal code still uses it. */ @Nullable @Deprecated @@ -2138,6 +2164,7 @@ public final class ShortcutInfo implements Parcelable { mPersons = source.readParcelableArray(cl, Person.class); mLocusId = source.readParcelable(cl); mIconUri = source.readString8(); + mStartingThemeResId = source.readInt(); } @Override @@ -2189,6 +2216,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeParcelableArray(mPersons, flags); dest.writeParcelable(mLocusId, flags); dest.writeString8(mIconUri); + dest.writeInt(mStartingThemeResId); } public static final @NonNull Creator CREATOR = @@ -2345,6 +2373,12 @@ public final class ShortcutInfo implements Parcelable { sb.append("disabledReason="); sb.append(getDisabledReasonDebugString(mDisabledReason)); + if (mStartingThemeResId != 0) { + addIndentOrComma(sb, indent); + sb.append("SplashScreenThemeResId="); + sb.append(Integer.toHexString(mStartingThemeResId)); + } + addIndentOrComma(sb, indent); sb.append("categories="); @@ -2430,7 +2464,7 @@ public final class ShortcutInfo implements Parcelable { Set categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String iconResName, String bitmapPath, String iconUri, - int disabledReason, Person[] persons, LocusId locusId) { + int disabledReason, Person[] persons, LocusId locusId, int startingThemeResId) { mUserId = userId; mId = id; mPackageName = packageName; @@ -2459,5 +2493,6 @@ public final class ShortcutInfo implements Parcelable { mDisabledReason = disabledReason; mPersons = persons; mLocusId = locusId; + mStartingThemeResId = startingThemeResId; } } diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index c62767ee031b0..233abf36131bf 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -71,6 +71,13 @@ public abstract class ShortcutServiceInternal { public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); + /** + * Get the theme res ID of the starting window, it can be 0 if not specified. + */ + public abstract int getShortcutStartingThemeResId(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, + int userId); + public abstract ParcelFileDescriptor getShortcutIconFd(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 2282cc5679364..63b9e9befb777 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -95,6 +95,12 @@ public final class StartingWindowInfo implements Parcelable { */ public int startingWindowTypeParameter; + /** + * Specifies a theme for the splash screen. + * @hide + */ + public int splashScreenThemeResId; + public StartingWindowInfo() { } @@ -115,6 +121,7 @@ public final class StartingWindowInfo implements Parcelable { dest.writeTypedObject(topOpaqueWindowInsetsState, flags); dest.writeTypedObject(topOpaqueWindowLayoutParams, flags); dest.writeTypedObject(mainWindowLayoutParams, flags); + dest.writeInt(splashScreenThemeResId); } void readFromParcel(@NonNull Parcel source) { @@ -124,6 +131,7 @@ public final class StartingWindowInfo implements Parcelable { topOpaqueWindowLayoutParams = source.readTypedObject( WindowManager.LayoutParams.CREATOR); mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); + splashScreenThemeResId = source.readInt(); } @Override @@ -135,7 +143,8 @@ public final class StartingWindowInfo implements Parcelable { + Integer.toHexString(startingWindowTypeParameter) + " insetsState=" + topOpaqueWindowInsetsState + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams - + " mainWindowLayoutParams=" + mainWindowLayoutParams; + + " mainWindowLayoutParams=" + mainWindowLayoutParams + + " splashScreenThemeResId " + Integer.toHexString(splashScreenThemeResId); } public static final @android.annotation.NonNull Creator CREATOR = diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 14f118056ceb5..927a8b49c17e8 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -9277,6 +9277,7 @@ + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 45e6392beb244..278708a26d444 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3070,6 +3070,7 @@ + diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 69c30f3ca05c0..ded4a276880f3 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -889,12 +889,6 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, - "-1088782910": { - "message": "Translucent=%s Floating=%s ShowWallpaper=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-1076978367": { "message": "thawRotation: mRotation=%d", "level": "VERBOSE", @@ -1675,6 +1669,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/Task.java" }, + "-124316973": { + "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-118786523": { "message": "Resume failed; resetting state to %s: %s", "level": "VERBOSE", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index e4c3a0569c661..8fe1c6ebbd774 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -199,9 +199,8 @@ public class StartingSurfaceDrawer { public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { final PreferredStartingTypeHelper helper = new PreferredStartingTypeHelper(windowInfo); - final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) { - addSplashScreenStartingWindow(runningTaskInfo, appToken); + addSplashScreenStartingWindow(windowInfo, appToken); } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) { final TaskSnapshot snapshot = helper.mSnapshot; makeTaskSnapshotWindow(windowInfo, appToken, snapshot); @@ -209,11 +208,13 @@ public class StartingSurfaceDrawer { // If prefer don't show, then don't show! } - private void addSplashScreenStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) { + private void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { + final RunningTaskInfo taskInfo = windowInfo.taskInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; if (activityInfo == null) { return; } + final int displayId = taskInfo.displayId; if (activityInfo.packageName == null) { return; @@ -228,11 +229,11 @@ public class StartingSurfaceDrawer { } Context context = mContext; - int theme = activityInfo.getThemeResource(); - if (theme == 0) { - // replace with the default theme if the application didn't set - theme = com.android.internal.R.style.Theme_DeviceDefault_DayNight; - } + // replace with the default theme if the application didn't set + final int theme = windowInfo.splashScreenThemeResId != 0 + ? windowInfo.splashScreenThemeResId + : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource() + : com.android.internal.R.style.Theme_DeviceDefault_DayNight; if (DEBUG_SPLASH_SCREEN) { Slog.d(TAG, "addSplashScreen " + activityInfo.packageName + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme=" diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index e91bb46657e17..b06e84d9df4e5 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; @@ -935,6 +936,17 @@ public class LauncherAppsService extends SystemService { intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intents[0].setSourceBounds(sourceBounds); + // Replace theme for splash screen + final int splashScreenThemeResId = + mShortcutServiceInternal.getShortcutStartingThemeResId(getCallingUserId(), + callingPackage, packageName, shortcutId, targetUserId); + if (splashScreenThemeResId != 0) { + if (startActivityOptions == null) { + startActivityOptions = new Bundle(); + } + startActivityOptions.putInt(KEY_SPLASH_SCREEN_THEME, splashScreenThemeResId); + } + return startShortcutIntentsAsPublisher( intents, packageName, featureId, startActivityOptions, targetUserId); } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 9b092c000172c..bb4ec16be0a88 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -112,6 +112,7 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_BITMAP_PATH = "bitmap-path"; private static final String ATTR_ICON_URI = "icon-uri"; private static final String ATTR_LOCUS_ID = "locus-id"; + private static final String ATTR_SPLASH_SCREEN_THEME_ID = "splash-screen-theme-id"; private static final String ATTR_PERSON_NAME = "name"; private static final String ATTR_PERSON_URI = "uri"; @@ -1654,6 +1655,7 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle()); ShortcutService.writeAttr(out, ATTR_TITLE_RES_ID, si.getTitleResId()); ShortcutService.writeAttr(out, ATTR_TITLE_RES_NAME, si.getTitleResName()); + ShortcutService.writeAttr(out, ATTR_SPLASH_SCREEN_THEME_ID, si.getStartingThemeResId()); ShortcutService.writeAttr(out, ATTR_TEXT, si.getText()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_NAME, si.getTextResName()); @@ -1861,6 +1863,7 @@ class ShortcutPackage extends ShortcutPackageItem { String bitmapPath; String iconUri; final String locusIdString; + int splashScreenThemeResId; int backupVersionCode; ArraySet categories = null; ArrayList persons = new ArrayList<>(); @@ -1871,6 +1874,8 @@ class ShortcutPackage extends ShortcutPackageItem { title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE); titleResId = ShortcutService.parseIntAttribute(parser, ATTR_TITLE_RES_ID); titleResName = ShortcutService.parseStringAttribute(parser, ATTR_TITLE_RES_NAME); + splashScreenThemeResId = ShortcutService.parseIntAttribute(parser, + ATTR_SPLASH_SCREEN_THEME_ID); text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT); textResId = ShortcutService.parseIntAttribute(parser, ATTR_TEXT_RES_ID); textResName = ShortcutService.parseStringAttribute(parser, ATTR_TEXT_RES_NAME); @@ -1964,7 +1969,8 @@ class ShortcutPackage extends ShortcutPackageItem { intents.toArray(new Intent[intents.size()]), rank, extras, lastChangedTimestamp, flags, iconResId, iconResName, bitmapPath, iconUri, - disabledReason, persons.toArray(new Person[persons.size()]), locusId); + disabledReason, persons.toArray(new Person[persons.size()]), locusId, + splashScreenThemeResId); } private static Intent parseIntent(TypedXmlPullParser parser) diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java index d3aace19672a2..c06f01a463adc 100644 --- a/services/core/java/com/android/server/pm/ShortcutParser.java +++ b/services/core/java/com/android/server/pm/ShortcutParser.java @@ -383,6 +383,8 @@ public class ShortcutParser { final int textResId = sa.getResourceId(R.styleable.Shortcut_shortcutLongLabel, 0); final int disabledMessageResId = sa.getResourceId( R.styleable.Shortcut_shortcutDisabledMessage, 0); + final int splashScreenTheme = sa.getResourceId( + R.styleable.Shortcut_splashScreenTheme, 0); if (TextUtils.isEmpty(id)) { Log.w(TAG, "android:shortcutId must be provided. activity=" + activity); @@ -404,7 +406,8 @@ public class ShortcutParser { disabledMessageResId, rank, iconResId, - enabled); + enabled, + splashScreenTheme); } finally { sa.recycle(); } @@ -413,7 +416,7 @@ public class ShortcutParser { private static ShortcutInfo createShortcutFromManifest(ShortcutService service, @UserIdInt int userId, String id, String packageName, ComponentName activityComponent, int titleResId, int textResId, int disabledMessageResId, - int rank, int iconResId, boolean enabled) { + int rank, int iconResId, boolean enabled, int splashScreenTheme) { final int flags = (enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED) @@ -452,7 +455,8 @@ public class ShortcutParser { null, // icon Url disabledReason, null /* persons */, - null /* locusId */); + null /* locusId */, + splashScreenTheme); } private static String parseCategory(ShortcutService service, AttributeSet attrs) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 863e3fe5c6a3e..4d8abea8acd42 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -3213,6 +3213,32 @@ public class ShortcutService extends IShortcutService.Stub { } } + @Override + public int getShortcutStartingThemeResId(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull String shortcutId, int userId) { + Objects.requireNonNull(callingPackage, "callingPackage"); + Objects.requireNonNull(packageName, "packageName"); + Objects.requireNonNull(shortcutId, "shortcutId"); + + synchronized (mLock) { + throwIfUserLockedL(userId); + throwIfUserLockedL(launcherUserId); + + getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) + .attemptToRestoreIfNeededAndSave(); + + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return 0; + } + + final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); + return shortcutInfo != null ? shortcutInfo.getStartingThemeResId() : 0; + } + } + @Override public ParcelFileDescriptor getShortcutIconFd(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 3ca6039a0f733..90bf82f47ada7 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1835,7 +1835,85 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return hasProcess() && app.hasThread(); } - boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, + /** + * Evaluate the theme for a starting window. + * @param originalTheme The original theme which read from activity or application. + * @param replaceTheme The replace theme which requested from starter. + * @return Resolved theme. + */ + private int evaluateStartingWindowTheme(String pkg, int originalTheme, int replaceTheme) { + // Skip if the package doesn't want a starting window. + if (!validateStartingWindowTheme(pkg, originalTheme)) { + return 0; + } + int selectedTheme = originalTheme; + if (replaceTheme != 0 && validateStartingWindowTheme(pkg, replaceTheme)) { + // allow to replace theme + selectedTheme = replaceTheme; + } + return selectedTheme; + } + + private boolean validateStartingWindowTheme(String pkg, int theme) { + // If this is a translucent window, then don't show a starting window -- the current + // effect (a full-screen opaque starting window that fades away to the real contents + // when it is ready) does not work for this. + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme); + if (theme != 0) { + AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, + com.android.internal.R.styleable.Window, + mWmService.mCurrentUserId); + if (ent == 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); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", + windowIsTranslucent, windowIsFloating, windowShowWallpaper, + windowDisableStarting); + if (windowIsTranslucent || windowIsFloating || windowDisableStarting) { + return false; + } + if (windowShowWallpaper + && getDisplayContent().mWallpaperController.getWallpaperTarget() != null) { + return false; + } + } + return true; + } + + private void applyStartingWindowTheme(String pkg, int theme) { + if (theme != 0) { + AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, + com.android.internal.R.styleable.Window, + mWmService.mCurrentUserId); + if (ent == null) { + return; + } + final boolean windowShowWallpaper = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowShowWallpaper, false); + if (windowShowWallpaper && getDisplayContent().mWallpaperController + .getWallpaperTarget() == null) { + // If this theme is requesting a wallpaper, and the wallpaper + // is not currently visible, then this effectively serves as + // an opaque window and our starting window transition animation + // can still work. We just need to make sure the starting window + // is also showing the wallpaper. + windowFlags |= FLAG_SHOW_WALLPAPER; + } + } + } + + boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) { @@ -1878,49 +1956,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return createSnapshot(snapshot, typeParameter); } - // If this is a translucent window, then don't show a starting window -- the current - // effect (a full-screen opaque starting window that fades away to the real contents - // when it is ready) does not work for this. - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme); - if (theme != 0) { - AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, - com.android.internal.R.styleable.Window, - mWmService.mCurrentUserId); - if (ent == 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); - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s", - windowIsTranslucent, windowIsFloating, windowShowWallpaper); - if (windowIsTranslucent) { - return false; - } - if (windowIsFloating || windowDisableStarting) { - return false; - } - if (windowShowWallpaper) { - if (getDisplayContent().mWallpaperController - .getWallpaperTarget() == null) { - // If this theme is requesting a wallpaper, and the wallpaper - // is not currently visible, then this effectively serves as - // an opaque window and our starting window transition animation - // can still work. We just need to make sure the starting window - // is also showing the wallpaper. - windowFlags |= FLAG_SHOW_WALLPAPER; - } else { - return false; - } - } + // Original theme can be 0 if developer doesn't request any theme. So if resolved theme is 0 + // but original theme is not 0, means this package doesn't want a starting window. + if (resolvedTheme == 0 && theme != 0) { + return false; } + applyStartingWindowTheme(pkg, resolvedTheme); if (transferStartingWindow(transferFrom)) { return true; @@ -1934,7 +1975,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData"); mStartingData = new SplashScreenStartingData(mWmService, pkg, - theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, + resolvedTheme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, getMergedOverrideConfiguration(), typeParameter); scheduleAddStartingWindow(); return true; @@ -6080,7 +6121,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pendingVoiceInteractionStart = false; } - void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) { + void showStartingWindow(boolean taskSwitch) { + showStartingWindow(null /* prev */, false /* newTask */, taskSwitch, + 0 /* splashScreenTheme */); + } + + void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, + int splashScreenTheme) { if (mTaskOverlay) { // We don't show starting window for overlay activities. return; @@ -6093,7 +6140,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final CompatibilityInfo compatInfo = mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo); - final boolean shown = addStartingWindow(packageName, theme, + + final int resolvedTheme = evaluateStartingWindowTheme(packageName, theme, + splashScreenTheme); + final boolean shown = addStartingWindow(packageName, resolvedTheme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(), allowTaskSnapshot(), diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 79f8229c61623..37fda4ce217a9 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1997,8 +1997,7 @@ class ActivityStarter { if (mMovedToFront) { // We moved the task to front, use starting window to hide initial drawn delay. - targetTaskTop.showStartingWindow(null /* prev */, false /* newTask */, - true /* taskSwitch */); + targetTaskTop.showStartingWindow(true /* taskSwitch */); } else if (mDoResume) { // Make sure the root task and its belonging display are moved to topmost. mTargetRootTask.moveToFront("intentActivityFound"); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0e1941ace6249..ef3f1358b6d8a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2028,8 +2028,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // We are reshowing a task, use a starting window to hide the initial draw delay // so the transition can start earlier. - topActivity.showStartingWindow(null /* prev */, false /* newTask */, - true /* taskSwitch */); + topActivity.showStartingWindow(true /* taskSwitch */); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index ceebe9550846c..6fbeaa4e944e0 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2656,7 +2656,7 @@ class RootWindowContainer extends WindowContainer void addStartingWindowsForVisibleActivities() { forAllActivities((r) -> { if (r.mVisibleRequested) { - r.showStartingWindow(null /* prev */, false /* newTask */, true /*taskSwitch*/); + r.showStartingWindow(true /*taskSwitch*/); } }); } diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index 94e14dd0a6b89..ef4a40f4837cc 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -60,7 +60,7 @@ public class StartingSurfaceController { final Task task = activity.getTask(); if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, - activity.token)) { + activity.token, theme)) { return new ShellStartingSurface(task); } return null; @@ -125,7 +125,8 @@ public class StartingSurfaceController { return mService.mTaskSnapshotController .createStartingSurface(activity, taskSnapshot); } - mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token); + mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token, + 0 /* launchTheme */); return new ShellStartingSurface(task); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e39ae9ae0babd..54bb9da99b99d 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6566,10 +6566,9 @@ class Task extends WindowContainer { Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null + } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null && lastFocusedRootTask.isTopRootTaskInDisplayArea()) { - next.showStartingWindow(null /* prev */, false /* newTask */, - false /* taskSwitch */); + next.showStartingWindow(false /* taskSwitch */); } mTaskSupervisor.startSpecificActivity(next, true, false); return true; @@ -6592,8 +6591,7 @@ class Task extends WindowContainer { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { - next.showStartingWindow(null /* prev */, false /* newTask */, - false /* taskSwich */); + next.showStartingWindow(false /* taskSwich */); } if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } @@ -6754,7 +6752,10 @@ class Task extends WindowContainer { prev = null; } } - r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity)); + final int splashScreenThemeResId = options != null + ? options.getSplashScreenThemeResId() : 0; + r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity), + splashScreenThemeResId); } } else { // If this is the first activity, don't do any fancy animations, diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 96d7ae3c5a5df..286d31ed7d5f8 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -117,8 +117,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return mTaskOrganizer.asBinder(); } - void addStartingWindow(Task task, IBinder appToken) { + void addStartingWindow(Task task, IBinder appToken, int launchTheme) { final StartingWindowInfo info = task.getStartingWindowInfo(); + if (launchTheme != 0) { + info.splashScreenThemeResId = launchTheme; + } mDeferTaskOrgCallbacksConsumer.accept(() -> { try { mTaskOrganizer.addStartingWindow(info, appToken); @@ -242,8 +245,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mUid = uid; } - void addStartingWindow(Task t, IBinder appToken) { - mOrganizer.addStartingWindow(t, appToken); + void addStartingWindow(Task t, IBinder appToken, int launchTheme) { + mOrganizer.addStartingWindow(t, appToken, launchTheme); } void removeStartingWindow(Task t) { @@ -479,14 +482,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode); } - boolean addStartingWindow(Task task, IBinder appToken) { + boolean addStartingWindow(Task task, IBinder appToken, int launchTheme) { final Task rootTask = task.getRootTask(); if (rootTask == null || rootTask.mTaskOrganizer == null) { return false; } final TaskOrganizerState state = mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder()); - state.addStartingWindow(task, appToken); + state.addStartingWindow(task, appToken, launchTheme); return true; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index be489c3bcd12b..5614aa2a165d5 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -394,7 +394,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { "disabledMessage", 0, "disabledMessageResName", null, null, 0, null, 0, 0, 0, "iconResName", "bitmapPath", null, 0, - null, null); + null, null, 0); return si; }