diff options
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(); } } |