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 d89ddd2074f0ea685d6b38821b8752ed7774e0f7..8cee4f1dc8fb46a94baef40eb0f9cbd46a000aa5 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 @@ -35,6 +35,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -53,6 +55,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.DisplayMetrics; import android.util.Slog; import android.view.ContextThemeWrapper; import android.view.SurfaceControl; @@ -68,7 +71,6 @@ import com.android.internal.graphics.palette.VariationalKMeansQuantizer; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.IconProvider; -import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -102,7 +104,7 @@ public class SplashscreenContentDrawer { */ private static final float NO_BACKGROUND_SCALE = 192f / 160; private final Context mContext; - private final IconProvider mIconProvider; + private final HighResIconProvider mHighResIconProvider; private int mIconSize; private int mDefaultIconSize; @@ -115,12 +117,10 @@ public class SplashscreenContentDrawer { private final Handler mSplashscreenWorkerHandler; @VisibleForTesting final ColorCache mColorCache; - private final ShellExecutor mSplashScreenExecutor; - SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool, - ShellExecutor splashScreenExecutor) { + SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool) { mContext = context; - mIconProvider = iconProvider; + mHighResIconProvider = new HighResIconProvider(mContext, iconProvider); mTransactionPool = pool; // Initialize Splashscreen worker thread @@ -131,7 +131,6 @@ public class SplashscreenContentDrawer { shellSplashscreenWorkerThread.start(); mSplashscreenWorkerHandler = shellSplashscreenWorkerThread.getThreadHandler(); mColorCache = new ColorCache(mContext, mSplashscreenWorkerHandler); - mSplashScreenExecutor = splashScreenExecutor; } /** @@ -416,18 +415,16 @@ public class SplashscreenContentDrawer { || mTmpAttrs.mIconBgColor == mThemeColor) { mFinalIconSize *= NO_BACKGROUND_SCALE; } - createIconDrawable(iconDrawable, false); + createIconDrawable(iconDrawable, false /* legacy */, false /* loadInDetail */); } else { final float iconScale = (float) mIconSize / (float) mDefaultIconSize; final int densityDpi = mContext.getResources().getConfiguration().densityDpi; final int scaledIconDpi = (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon"); - iconDrawable = mIconProvider.getIcon(mActivityInfo, scaledIconDpi); + iconDrawable = mHighResIconProvider.getIcon( + mActivityInfo, densityDpi, scaledIconDpi); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - if (iconDrawable == null) { - iconDrawable = mContext.getPackageManager().getDefaultActivityIcon(); - } if (!processAdaptiveIcon(iconDrawable)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "The icon is not an AdaptiveIconDrawable"); @@ -437,7 +434,8 @@ public class SplashscreenContentDrawer { scaledIconDpi, mFinalIconSize); final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(iconDrawable); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - createIconDrawable(new BitmapDrawable(bitmap), true); + createIconDrawable(new BitmapDrawable(bitmap), true, + mHighResIconProvider.mLoadInDetail); } } @@ -450,14 +448,16 @@ public class SplashscreenContentDrawer { } } - private void createIconDrawable(Drawable iconDrawable, boolean legacy) { + private void createIconDrawable(Drawable iconDrawable, boolean legacy, + boolean loadInDetail) { if (legacy) { mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable( - iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler); + iconDrawable, mDefaultIconSize, mFinalIconSize, loadInDetail, + mSplashscreenWorkerHandler); } else { mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable( mTmpAttrs.mIconBgColor, mThemeColor, iconDrawable, mDefaultIconSize, - mFinalIconSize, mSplashscreenWorkerHandler); + mFinalIconSize, loadInDetail, mSplashscreenWorkerHandler); } } @@ -506,11 +506,11 @@ public class SplashscreenContentDrawer { // Using AdaptiveIconDrawable here can help keep the shape consistent with the // current settings. mFinalIconSize = (int) (0.5f + mIconSize * noBgScale); - createIconDrawable(iconForeground, false); + createIconDrawable(iconForeground, false, mHighResIconProvider.mLoadInDetail); } else { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "processAdaptiveIcon: draw whole icon"); - createIconDrawable(iconDrawable, false); + createIconDrawable(iconDrawable, false, mHighResIconProvider.mLoadInDetail); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return true; @@ -1015,4 +1015,77 @@ public class SplashscreenContentDrawer { playAnimation.run(); } } + + /** + * When loading a BitmapDrawable object with specific density, there will decode the image based + * on the density from display metrics, so even when load with higher override density, the + * final intrinsic size of a BitmapDrawable can still not big enough to draw on expect size. + * + * So here we use a standalone IconProvider object to load the Drawable object for higher + * density, and the resources object won't affect the entire system. + * + */ + private static class HighResIconProvider { + private final Context mSharedContext; + private final IconProvider mSharedIconProvider; + private boolean mLoadInDetail; + + // only create standalone icon provider when the density dpi is low. + private Context mStandaloneContext; + private IconProvider mStandaloneIconProvider; + + HighResIconProvider(Context context, IconProvider sharedIconProvider) { + mSharedContext = context; + mSharedIconProvider = sharedIconProvider; + } + + Drawable getIcon(ActivityInfo activityInfo, int currentDpi, int iconDpi) { + mLoadInDetail = false; + Drawable drawable; + if (currentDpi < iconDpi && currentDpi < DisplayMetrics.DENSITY_XHIGH) { + drawable = loadFromStandalone(activityInfo, currentDpi, iconDpi); + } else { + drawable = mSharedIconProvider.getIcon(activityInfo, iconDpi); + } + + if (drawable == null) { + drawable = mSharedContext.getPackageManager().getDefaultActivityIcon(); + } + return drawable; + } + + private Drawable loadFromStandalone(ActivityInfo activityInfo, int currentDpi, + int iconDpi) { + if (mStandaloneContext == null) { + final Configuration defConfig = mSharedContext.getResources().getConfiguration(); + mStandaloneContext = mSharedContext.createConfigurationContext(defConfig); + mStandaloneIconProvider = new IconProvider(mStandaloneContext); + } + Resources resources; + try { + resources = mStandaloneContext.getPackageManager() + .getResourcesForApplication(activityInfo.applicationInfo); + } catch (PackageManager.NameNotFoundException | Resources.NotFoundException exc) { + resources = null; + } + if (resources != null) { + updateResourcesDpi(resources, iconDpi); + } + final Drawable drawable = mStandaloneIconProvider.getIcon(activityInfo, iconDpi); + mLoadInDetail = true; + // reset density dpi + if (resources != null) { + updateResourcesDpi(resources, currentDpi); + } + return drawable; + } + + private void updateResourcesDpi(Resources resources, int densityDpi) { + final Configuration config = resources.getConfiguration(); + final DisplayMetrics displayMetrics = resources.getDisplayMetrics(); + config.densityDpi = densityDpi; + displayMetrics.densityDpi = densityDpi; + resources.updateConfiguration(config, displayMetrics); + } + } } 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 index 5f52071bf950478de8972f0a99b9329fecd86d8b..7f6bfd23f72b9b1983779cefd6be6d4b69b322d0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java @@ -62,7 +62,7 @@ public class SplashscreenIconDrawableFactory { */ static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor, @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize, - Handler splashscreenWorkerHandler) { + boolean loadInDetail, Handler splashscreenWorkerHandler) { Drawable foreground; Drawable background = null; boolean drawBackground = @@ -74,13 +74,13 @@ public class SplashscreenIconDrawableFactory { // If the icon is Adaptive, we already use the icon background. drawBackground = false; foreground = new ImmobileIconDrawable(foregroundDrawable, - srcIconSize, iconSize, splashscreenWorkerHandler); + srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler); } else { // Adaptive icon don't handle transparency so we draw the background of the adaptive // icon with the same color as the window background color instead of using two layers foreground = new ImmobileIconDrawable( new AdaptiveForegroundDrawable(foregroundDrawable), - srcIconSize, iconSize, splashscreenWorkerHandler); + srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler); } if (drawBackground) { @@ -91,9 +91,9 @@ public class SplashscreenIconDrawableFactory { } static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize, - int iconSize, Handler splashscreenWorkerHandler) { + int iconSize, boolean loadInDetail, Handler splashscreenWorkerHandler) { return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize, - splashscreenWorkerHandler)}; + loadInDetail, splashscreenWorkerHandler)}; } /** @@ -106,11 +106,16 @@ public class SplashscreenIconDrawableFactory { private final Matrix mMatrix = new Matrix(); private Bitmap mIconBitmap; - ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, + ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, boolean loadInDetail, Handler splashscreenWorkerHandler) { - final float scale = (float) iconSize / srcIconSize; - mMatrix.setScale(scale, scale); - splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize)); + // This icon has lower density, don't scale it. + if (loadInDetail) { + splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, iconSize)); + } else { + final float scale = (float) iconSize / srcIconSize; + mMatrix.setScale(scale, scale); + splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize)); + } } private void preDrawIcon(Drawable drawable, int size) { 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 464ab1ae2a8cfbf049d174b39507bf24d167b4e1..54d62edf25701935590c36353a717f972a35b712 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 @@ -153,8 +153,7 @@ public class StartingSurfaceDrawer { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); mSplashScreenExecutor = splashScreenExecutor; - mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool, - mSplashScreenExecutor); + mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool); mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance()); mWindowManagerGlobal = WindowManagerGlobal.getInstance(); mDisplayManager.getDisplay(DEFAULT_DISPLAY);