summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt39
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/window/SplashScreenView.java94
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/themes.xml1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java217
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java1
9 files changed, 329 insertions, 67 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index a00eae9422d0..481850e5c138 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -330,7 +330,7 @@ package android {
field public static final int apiKey = 16843281; // 0x1010211
field public static final int appCategory = 16844101; // 0x1010545
field public static final int appComponentFactory = 16844154; // 0x101057a
- field public static final int attributionTags = 16844353; // 0x1010641
+ field public static final int attributionTags = 16844354; // 0x1010642
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -508,7 +508,7 @@ package android {
field public static final int dashGap = 16843175; // 0x10101a7
field public static final int dashWidth = 16843174; // 0x10101a6
field public static final int data = 16842798; // 0x101002e
- field public static final int dataExtractionRules = 16844349; // 0x101063d
+ field public static final int dataExtractionRules = 16844350; // 0x101063e
field public static final int datePickerDialogTheme = 16843948; // 0x10104ac
field public static final int datePickerMode = 16843955; // 0x10104b3
field public static final int datePickerStyle = 16843612; // 0x101035c
@@ -530,8 +530,8 @@ package android {
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
- field public static final int dialTint = 16844341; // 0x1010635
- field public static final int dialTintMode = 16844342; // 0x1010636
+ field public static final int dialTint = 16844342; // 0x1010636
+ field public static final int dialTintMode = 16844343; // 0x1010637
field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
@@ -729,14 +729,14 @@ package android {
field public static final int groupIndicator = 16843019; // 0x101010b
field public static final int gwpAsanMode = 16844310; // 0x1010616
field public static final int hand_hour = 16843011; // 0x1010103
- field public static final int hand_hourTint = 16844343; // 0x1010637
- field public static final int hand_hourTintMode = 16844344; // 0x1010638
+ field public static final int hand_hourTint = 16844344; // 0x1010638
+ field public static final int hand_hourTintMode = 16844345; // 0x1010639
field public static final int hand_minute = 16843012; // 0x1010104
- field public static final int hand_minuteTint = 16844345; // 0x1010639
- field public static final int hand_minuteTintMode = 16844346; // 0x101063a
+ field public static final int hand_minuteTint = 16844346; // 0x101063a
+ field public static final int hand_minuteTintMode = 16844347; // 0x101063b
field public static final int hand_second = 16844323; // 0x1010623
- field public static final int hand_secondTint = 16844347; // 0x101063b
- field public static final int hand_secondTintMode = 16844348; // 0x101063c
+ field public static final int hand_secondTint = 16844348; // 0x101063c
+ field public static final int hand_secondTintMode = 16844349; // 0x101063d
field public static final int handle = 16843354; // 0x101025a
field public static final int handleProfiling = 16842786; // 0x1010022
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
@@ -820,7 +820,7 @@ package android {
field public static final int installLocation = 16843447; // 0x10102b7
field public static final int interactiveUiTimeout = 16844181; // 0x1010595
field public static final int interpolator = 16843073; // 0x1010141
- field public static final int isAccessibilityTool = 16844352; // 0x1010640
+ field public static final int isAccessibilityTool = 16844353; // 0x1010641
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
field public static final int isAsciiCapable = 16843753; // 0x10103e9
field public static final int isAuxiliary = 16843647; // 0x101037f
@@ -972,8 +972,8 @@ package android {
field public static final int maxLines = 16843091; // 0x1010153
field public static final int maxLongVersionCode = 16844163; // 0x1010583
field public static final int maxRecents = 16843846; // 0x1010446
- field public static final int maxResizeHeight = 16844338; // 0x1010632
- field public static final int maxResizeWidth = 16844337; // 0x1010631
+ field public static final int maxResizeHeight = 16844339; // 0x1010633
+ field public static final int maxResizeWidth = 16844338; // 0x1010632
field public static final int maxRows = 16843059; // 0x1010133
field public static final int maxSdkVersion = 16843377; // 0x1010271
field public static final int maxWidth = 16843039; // 0x101011f
@@ -1076,7 +1076,7 @@ package android {
field public static final int panelTextAppearance = 16842850; // 0x1010062
field public static final int parentActivityName = 16843687; // 0x10103a7
field @Deprecated public static final int password = 16843100; // 0x101015c
- field public static final int passwordsActivity = 16844350; // 0x101063e
+ field public static final int passwordsActivity = 16844351; // 0x101063f
field public static final int path = 16842794; // 0x101002a
field public static final int pathAdvancedPattern = 16844320; // 0x1010620
field public static final int pathData = 16843781; // 0x1010405
@@ -1262,7 +1262,7 @@ package android {
field public static final int segmentedButtonStyle = 16843568; // 0x1010330
field public static final int selectAllOnFocus = 16843102; // 0x101015e
field public static final int selectable = 16843238; // 0x10101e6
- field public static final int selectableAsDefault = 16844351; // 0x101063f
+ field public static final int selectableAsDefault = 16844352; // 0x1010640
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347
@@ -1312,7 +1312,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 splashScreenTheme = 16844337; // 0x1010631
field public static final int splitMotionEvents = 16843503; // 0x10102ef
field public static final int splitName = 16844105; // 0x1010549
field public static final int splitTrack = 16843852; // 0x101044c
@@ -1395,7 +1395,7 @@ package android {
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
- field public static final int suppressesSpellChecker = 16844354; // 0x1010642
+ field public static final int suppressesSpellChecker = 16844355; // 0x1010643
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
field public static final int switchPreferenceStyle = 16843629; // 0x101036d
@@ -1410,8 +1410,8 @@ package android {
field public static final int tabWidgetStyle = 16842883; // 0x1010083
field public static final int tag = 16842961; // 0x10100d1
field public static final int targetActivity = 16843266; // 0x1010202
- field public static final int targetCellHeight = 16844340; // 0x1010634
- field public static final int targetCellWidth = 16844339; // 0x1010633
+ field public static final int targetCellHeight = 16844341; // 0x1010635
+ field public static final int targetCellWidth = 16844340; // 0x1010634
field public static final int targetClass = 16842799; // 0x101002f
field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0
field public static final int targetId = 16843740; // 0x10103dc
@@ -1680,6 +1680,7 @@ package android {
field public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
field public static final int windowSplashScreenBackground = 16844332; // 0x101062c
field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f
+ field public static final int windowSplashScreenIconBackgroundColor = 16844336; // 0x1010630
field @Deprecated public static final int windowSplashscreenContent = 16844132; // 0x1010564
field @Deprecated public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a97c3ae7b08e..92dada62b264 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2929,6 +2929,7 @@ package android.window {
public final class SplashScreenView extends android.widget.FrameLayout {
method @Nullable public android.view.View getBrandingView();
+ method @ColorInt public int getIconBackgroundColor();
}
public final class StartingWindowInfo implements android.os.Parcelable {
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index ddea64a77f4b..3709aa1583ba 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -17,8 +17,6 @@ package android.window;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import android.animation.Animator;
-import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,7 +27,6 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
-import android.graphics.drawable.Animatable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
@@ -47,6 +44,8 @@ import android.widget.FrameLayout;
import com.android.internal.R;
import com.android.internal.policy.DecorView;
+import java.util.function.Consumer;
+
/**
* <p>The view which allows an activity to customize its splash screen exit animation.</p>
*
@@ -69,6 +68,7 @@ public final class SplashScreenView extends FrameLayout {
private boolean mNotCopyable;
private int mInitBackgroundColor;
+ private int mInitIconBackgroundColor;
private View mIconView;
private Bitmap mParceledIconBitmap;
private View mBrandingImageView;
@@ -76,8 +76,6 @@ public final class SplashScreenView extends FrameLayout {
private long mIconAnimationDuration;
private long mIconAnimationStart;
- private Animatable mAnimatableIcon;
- private ValueAnimator mAnimator;
// The host activity when transfer view to it.
private Activity mHostActivity;
// cache original window and status
@@ -94,6 +92,7 @@ public final class SplashScreenView extends FrameLayout {
private final Context mContext;
private int mIconSize;
private @ColorInt int mBackgroundColor;
+ private @ColorInt int mIconBackground;
private Bitmap mParceledIconBitmap;
private Drawable mIconDrawable;
private int mBrandingImageWidth;
@@ -114,6 +113,7 @@ public final class SplashScreenView extends FrameLayout {
public Builder createFromParcel(SplashScreenViewParcelable parcelable) {
mIconSize = parcelable.getIconSize();
mBackgroundColor = parcelable.getBackgroundColor();
+ mIconBackground = parcelable.getIconBackground();
if (parcelable.mIconBitmap != null) {
mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
mParceledIconBitmap = parcelable.mIconBitmap;
@@ -154,6 +154,14 @@ public final class SplashScreenView extends FrameLayout {
}
/**
+ * Set the background color for the icon.
+ */
+ public Builder setIconBackground(int color) {
+ mIconBackground = color;
+ return this;
+ }
+
+ /**
* Set the animation duration if icon is animatable.
*/
public Builder setAnimationDuration(int duration) {
@@ -179,6 +187,7 @@ public final class SplashScreenView extends FrameLayout {
final SplashScreenView view = (SplashScreenView)
layoutInflater.inflate(R.layout.splash_screen_view, null, false);
view.mInitBackgroundColor = mBackgroundColor;
+ view.mInitIconBackgroundColor = mIconBackground;
view.setBackgroundColor(mBackgroundColor);
view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view);
@@ -266,43 +275,15 @@ public final class SplashScreenView extends FrameLayout {
}
void initIconAnimation(Drawable iconDrawable, long duration) {
- if (iconDrawable instanceof Animatable) {
- mAnimatableIcon = (Animatable) iconDrawable;
- mAnimator = ValueAnimator.ofInt(0, 1);
- mAnimator.setDuration(duration);
- mAnimator.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIconAnimationStart = SystemClock.uptimeMillis();
- mAnimatableIcon.start();
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimatableIcon.stop();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mAnimatableIcon.stop();
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- // do not repeat
- mAnimatableIcon.stop();
- }
- });
+ if (!(iconDrawable instanceof SplashscreenIconDrawable)) {
+ return;
}
+ SplashscreenIconDrawable aniDrawable = (SplashscreenIconDrawable) iconDrawable;
+ aniDrawable.prepareAnimate(duration, this::animationStartCallback);
}
- /**
- * @hide
- */
- public void startIntroAnimation() {
- if (mAnimatableIcon != null) {
- mAnimator.start();
- }
+ private void animationStartCallback(long startAt) {
+ mIconAnimationStart = startAt;
}
/**
@@ -401,6 +382,15 @@ public final class SplashScreenView extends FrameLayout {
}
/**
+ * Get the icon background color
+ * @hide
+ */
+ @TestApi
+ public @ColorInt int getIconBackgroundColor() {
+ return mInitIconBackgroundColor;
+ }
+
+ /**
* Get the initial background color of this view.
* @hide
*/
@@ -409,12 +399,30 @@ public final class SplashScreenView extends FrameLayout {
}
/**
+ * A lightweight Drawable object to make the view drawing faster and keep this
+ * drawable masked by config_icon_mask.
+ * @hide
+ */
+ public abstract static class SplashscreenIconDrawable extends Drawable {
+ /**
+ * Prepare the animation if this drawable also be animatable.
+ * @param duration The animation duration.
+ * @param startListener The callback listener used to receive the start of the animation.
+ * @return true if this drawable object can also be animated and it can be played now.
+ */
+ protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+ return false;
+ }
+ }
+
+ /**
* Use to create {@link SplashScreenView} object across process.
* @hide
*/
public static class SplashScreenViewParcelable implements Parcelable {
private int mIconSize;
private int mBackgroundColor;
+ private int mIconBackground;
private Bitmap mIconBitmap;
private int mBrandingWidth;
@@ -428,7 +436,7 @@ public final class SplashScreenView extends FrameLayout {
ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
mIconSize = params.height;
mBackgroundColor = view.getInitBackgroundColor();
-
+ mIconBackground = view.getIconBackgroundColor();
mIconBitmap = copyDrawable(view.getIconView().getBackground());
mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
params = view.getBrandingView().getLayoutParams();
@@ -469,6 +477,7 @@ public final class SplashScreenView extends FrameLayout {
mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
mIconAnimationStart = source.readLong();
mIconAnimationDuration = source.readLong();
+ mIconBackground = source.readInt();
}
@Override
@@ -486,6 +495,7 @@ public final class SplashScreenView extends FrameLayout {
dest.writeTypedObject(mBrandingBitmap, flags);
dest.writeLong(mIconAnimationStart);
dest.writeLong(mIconAnimationDuration);
+ dest.writeInt(mIconBackground);
}
public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
@@ -519,5 +529,9 @@ public final class SplashScreenView extends FrameLayout {
int getBackgroundColor() {
return mBackgroundColor;
}
+
+ int getIconBackground() {
+ return mIconBackground;
+ }
}
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9e1a08527330..5e95f941d14c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2280,6 +2280,10 @@
<!-- Place an drawable image in the bottom of the starting window, it can be used to
represent the branding of the application. -->
<attr name="windowSplashScreenBrandingImage" format="reference"/>
+ <!-- Set a background behind the splash screen icon. This is useful if there is not enough
+ contrast between the window background and the icon. Note the shape would also be
+ masking like an icon. -->
+ <attr name="windowSplashScreenIconBackgroundColor" format="color"/>
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ba21679df2fe..33cc89d2ab6e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3071,6 +3071,7 @@
<public name="windowSplashScreenAnimatedIcon"/>
<public name="windowSplashScreenAnimationDuration"/>
<public name="windowSplashScreenBrandingImage"/>
+ <public name="windowSplashScreenIconBackgroundColor"/>
<public name="splashScreenTheme" />
<public name="maxResizeWidth" />
<public name="maxResizeHeight" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 87ae1623ca92..bf42da080390 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -170,6 +170,7 @@ please see themes_device_defaults.xml.
<item name="windowSplashScreenBackground">@color/transparent</item>
<item name="windowSplashScreenAnimatedIcon">@null</item>
<item name="windowSplashScreenBrandingImage">@null</item>
+ <item name="windowSplashScreenIconBackgroundColor">@color/transparent</item>
<item name="windowClipToOutline">false</item>
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 3f9c2717731a..3f46fee26510 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.startingsurface;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.Context;
@@ -149,14 +150,16 @@ public class SplashscreenContentDrawer {
.setThemeDrawable(themeBGDrawable)
.setIconDrawable(iconDrawable)
.setIconAnimationDuration(animationDuration)
- .setBrandingDrawable(attrs.mBrandingImage).build();
+ .setBrandingDrawable(attrs.mBrandingImage)
+ .setIconBackground(attrs.mIconBgColor).build();
}
- private static class SplashScreenWindowAttrs {
+ static class SplashScreenWindowAttrs {
private int mWindowBgResId = 0;
private int mWindowBgColor = Color.TRANSPARENT;
private Drawable mReplaceIcon = null;
private Drawable mBrandingImage = null;
+ private int mIconBgColor = Color.TRANSPARENT;
private int mAnimationDuration = 0;
static SplashScreenWindowAttrs createWindowAttrs(Context context) {
@@ -172,6 +175,8 @@ public class SplashscreenContentDrawer {
R.styleable.Window_windowSplashScreenAnimationDuration, 0);
attrs.mBrandingImage = typedArray.getDrawable(
R.styleable.Window_windowSplashScreenBrandingImage);
+ attrs.mIconBgColor = typedArray.getColor(
+ R.styleable.Window_windowSplashScreenIconBackgroundColor, Color.TRANSPARENT);
typedArray.recycle();
if (DEBUG) {
Slog.d(TAG, "window attributes color: "
@@ -189,6 +194,7 @@ public class SplashscreenContentDrawer {
private int mIconAnimationDuration;
private Context mContext;
private Drawable mBrandingDrawable;
+ private @ColorInt int mIconBackground;
// result
private boolean mBuildComplete = false;
@@ -221,6 +227,12 @@ public class SplashscreenContentDrawer {
return this;
}
+ StartingWindowViewBuilder setIconBackground(int color) {
+ mIconBackground = color;
+ mBuildComplete = false;
+ return this;
+ }
+
StartingWindowViewBuilder setContext(Context context) {
mContext = context;
mBuildComplete = false;
@@ -244,7 +256,9 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
}
- mFinalIconDrawable = mIconDrawable;
+ mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
+ mIconBackground != Color.TRANSPARENT
+ ? mIconBackground : mThemeColor, mIconDrawable);
}
final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);
@@ -252,6 +266,12 @@ public class SplashscreenContentDrawer {
return mCachedResult;
}
+ private void createIconDrawable(Drawable iconDrawable) {
+ mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
+ mIconBackground != Color.TRANSPARENT
+ ? mIconBackground : mThemeColor, iconDrawable);
+ }
+
private void processThemeColor() {
final DrawableColorTester themeBGTester =
new DrawableColorTester(mThemeBGDrawable, true /* filterTransparent */);
@@ -307,8 +327,7 @@ public class SplashscreenContentDrawer {
}
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
- mFinalIconDrawable = new AdaptiveIconDrawable(
- new ColorDrawable(mThemeColor), iconForeground);
+ createIconDrawable(iconForeground);
// Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
// should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) {
@@ -318,7 +337,11 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
}
- mFinalIconDrawable = adaptiveIconDrawable;
+ if (mIconBackground != Color.TRANSPARENT) {
+ createIconDrawable(adaptiveIconDrawable);
+ } else {
+ mFinalIconDrawable = adaptiveIconDrawable;
+ }
}
return true;
}
@@ -326,7 +349,8 @@ public class SplashscreenContentDrawer {
private SplashScreenView fillViewWithIcon(Context context,
int iconSize, Drawable iconDrawable) {
final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
- builder.setIconSize(iconSize).setBackgroundColor(mThemeColor);
+ builder.setIconSize(iconSize).setBackgroundColor(mThemeColor)
+ .setIconBackground(mIconBackground);
if (iconDrawable != null) {
builder.setCenterViewDrawable(iconDrawable);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
new file mode 100644
index 000000000000..8626dbc6d724
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.startingsurface;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
+import android.util.PathParser;
+import android.window.SplashScreenView;
+
+import com.android.internal.R;
+
+import java.util.function.Consumer;
+
+/**
+ * Creating a lightweight Drawable object used for splash screen.
+ * @hide
+ */
+public class SplashscreenIconDrawableFactory {
+
+ static Drawable makeIconDrawable(@ColorInt int backgroundColor,
+ @NonNull Drawable foregroundDrawable) {
+ if (foregroundDrawable instanceof Animatable) {
+ return new AnimatableIconDrawable(backgroundColor, foregroundDrawable);
+ } else {
+ // TODO make a light weight drawable instead of AdaptiveIconDrawable
+ return new AdaptiveIconDrawable(new ColorDrawable(backgroundColor), foregroundDrawable);
+ }
+ }
+
+ /**
+ * A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
+ * drawable masked by config_icon_mask.
+ * @hide
+ */
+ private static class AnimatableIconDrawable extends SplashScreenView.SplashscreenIconDrawable {
+ private static final float MASK_SIZE = AdaptiveIconDrawable.MASK_SIZE;
+ private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f;
+ private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
+ private final Rect mTmpOutRect = new Rect();
+ /**
+ * Clip path defined in R.string.config_icon_mask.
+ */
+ private static Path sMask;
+
+ /**
+ * Scaled mask based on the view bounds.
+ */
+ private final Path mMask;
+ private final Path mMaskScaleOnly;
+ private final Matrix mMaskMatrix;
+ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Drawable mForegroundDrawable;
+ private Animatable mAnimatableIcon;
+ private Animator mIconAnimator;
+ private boolean mAnimationTriggered;
+ private long mIconAnimationStart;
+
+ AnimatableIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
+ mForegroundDrawable = foregroundDrawable;
+ final Resources r = Resources.getSystem();
+ sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
+ mMask = new Path(sMask);
+ mMaskScaleOnly = new Path(mMask);
+ mMaskMatrix = new Matrix();
+ mPaint.setColor(backgroundColor);
+ mPaint.setStyle(Paint.Style.FILL);
+ if (mForegroundDrawable != null) {
+ mForegroundDrawable.setCallback(mCallback);
+ }
+ }
+
+ @Override
+ protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+ mAnimatableIcon = (Animatable) mForegroundDrawable;
+ mIconAnimator = ValueAnimator.ofInt(0, 1);
+ mIconAnimator.setDuration(duration);
+ mIconAnimator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIconAnimationStart = SystemClock.uptimeMillis();
+ if (startListener != null) {
+ startListener.accept(mIconAnimationStart);
+ }
+ mAnimatableIcon.start();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimatableIcon.stop();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mAnimatableIcon.stop();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ // do not repeat
+ mAnimatableIcon.stop();
+ }
+ });
+ return true;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ if (bounds.isEmpty()) {
+ return;
+ }
+ updateLayerBounds(bounds);
+ }
+
+ private final Callback mCallback = new Callback() {
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ invalidateSelf();
+ }
+
+ @Override
+ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+ unscheduleSelf(what);
+ }
+ };
+
+ private void updateLayerBounds(Rect bounds) {
+ int cX = bounds.width() / 2;
+ int cY = bounds.height() / 2;
+
+ int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ final Rect outRect = mTmpOutRect;
+ outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
+
+ if (mForegroundDrawable != null) {
+ mForegroundDrawable.setBounds(outRect);
+ }
+ // reset everything that depends on the view bounds
+ mMaskMatrix.setScale(bounds.width() / MASK_SIZE, bounds.height() / MASK_SIZE);
+ sMask.transform(mMaskMatrix, mMaskScaleOnly);
+ invalidateSelf();
+ }
+
+ private void ensureAnimationStarted() {
+ if (mAnimationTriggered) {
+ return;
+ }
+ if (mIconAnimator != null && !mIconAnimator.isRunning()) {
+ mIconAnimator.start();
+ }
+ mAnimationTriggered = true;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mMaskScaleOnly != null) {
+ canvas.drawPath(mMaskScaleOnly, mPaint);
+ }
+ if (mForegroundDrawable != null) {
+ ensureAnimationStarted();
+ mForegroundDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ if (mForegroundDrawable != null) {
+ mForegroundDrawable.setColorFilter(colorFilter);
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
+
+}
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 9212c4b86105..b592121e98c0 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
@@ -362,7 +362,6 @@ public class StartingSurfaceDrawer {
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
if (record != null) {
record.setSplashScreenView(splashScreenView);
- splashScreenView.startIntroAnimation();
}
}