Add API windowSplashScreenIconBackground(12/N)
Add new API for developer to customize starting window, set a background color behind the icon. Also masking the AVD and icon background like AdaptiveIconDrawable. Ref doc: go/improved_app_launch_animations Bug: 73289295 Test: atest SplashscreenTests Change-Id: Ibba49ecc3ca020022cf775fed302e383908be327
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -2920,6 +2920,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 {
|
||||
|
||||
@@ -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;
|
||||
@@ -153,6 +153,14 @@ public final class SplashScreenView extends FrameLayout {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the background color for the icon.
|
||||
*/
|
||||
public Builder setIconBackground(int color) {
|
||||
mIconBackground = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the animation duration if icon is animatable.
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,6 +381,15 @@ public final class SplashScreenView extends FrameLayout {
|
||||
return mBrandingImageView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the icon background color
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public @ColorInt int getIconBackgroundColor() {
|
||||
return mInitIconBackgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial background color of this view.
|
||||
* @hide
|
||||
@@ -408,6 +398,23 @@ public final class SplashScreenView extends FrameLayout {
|
||||
return mInitBackgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -415,6 +422,7 @@ public final class SplashScreenView extends FrameLayout {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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. -->
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -362,7 +362,6 @@ public class StartingSurfaceDrawer {
|
||||
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
|
||||
if (record != null) {
|
||||
record.setSplashScreenView(splashScreenView);
|
||||
splashScreenView.startIntroAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user