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

Commit 1d699ec6 authored by wilsonshih's avatar wilsonshih
Browse files

Load higher resolution resource for icon on splash screen when needed

Enlarge the basic icon visible size to 160dp, and loading higher icon
drawable if available. For replaced icon we also enlarge the visible
area.
And if the icon does not need to draw the background, apply another 1.3
times scale than normal case.

TODO: need to handle legacy icon.

Bug: 182883560
Test: atest SplashscreenTests
Change-Id: Ia72a72a743a7ef5f80f247393c1a5bd0b6653a48
parent fd0acf04
Loading
Loading
Loading
Loading
+0 −3
Original line number Original line Diff line number Diff line
@@ -52,9 +52,6 @@
     when the PIP menu is shown in center. -->
     when the PIP menu is shown in center. -->
    <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
    <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 -->
    <!-- Animation duration when exit starting window: icon going away -->
    <integer name="starting_window_icon_exit_anim_duration">166</integer>
    <integer name="starting_window_icon_exit_anim_duration">166</integer>


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


    <!-- The width/height of the icon view on staring surface. -->
    <!-- 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. -->
    <!-- The width/height of the size compat restart button. -->
    <dimen name="size_compat_button_size">48dp</dimen>
    <dimen name="size_compat_button_size">48dp</dimen>
+90 −86
Original line number Original line 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.Process.THREAD_PRIORITY_TOP_APP_BOOST;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.os.UserHandle.getUserHandleForUid;


import android.annotation.ColorInt;
import android.annotation.ColorInt;
import android.annotation.NonNull;
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
    // 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.
    // 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 ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
    private static final float NO_BACKGROUND_SCALE = 1.3f;
    private final Context mContext;
    private final Context mContext;
    private final IconProvider mIconProvider;
    private final IconProvider mIconProvider;
    private final int mMaxAnimatableIconDuration;


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


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


    private SplashScreenView makeEmptySplashScreenContentView(Context context) {
    private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
        getWindowAttrs(context, mTmpAttrs);
            boolean emptyView) {
        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) {
        updateDensity();
        updateDensity();


        getWindowAttrs(context, mTmpAttrs);
        getWindowAttrs(context, mTmpAttrs);
        final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
        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);
        final int themeBGColor = peekWindowBGColor(context);
        // TODO (b/173975965) Tracking the performance on improved splash screen.
        // TODO (b/173975965) Tracking the performance on improved splash screen.
        return builder
        return builder
                .setContext(context)
                .setContext(context)
                .setWindowBGColor(themeBGColor)
                .setWindowBGColor(themeBGColor)
                .setIconDrawable(iconDrawable)
                .makeEmptyView(emptyView)
                .setIconAnimationDuration(animationDuration)
                .setActivityInfo(ai)
                .setBrandingDrawable(mTmpAttrs.mBrandingImage)
                .build();
                .setIconBackground(mTmpAttrs.mIconBgColor).build();
    }
    }


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


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


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


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


        StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) {
        StartingWindowViewBuilder setActivityInfo(ActivityInfo ai) {
            mIconAnimationDuration = iconAnimationDuration;
            mActivityInfo = ai;
            mBuildComplete = false;
            return this;
        }

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

        StartingWindowViewBuilder setIconBackground(int color) {
            mIconBackground = color;
            mBuildComplete = false;
            mBuildComplete = false;
            return this;
            return this;
        }
        }
@@ -323,40 +280,66 @@ public class SplashscreenContentDrawer {
            if (mBuildComplete) {
            if (mBuildComplete) {
                return mCachedResult;
                return mCachedResult;
            }
            }
            if (mContext == null) {
            if (mContext == null || mActivityInfo == null) {
                Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
                Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
                return null;
                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) {
                    if (DEBUG) {
                        Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
                        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;
            mBuildComplete = true;
            return mCachedResult;
            return mCachedResult;
        }
        }


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


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


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


            final Drawable iconForeground = adaptiveIconDrawable.getForeground();
            Drawable iconForeground = adaptiveIconDrawable.getForeground();
            final DrawableColorTester foreIconTester =
            final DrawableColorTester foreIconTester =
                    new DrawableColorTester(iconForeground, true /* filterTransparent */);
                    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
            // 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
            // C. The background of the adaptive icon is grayscale, and the foreground of the
            // adaptive icon forms a certain contrast with the theme color.
            // 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()
                    || (backIconTester.isGrayscale()
                    && !isRgbSimilarInHsv(mThemeColor, foreMainColor)))) {
                    && !isRgbSimilarInHsv(mThemeColor, foreMainColor)))) {
                if (DEBUG) {
                if (DEBUG) {
@@ -390,8 +375,13 @@ public class SplashscreenContentDrawer {
                }
                }
                // Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
                // 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.
                // should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
                if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) {
                final float noBgScale =
                    mScale = 1.5f;
                        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
                // Using AdaptiveIconDrawable here can help keep the shape consistent with the
                // current settings.
                // current settings.
@@ -401,30 +391,44 @@ public class SplashscreenContentDrawer {
                if (DEBUG) {
                if (DEBUG) {
                    Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
                    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);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            return true;
            return true;
        }
        }


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