Merge "Do not draw icon background if it shouldn't be seen" into sc-dev

This commit is contained in:
Vadim Caen
2021-07-27 10:05:17 +00:00
committed by Android (Google) Code Review
5 changed files with 173 additions and 115 deletions

View File

@@ -3176,7 +3176,6 @@ package android.window {
public final class SplashScreenView extends android.widget.FrameLayout { public final class SplashScreenView extends android.widget.FrameLayout {
method @Nullable public android.view.View getBrandingView(); method @Nullable public android.view.View getBrandingView();
method @ColorInt public int getIconBackgroundColor();
} }
public final class StartingWindowInfo implements android.os.Parcelable { public final class StartingWindowInfo implements android.os.Parcelable {

View File

@@ -89,11 +89,11 @@ public final class SplashScreenView extends FrameLayout {
private boolean mNotCopyable; private boolean mNotCopyable;
private boolean mIsCopied; private boolean mIsCopied;
private int mInitBackgroundColor; private int mInitBackgroundColor;
private int mInitIconBackgroundColor;
private View mIconView; private View mIconView;
private Bitmap mParceledIconBitmap; private Bitmap mParceledIconBitmap;
private View mBrandingImageView; private View mBrandingImageView;
private Bitmap mParceledBrandingBitmap; private Bitmap mParceledBrandingBitmap;
private Bitmap mParceledIconBackgroundBitmap;
private Duration mIconAnimationDuration; private Duration mIconAnimationDuration;
private Instant mIconAnimationStart; private Instant mIconAnimationStart;
@@ -130,11 +130,12 @@ public final class SplashScreenView extends FrameLayout {
private final Context mContext; private final Context mContext;
private int mIconSize; private int mIconSize;
private @ColorInt int mBackgroundColor; private @ColorInt int mBackgroundColor;
private @ColorInt int mIconBackground;
private Bitmap mParceledIconBitmap; private Bitmap mParceledIconBitmap;
private Bitmap mParceledIconBackgroundBitmap;
private Drawable mIconDrawable; private Drawable mIconDrawable;
// It is only set for legacy splash screen which won't be sent across processes. // It is only set for legacy splash screen which won't be sent across processes.
private Drawable mOverlayDrawable; private Drawable mOverlayDrawable;
private Drawable mIconBackground;
private SurfaceControlViewHost.SurfacePackage mSurfacePackage; private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
private RemoteCallback mClientCallback; private RemoteCallback mClientCallback;
private int mBrandingImageWidth; private int mBrandingImageWidth;
@@ -155,7 +156,6 @@ public final class SplashScreenView extends FrameLayout {
public Builder createFromParcel(SplashScreenViewParcelable parcelable) { public Builder createFromParcel(SplashScreenViewParcelable parcelable) {
mIconSize = parcelable.getIconSize(); mIconSize = parcelable.getIconSize();
mBackgroundColor = parcelable.getBackgroundColor(); mBackgroundColor = parcelable.getBackgroundColor();
mIconBackground = parcelable.getIconBackground();
mSurfacePackage = parcelable.mSurfacePackage; mSurfacePackage = parcelable.mSurfacePackage;
if (mSurfacePackage == null && parcelable.mIconBitmap != null) { if (mSurfacePackage == null && parcelable.mIconBitmap != null) {
// We only create a Bitmap copies of immobile icons since animated icon are using // We only create a Bitmap copies of immobile icons since animated icon are using
@@ -163,6 +163,11 @@ public final class SplashScreenView extends FrameLayout {
mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap); mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
mParceledIconBitmap = parcelable.mIconBitmap; mParceledIconBitmap = parcelable.mIconBitmap;
} }
if (parcelable.mIconBackground != null) {
mIconBackground = new BitmapDrawable(mContext.getResources(),
parcelable.mIconBackground);
mParceledIconBackgroundBitmap = parcelable.mIconBackground;
}
if (parcelable.mBrandingBitmap != null) { if (parcelable.mBrandingBitmap != null) {
setBrandingDrawable(new BitmapDrawable(mContext.getResources(), setBrandingDrawable(new BitmapDrawable(mContext.getResources(),
parcelable.mBrandingBitmap), parcelable.mBrandingWidth, parcelable.mBrandingBitmap), parcelable.mBrandingWidth,
@@ -213,8 +218,8 @@ public final class SplashScreenView extends FrameLayout {
/** /**
* Set the background color for the icon. * Set the background color for the icon.
*/ */
public Builder setIconBackground(int color) { public Builder setIconBackground(Drawable iconBackground) {
mIconBackground = color; mIconBackground = iconBackground;
return this; return this;
} }
@@ -245,7 +250,6 @@ public final class SplashScreenView extends FrameLayout {
final SplashScreenView view = (SplashScreenView) final SplashScreenView view = (SplashScreenView)
layoutInflater.inflate(R.layout.splash_screen_view, null, false); layoutInflater.inflate(R.layout.splash_screen_view, null, false);
view.mInitBackgroundColor = mBackgroundColor; view.mInitBackgroundColor = mBackgroundColor;
view.mInitIconBackgroundColor = mIconBackground;
if (mOverlayDrawable != null) { if (mOverlayDrawable != null) {
view.setBackground(mOverlayDrawable); view.setBackground(mOverlayDrawable);
} else { } else {
@@ -263,25 +267,29 @@ public final class SplashScreenView extends FrameLayout {
mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0); mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
view.mIconAnimationStart = mIconAnimationStart; view.mIconAnimationStart = mIconAnimationStart;
view.mIconAnimationDuration = mIconAnimationDuration; view.mIconAnimationDuration = mIconAnimationDuration;
} else { } else if (mIconSize != 0) {
view.mIconView = view.findViewById(R.id.splashscreen_icon_view); ImageView imageView = view.findViewById(R.id.splashscreen_icon_view);
if (mIconSize != 0) { assert imageView != null;
final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
params.width = mIconSize; final ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.height = mIconSize; params.width = mIconSize;
view.mIconView.setLayoutParams(params); params.height = mIconSize;
if (mIconDrawable != null) { imageView.setLayoutParams(params);
view.mIconView.setBackground(mIconDrawable); if (mIconDrawable != null) {
} imageView.setImageDrawable(mIconDrawable);
} }
if (mIconBackground != null) {
imageView.setBackground(mIconBackground);
}
view.mIconView = imageView;
} }
if (mOverlayDrawable != null || mIconDrawable == null) { if (mOverlayDrawable != null || mIconDrawable == null) {
view.setNotCopyable(); view.setNotCopyable();
} }
if (mParceledIconBitmap != null) { view.mParceledIconBackgroundBitmap = mParceledIconBackgroundBitmap;
view.mParceledIconBitmap = mParceledIconBitmap; view.mParceledIconBitmap = mParceledIconBitmap;
}
// branding image // branding image
if (mBrandingImageHeight > 0 && mBrandingImageWidth > 0 && mBrandingDrawable != null) { if (mBrandingImageHeight > 0 && mBrandingImageWidth > 0 && mBrandingDrawable != null) {
final ViewGroup.LayoutParams params = view.mBrandingImageView.getLayoutParams(); final ViewGroup.LayoutParams params = view.mBrandingImageView.getLayoutParams();
@@ -310,6 +318,7 @@ public final class SplashScreenView extends FrameLayout {
private SurfaceView createSurfaceView(@NonNull SplashScreenView view) { private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
final SurfaceView surfaceView = new SurfaceView(view.getContext()); final SurfaceView surfaceView = new SurfaceView(view.getContext());
surfaceView.setPadding(0, 0, 0, 0); surfaceView.setPadding(0, 0, 0, 0);
surfaceView.setBackground(mIconBackground);
if (mSurfacePackage == null) { if (mSurfacePackage == null) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, Log.d(TAG,
@@ -475,7 +484,11 @@ public final class SplashScreenView extends FrameLayout {
} }
setVisibility(GONE); setVisibility(GONE);
if (mParceledIconBitmap != null) { if (mParceledIconBitmap != null) {
mIconView.setBackground(null); if (mIconView instanceof ImageView) {
((ImageView) mIconView).setImageDrawable(null);
} else if (mIconView != null) {
mIconView.setBackground(null);
}
mParceledIconBitmap.recycle(); mParceledIconBitmap.recycle();
mParceledIconBitmap = null; mParceledIconBitmap = null;
} }
@@ -484,6 +497,13 @@ public final class SplashScreenView extends FrameLayout {
mParceledBrandingBitmap.recycle(); mParceledBrandingBitmap.recycle();
mParceledBrandingBitmap = null; mParceledBrandingBitmap = null;
} }
if (mParceledIconBackgroundBitmap != null) {
if (mIconView != null) {
mIconView.setBackground(null);
}
mParceledIconBackgroundBitmap.recycle();
mParceledIconBackgroundBitmap = null;
}
if (mWindow != null) { if (mWindow != null) {
final DecorView decorView = (DecorView) mWindow.peekDecorView(); final DecorView decorView = (DecorView) mWindow.peekDecorView();
if (DEBUG) { if (DEBUG) {
@@ -599,15 +619,6 @@ public final class SplashScreenView extends FrameLayout {
return mBrandingImageView; return mBrandingImageView;
} }
/**
* Get the icon background color
* @hide
*/
@TestApi
public @ColorInt int getIconBackgroundColor() {
return mInitIconBackgroundColor;
}
/** /**
* Get the initial background color of this view. * Get the initial background color of this view.
* @hide * @hide
@@ -637,7 +648,7 @@ public final class SplashScreenView extends FrameLayout {
public static class SplashScreenViewParcelable implements Parcelable { public static class SplashScreenViewParcelable implements Parcelable {
private int mIconSize; private int mIconSize;
private int mBackgroundColor; private int mBackgroundColor;
private int mIconBackground; private Bitmap mIconBackground;
private Bitmap mIconBitmap = null; private Bitmap mIconBitmap = null;
private int mBrandingWidth; private int mBrandingWidth;
@@ -653,11 +664,11 @@ public final class SplashScreenView extends FrameLayout {
public SplashScreenViewParcelable(SplashScreenView view) { public SplashScreenViewParcelable(SplashScreenView view) {
mIconSize = view.mIconView.getWidth(); mIconSize = view.mIconView.getWidth();
mBackgroundColor = view.getInitBackgroundColor(); mBackgroundColor = view.getInitBackgroundColor();
mIconBackground = view.getIconBackgroundColor(); mIconBackground = copyDrawable(view.getIconView().getBackground());
mSurfacePackage = view.mSurfacePackageCopy; mSurfacePackage = view.mSurfacePackageCopy;
if (mSurfacePackage == null) { if (mSurfacePackage == null) {
// We only need to copy the drawable if we are not using a SurfaceView // We only need to copy the drawable if we are not using a SurfaceView
mIconBitmap = copyDrawable(view.getIconView().getBackground()); mIconBitmap = copyDrawable(((ImageView) view.getIconView()).getDrawable());
} }
mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground()); mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
@@ -703,7 +714,7 @@ public final class SplashScreenView extends FrameLayout {
mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR); mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
mIconAnimationStartMillis = source.readLong(); mIconAnimationStartMillis = source.readLong();
mIconAnimationDurationMillis = source.readLong(); mIconAnimationDurationMillis = source.readLong();
mIconBackground = source.readInt(); mIconBackground = source.readTypedObject(Bitmap.CREATOR);
mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR); mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
mClientCallback = source.readTypedObject(RemoteCallback.CREATOR); mClientCallback = source.readTypedObject(RemoteCallback.CREATOR);
} }
@@ -723,7 +734,7 @@ public final class SplashScreenView extends FrameLayout {
dest.writeTypedObject(mBrandingBitmap, flags); dest.writeTypedObject(mBrandingBitmap, flags);
dest.writeLong(mIconAnimationStartMillis); dest.writeLong(mIconAnimationStartMillis);
dest.writeLong(mIconAnimationDurationMillis); dest.writeLong(mIconAnimationDurationMillis);
dest.writeInt(mIconBackground); dest.writeTypedObject(mIconBackground, flags);
dest.writeTypedObject(mSurfacePackage, flags); dest.writeTypedObject(mSurfacePackage, flags);
dest.writeTypedObject(mClientCallback, flags); dest.writeTypedObject(mClientCallback, flags);
} }
@@ -760,10 +771,6 @@ public final class SplashScreenView extends FrameLayout {
return mBackgroundColor; return mBackgroundColor;
} }
int getIconBackground() {
return mIconBackground;
}
/** /**
* Sets the {@link RemoteCallback} that will be called by the client to notify the shell * Sets the {@link RemoteCallback} that will be called by the client to notify the shell
* of the removal of the {@link SplashScreenView}. * of the removal of the {@link SplashScreenView}.

View File

@@ -21,12 +21,11 @@
android:padding="0dp" android:padding="0dp"
android:orientation="vertical"> android:orientation="vertical">
<View android:id="@+id/splashscreen_icon_view" <ImageView android:id="@+id/splashscreen_icon_view"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:padding="0dp" android:padding="0dp"
android:background="@null"
android:contentDescription="@string/splash_screen_view_icon_description"/> android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view" <View android:id="@+id/splashscreen_branding_view"

View File

@@ -25,6 +25,7 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCRE
import android.annotation.ColorInt; import android.annotation.ColorInt;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -315,7 +316,7 @@ public class SplashscreenContentDrawer {
private Drawable mOverlayDrawable; private Drawable mOverlayDrawable;
private int mSuggestType; private int mSuggestType;
private int mThemeColor; private int mThemeColor;
private Drawable mFinalIconDrawable; private Drawable[] mFinalIconDrawables;
private int mFinalIconSize = mIconSize; private int mFinalIconSize = mIconSize;
StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) { StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
@@ -347,12 +348,13 @@ public class SplashscreenContentDrawer {
animationDuration = 0; animationDuration = 0;
mFinalIconSize = 0; mFinalIconSize = 0;
} else if (mTmpAttrs.mSplashScreenIcon != null) { } else if (mTmpAttrs.mSplashScreenIcon != null) {
// replaced icon, don't process // Using the windowSplashScreenAnimatedIcon attribute
iconDrawable = mTmpAttrs.mSplashScreenIcon; iconDrawable = mTmpAttrs.mSplashScreenIcon;
animationDuration = mTmpAttrs.mAnimationDuration; animationDuration = mTmpAttrs.mAnimationDuration;
// There is no background below the icon, so scale the icon up // There is no background below the icon, so scale the icon up
if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT) { if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT
|| mTmpAttrs.mIconBgColor == mThemeColor) {
mFinalIconSize *= NO_BACKGROUND_SCALE; mFinalIconSize *= NO_BACKGROUND_SCALE;
} }
createIconDrawable(iconDrawable, false); createIconDrawable(iconDrawable, false);
@@ -383,7 +385,7 @@ public class SplashscreenContentDrawer {
animationDuration = 0; animationDuration = 0;
} }
return fillViewWithIcon(mFinalIconSize, mFinalIconDrawable, animationDuration); return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration);
} }
private class ShapeIconFactory extends BaseIconFactory { private class ShapeIconFactory extends BaseIconFactory {
@@ -394,12 +396,11 @@ public class SplashscreenContentDrawer {
private void createIconDrawable(Drawable iconDrawable, boolean legacy) { private void createIconDrawable(Drawable iconDrawable, boolean legacy) {
if (legacy) { if (legacy) {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeLegacyIconDrawable( mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler); iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
} else { } else {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable( mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable(
mTmpAttrs.mIconBgColor != Color.TRANSPARENT mTmpAttrs.mIconBgColor, mThemeColor,
? mTmpAttrs.mIconBgColor : mThemeColor,
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler); iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
} }
} }
@@ -461,18 +462,24 @@ public class SplashscreenContentDrawer {
return true; return true;
} }
private SplashScreenView fillViewWithIcon(int iconSize, Drawable iconDrawable, private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable,
int animationDuration) { int animationDuration) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); Drawable foreground = null;
final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); Drawable background = null;
builder.setBackgroundColor(mThemeColor);
builder.setOverlayDrawable(mOverlayDrawable);
if (iconDrawable != null) { if (iconDrawable != null) {
builder.setIconSize(iconSize) foreground = iconDrawable.length > 0 ? iconDrawable[0] : null;
.setIconBackground(mTmpAttrs.mIconBgColor) background = iconDrawable.length > 1 ? iconDrawable[1] : null;
.setCenterViewDrawable(iconDrawable)
.setAnimationDurationMillis(animationDuration);
} }
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext)
.setBackgroundColor(mThemeColor)
.setOverlayDrawable(mOverlayDrawable)
.setIconSize(iconSize)
.setIconBackground(background)
.setCenterViewDrawable(foreground)
.setAnimationDurationMillis(animationDuration);
if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
&& mTmpAttrs.mBrandingImage != null) { && mTmpAttrs.mBrandingImage != null) {
builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth,

View File

@@ -22,9 +22,11 @@ import android.animation.Animator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.annotation.ColorInt; import android.annotation.ColorInt;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
@@ -33,7 +35,6 @@ import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
import android.os.Trace; import android.os.Trace;
@@ -44,32 +45,55 @@ import com.android.internal.R;
/** /**
* Creating a lightweight Drawable object used for splash screen. * Creating a lightweight Drawable object used for splash screen.
*
* @hide * @hide
*/ */
public class SplashscreenIconDrawableFactory { public class SplashscreenIconDrawableFactory {
static Drawable makeIconDrawable(@ColorInt int backgroundColor, /**
* @return An array containing the foreground drawable at index 0 and if needed a background
* drawable at index 1.
*/
static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
@NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize, @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
Handler splashscreenWorkerHandler) { Handler splashscreenWorkerHandler) {
Drawable foreground;
Drawable background = null;
boolean drawBackground =
backgroundColor != Color.TRANSPARENT && backgroundColor != themeColor;
if (foregroundDrawable instanceof Animatable) { if (foregroundDrawable instanceof Animatable) {
return new AnimatableIconAnimateListener(backgroundColor, foregroundDrawable); foreground = new AnimatableIconAnimateListener(foregroundDrawable);
} else if (foregroundDrawable instanceof AdaptiveIconDrawable) { } else if (foregroundDrawable instanceof AdaptiveIconDrawable) {
return new ImmobileIconDrawable(foregroundDrawable, // If the icon is Adaptive, we already use the icon background.
drawBackground = false;
foreground = new ImmobileIconDrawable(foregroundDrawable,
srcIconSize, iconSize, splashscreenWorkerHandler); srcIconSize, iconSize, splashscreenWorkerHandler);
} else { } else {
// single layer icon // Adaptive icon don't handle transparency so we draw the background of the adaptive
return new ImmobileIconDrawable(new AdaptiveIconDrawable( // icon with the same color as the window background color instead of using two layers
new ColorDrawable(backgroundColor), foregroundDrawable), foreground = new ImmobileIconDrawable(
new AdaptiveForegroundDrawable(foregroundDrawable),
srcIconSize, iconSize, splashscreenWorkerHandler); srcIconSize, iconSize, splashscreenWorkerHandler);
} }
if (drawBackground) {
background = new MaskBackgroundDrawable(backgroundColor);
}
return new Drawable[]{foreground, background};
} }
static Drawable makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize, static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
int iconSize, Handler splashscreenWorkerHandler) { int iconSize, Handler splashscreenWorkerHandler) {
return new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize, return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
splashscreenWorkerHandler); splashscreenWorkerHandler)};
} }
/**
* Drawable pre-drawing the scaled icon in a separate thread to increase the speed of the
* final drawing.
*/
private static class ImmobileIconDrawable extends Drawable { private static class ImmobileIconDrawable extends Drawable {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG); | Paint.FILTER_BITMAP_FLAG);
@@ -121,8 +145,10 @@ public class SplashscreenIconDrawableFactory {
} }
} }
// Base class the draw the circle background /**
private abstract static class MaskBackgroundDrawable extends Drawable { * Base class the draw a background clipped by the system mask.
*/
public static class MaskBackgroundDrawable extends Drawable {
private static final float MASK_SIZE = AdaptiveIconDrawable.MASK_SIZE; private static final float MASK_SIZE = AdaptiveIconDrawable.MASK_SIZE;
private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f; private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f;
static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE); static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
@@ -132,17 +158,24 @@ public class SplashscreenIconDrawableFactory {
private static Path sMask; private static Path sMask;
private final Path mMaskScaleOnly; private final Path mMaskScaleOnly;
private final Matrix mMaskMatrix; private final Matrix mMaskMatrix;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG);
MaskBackgroundDrawable(@ColorInt int backgroundColor) { @Nullable
private final Paint mBackgroundPaint;
public MaskBackgroundDrawable(@ColorInt int backgroundColor) {
final Resources r = Resources.getSystem(); final Resources r = Resources.getSystem();
sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask)); sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
Path mask = new Path(sMask); Path mask = new Path(sMask);
mMaskScaleOnly = new Path(mask); mMaskScaleOnly = new Path(mask);
mMaskMatrix = new Matrix(); mMaskMatrix = new Matrix();
mPaint.setColor(backgroundColor); if (backgroundColor != Color.TRANSPARENT) {
mPaint.setStyle(Paint.Style.FILL); mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG);
mBackgroundPaint.setColor(backgroundColor);
mBackgroundPaint.setStyle(Paint.Style.FILL);
} else {
mBackgroundPaint = null;
}
} }
@Override @Override
@@ -162,40 +195,80 @@ public class SplashscreenIconDrawableFactory {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
canvas.clipPath(mMaskScaleOnly); canvas.clipPath(mMaskScaleOnly);
if (mMaskScaleOnly != null) { if (mBackgroundPaint != null) {
canvas.drawPath(mMaskScaleOnly, mPaint); canvas.drawPath(mMaskScaleOnly, mBackgroundPaint);
} }
} }
@Override @Override
public void setAlpha(int alpha) { public void setAlpha(int alpha) {
mPaint.setAlpha(alpha); if (mBackgroundPaint != null) {
mBackgroundPaint.setAlpha(alpha);
}
} }
@Override @Override
public int getOpacity() { public int getOpacity() {
return PixelFormat.RGBA_8888; return PixelFormat.RGBA_8888;
} }
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
}
private static class AdaptiveForegroundDrawable extends MaskBackgroundDrawable {
@NonNull
protected final Drawable mForegroundDrawable;
private final Rect mTmpOutRect = new Rect();
AdaptiveForegroundDrawable(@NonNull Drawable foregroundDrawable) {
super(Color.TRANSPARENT);
mForegroundDrawable = foregroundDrawable;
}
@Override
protected void updateLayerBounds(Rect bounds) {
super.updateLayerBounds(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);
}
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
mForegroundDrawable.draw(canvas);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mForegroundDrawable.setColorFilter(colorFilter);
}
} }
/** /**
* A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this * A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
* drawable masked by config_icon_mask. * drawable masked by config_icon_mask.
*/ */
private static class AnimatableIconAnimateListener extends MaskBackgroundDrawable private static class AnimatableIconAnimateListener extends AdaptiveForegroundDrawable
implements SplashScreenView.IconAnimateListener { implements SplashScreenView.IconAnimateListener {
private final Drawable mForegroundDrawable;
private Animatable mAnimatableIcon; private Animatable mAnimatableIcon;
private Animator mIconAnimator; private Animator mIconAnimator;
private boolean mAnimationTriggered; private boolean mAnimationTriggered;
private final Rect mTmpOutRect = new Rect();
AnimatableIconAnimateListener(@ColorInt int backgroundColor, Drawable foregroundDrawable) { AnimatableIconAnimateListener(@NonNull Drawable foregroundDrawable) {
super(backgroundColor); super(foregroundDrawable);
mForegroundDrawable = foregroundDrawable; mForegroundDrawable.setCallback(mCallback);
if (mForegroundDrawable != null) {
mForegroundDrawable.setCallback(mCallback);
}
} }
@Override @Override
@@ -231,22 +304,6 @@ public class SplashscreenIconDrawableFactory {
return true; return true;
} }
@Override
protected void updateLayerBounds(Rect bounds) {
super.updateLayerBounds(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);
}
invalidateSelf();
}
private final Callback mCallback = new Callback() { private final Callback mCallback = new Callback() {
@Override @Override
public void invalidateDrawable(@NonNull Drawable who) { public void invalidateDrawable(@NonNull Drawable who) {
@@ -276,19 +333,8 @@ public class SplashscreenIconDrawableFactory {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
ensureAnimationStarted();
super.draw(canvas); super.draw(canvas);
if (mForegroundDrawable != null) {
ensureAnimationStarted();
mForegroundDrawable.draw(canvas);
}
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
if (mForegroundDrawable != null) {
mForegroundDrawable.setColorFilter(colorFilter);
}
} }
} }
} }