Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11b1cb28 authored by Wei Sheng Shih's avatar Wei Sheng Shih Committed by Android (Google) Code Review
Browse files

Merge "Load higher resolution resource for icon on splash screen when needed" into sc-dev

parents 5a080745 1d699ec6
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -52,9 +52,6 @@
     when the PIP menu is shown in center. -->
    <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>

    <!-- maximum animation duration for the icon when entering the starting window -->
    <integer name="max_starting_window_intro_icon_anim_duration">1000</integer>

    <!-- Animation duration when exit starting window: icon going away -->
    <integer name="starting_window_icon_exit_anim_duration">166</integer>

+3 −1
Original line number Diff line number Diff line
@@ -178,7 +178,9 @@
    <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>

    <!-- The width/height of the icon view on staring surface. -->
    <dimen name="starting_surface_icon_size">108dp</dimen>
    <dimen name="starting_surface_icon_size">160dp</dimen>
    <!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
    <dimen name="default_icon_size">108dp</dimen>

    <!-- The width/height of the size compat restart button. -->
    <dimen name="size_compat_button_size">48dp</dimen>
+90 −86
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.wm.shell.startingsurface;

import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.os.UserHandle.getUserHandleForUid;

import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -68,11 +67,12 @@ public class SplashscreenContentDrawer {
    // For example, an icon with the foreground 108*108 opaque pixels and it's background
    // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
    private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
    private static final float NO_BACKGROUND_SCALE = 1.3f;
    private final Context mContext;
    private final IconProvider mIconProvider;
    private final int mMaxAnimatableIconDuration;

    private int mIconSize;
    private int mDefaultIconSize;
    private int mBrandingImageWidth;
    private int mBrandingImageHeight;
    private final int mAppRevealDuration;
@@ -84,11 +84,10 @@ public class SplashscreenContentDrawer {
    private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs();
    private final Handler mSplashscreenWorkerHandler;

    SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
            int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
    SplashscreenContentDrawer(Context context, int iconExitAnimDuration, int appRevealAnimDuration,
            TransactionPool pool) {
        mContext = context;
        mIconProvider = new IconProvider(context);
        mMaxAnimatableIconDuration = maxAnimatableIconDuration;
        mAppRevealDuration = appRevealAnimDuration;
        mIconExitDuration = iconExitAnimDuration;
        mTransactionPool = pool;
@@ -122,11 +121,7 @@ public class SplashscreenContentDrawer {
                        context, splashScreenResId);
                if (contentView == null) {
                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
                    if (emptyView) {
                        contentView = makeEmptySplashScreenContentView(context);
                    } else {
                        contentView = makeSplashScreenContentView(context, info);
                    }
                    contentView = makeSplashScreenContentView(context, info, emptyView);
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                }
            } catch (RuntimeException e) {
@@ -141,6 +136,8 @@ public class SplashscreenContentDrawer {
    private void updateDensity() {
        mIconSize = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.starting_surface_icon_size);
        mDefaultIconSize = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.default_icon_size);
        mBrandingImageWidth = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.starting_surface_brand_image_width);
        mBrandingImageHeight = mContext.getResources().getDimensionPixelSize(
@@ -195,46 +192,20 @@ public class SplashscreenContentDrawer {
        }
    }

    private SplashScreenView makeEmptySplashScreenContentView(Context context) {
        getWindowAttrs(context, mTmpAttrs);
        final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
        final int themeBGColor = peekWindowBGColor(context);
        final SplashScreenView view =  builder
                .setContext(context)
                .setWindowBGColor(themeBGColor)
                .build();
        view.setNotCopyable();
        return view;
    }

    private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai) {
    private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
            boolean emptyView) {
        updateDensity();

        getWindowAttrs(context, mTmpAttrs);
        final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
        final int animationDuration;
        Drawable iconDrawable;
        if (mTmpAttrs.mReplaceIcon != null) {
            iconDrawable = mTmpAttrs.mReplaceIcon;
            animationDuration = Math.max(0,
                    Math.min(mTmpAttrs.mAnimationDuration, mMaxAnimatableIconDuration));
        } else {
            iconDrawable = mIconProvider.getIconForUI(
                    ai, getUserHandleForUid(ai.applicationInfo.uid));
            if (iconDrawable == null) {
                iconDrawable = context.getPackageManager().getDefaultActivityIcon();
            }
            animationDuration = 0;
        }
        final int themeBGColor = peekWindowBGColor(context);
        // TODO (b/173975965) Tracking the performance on improved splash screen.
        return builder
                .setContext(context)
                .setWindowBGColor(themeBGColor)
                .setIconDrawable(iconDrawable)
                .setIconAnimationDuration(animationDuration)
                .setBrandingDrawable(mTmpAttrs.mBrandingImage)
                .setIconBackground(mTmpAttrs.mIconBgColor).build();
                .makeEmptyView(emptyView)
                .setActivityInfo(ai)
                .build();
    }

    private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) {
@@ -270,11 +241,9 @@ public class SplashscreenContentDrawer {
    }

    private class StartingWindowViewBuilder {
        private Drawable mIconDrawable;
        private int mIconAnimationDuration;
        private ActivityInfo mActivityInfo;
        private Context mContext;
        private Drawable mBrandingDrawable;
        private @ColorInt int mIconBackground;
        private boolean mEmptyView;

        // result
        private boolean mBuildComplete = false;
@@ -289,26 +258,14 @@ public class SplashscreenContentDrawer {
            return this;
        }

        StartingWindowViewBuilder setIconDrawable(Drawable iconDrawable) {
            mIconDrawable = iconDrawable;
        StartingWindowViewBuilder makeEmptyView(boolean empty) {
            mEmptyView = empty;
            mBuildComplete = false;
            return this;
        }

        StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) {
            mIconAnimationDuration = iconAnimationDuration;
            mBuildComplete = false;
            return this;
        }

        StartingWindowViewBuilder setBrandingDrawable(Drawable branding) {
            mBrandingDrawable = branding;
            mBuildComplete = false;
            return this;
        }

        StartingWindowViewBuilder setIconBackground(int color) {
            mIconBackground = color;
        StartingWindowViewBuilder setActivityInfo(ActivityInfo ai) {
            mActivityInfo = ai;
            mBuildComplete = false;
            return this;
        }
@@ -323,40 +280,66 @@ public class SplashscreenContentDrawer {
            if (mBuildComplete) {
                return mCachedResult;
            }
            if (mContext == null) {
            if (mContext == null || mActivityInfo == null) {
                Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
                return null;
            }

            if (!processAdaptiveIcon() && mIconDrawable != null) {
            Drawable iconDrawable;
            final int animationDuration;
            final int iconSize;
            if (mEmptyView) {
                // empty splash screen case
                animationDuration = 0;
                iconSize = 0;
            } else if (mTmpAttrs.mReplaceIcon != null) {
                // replaced icon, don't process
                iconDrawable = mTmpAttrs.mReplaceIcon;
                animationDuration = mTmpAttrs.mAnimationDuration;
                createIconDrawable(iconDrawable, mIconSize);
                iconSize = mIconSize;
            } else {
                final float iconScale =  (float) mIconSize / (float) mDefaultIconSize;
                iconDrawable = mIconProvider.getIcon(mActivityInfo);
                if (iconDrawable == null) {
                    iconDrawable = mContext.getPackageManager().getDefaultActivityIcon();
                }
                if (!processAdaptiveIcon(iconDrawable, iconScale)) {
                    if (DEBUG) {
                        Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
                    }
                createIconDrawable(mIconDrawable, mIconSize);
                    // TODO process legacy icon(bitmap)
                    final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale);
                    createIconDrawable(tempIcon, mIconSize);
                }
                animationDuration = 0;
                iconSize = (int) (0.5 + mIconSize * mScale);
            }
            final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
            mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);

            mCachedResult = fillViewWithIcon(iconSize, mFinalIconDrawable, animationDuration);
            mBuildComplete = true;
            return mCachedResult;
        }

        private void createIconDrawable(Drawable iconDrawable, int iconSize) {
            mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
                    mIconBackground != Color.TRANSPARENT ? mIconBackground : mThemeColor,
                    mTmpAttrs.mIconBgColor != Color.TRANSPARENT
                            ? mTmpAttrs.mIconBgColor : mThemeColor,
                    iconDrawable, iconSize, mSplashscreenWorkerHandler);
        }

        private boolean processAdaptiveIcon() {
            if (!(mIconDrawable instanceof AdaptiveIconDrawable)) {
        private boolean processAdaptiveIcon(Drawable iconDrawable, float iconScale) {
            if (!(iconDrawable instanceof AdaptiveIconDrawable)) {
                return false;
            }

            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "processAdaptiveIcon");
            final AdaptiveIconDrawable adaptiveIconDrawable = (AdaptiveIconDrawable) mIconDrawable;
            final AdaptiveIconDrawable adaptiveIconDrawable =
                    (AdaptiveIconDrawable) iconDrawable;
            final DrawableColorTester backIconTester =
                    new DrawableColorTester(adaptiveIconDrawable.getBackground());

            final Drawable iconForeground = adaptiveIconDrawable.getForeground();
            Drawable iconForeground = adaptiveIconDrawable.getForeground();
            final DrawableColorTester foreIconTester =
                    new DrawableColorTester(iconForeground, true /* filterTransparent */);

@@ -382,7 +365,9 @@ public class SplashscreenContentDrawer {
            // B. The background of the adaptive icon is similar to the theme color, or
            // C. The background of the adaptive icon is grayscale, and the foreground of the
            // adaptive icon forms a certain contrast with the theme color.
            if (!backComplex && (isRgbSimilarInHsv(mThemeColor, backMainColor)
            // D. Didn't specify icon background color.
            if (!backComplex && mTmpAttrs.mIconBgColor == Color.TRANSPARENT
                    && (isRgbSimilarInHsv(mThemeColor, backMainColor)
                    || (backIconTester.isGrayscale()
                    && !isRgbSimilarInHsv(mThemeColor, foreMainColor)))) {
                if (DEBUG) {
@@ -390,8 +375,13 @@ public class SplashscreenContentDrawer {
                }
                // 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) {
                    mScale = 1.5f;
                final float noBgScale =
                        foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD
                                ? NO_BACKGROUND_SCALE : 1f;
                final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale * noBgScale);
                if (tempIcon instanceof AdaptiveIconDrawable) {
                    mScale = noBgScale;
                    iconForeground = ((AdaptiveIconDrawable) tempIcon).getForeground();
                }
                // Using AdaptiveIconDrawable here can help keep the shape consistent with the
                // current settings.
@@ -401,30 +391,44 @@ public class SplashscreenContentDrawer {
                if (DEBUG) {
                    Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
                }
                createIconDrawable(adaptiveIconDrawable, mIconSize);
                final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale);
                createIconDrawable(tempIcon, mIconSize);
            }
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            return true;
        }

        private SplashScreenView fillViewWithIcon(Context context,
                int iconSize, Drawable iconDrawable) {
        private Drawable loadIconByDensity(Drawable baseDrawable, float scale) {
            if (scale == 1 && baseDrawable != null) {
                return baseDrawable;
            }
            final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi;
            final int updateDpi = (int) (0.5f + scale * densityDpi);
            return  mIconProvider.getIcon(mActivityInfo, updateDpi);
        }

        private SplashScreenView fillViewWithIcon(int iconSize, Drawable iconDrawable,
                int animationDuration) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
            final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
            builder.setIconSize(iconSize).setBackgroundColor(mThemeColor)
                    .setIconBackground(mIconBackground);
            final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext);
            builder.setBackgroundColor(mThemeColor);
            if (iconDrawable != null) {
                builder.setCenterViewDrawable(iconDrawable);
                builder.setIconSize(iconSize)
                        .setIconBackground(mTmpAttrs.mIconBgColor)
                        .setCenterViewDrawable(iconDrawable)
                        .setAnimationDurationMillis(animationDuration);
            }
            builder.setAnimationDurationMillis(mIconAnimationDuration);
            if (mBrandingDrawable != null) {
                builder.setBrandingDrawable(mBrandingDrawable, mBrandingImageWidth,
            if (mTmpAttrs.mBrandingImage != null) {
                builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth,
                        mBrandingImageHeight);
            }
            final SplashScreenView splashScreenView = builder.build();
            if (DEBUG) {
                Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView);
            }
            if (mEmptyView) {
                splashScreenView.setNotCopyable();
            }
            splashScreenView.makeSystemUIColorsTransparent();
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            return splashScreenView;
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ public class SplashscreenIconDrawableFactory {
            return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable, iconSize,
                    splashscreenWorkerHandler);
        } else {
            // TODO for legacy icon don't use adaptive icon drawable to wrapper it
            return new ImmobileIconDrawable(new AdaptiveIconDrawable(
                    new ColorDrawable(backgroundColor), foregroundDrawable), iconSize,
                    splashscreenWorkerHandler);
+2 −4
Original line number Diff line number Diff line
@@ -114,14 +114,12 @@ public class StartingSurfaceDrawer {
        mContext = context;
        mDisplayManager = mContext.getSystemService(DisplayManager.class);
        mSplashScreenExecutor = splashScreenExecutor;
        final int maxAnimatableIconDuration = context.getResources().getInteger(
                com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration);
        final int iconExitAnimDuration = context.getResources().getInteger(
                com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
        final int appRevealAnimDuration = context.getResources().getInteger(
                com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
        mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext,
                maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool);
        mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconExitAnimDuration,
                appRevealAnimDuration, pool);
        mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
    }