Merge "Update density dpi before load drawable." into tm-dev am: c122c97cff am: 5ea986ec93

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17951297

Change-Id: Ic866ed73289d1908d659ac3ffd69361ae3be585f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Wei Sheng Shih
2022-05-11 02:45:43 +00:00
committed by Automerger Merge Worker
3 changed files with 106 additions and 29 deletions

View File

@@ -35,6 +35,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@@ -53,6 +55,7 @@ import android.os.SystemClock;
import android.os.Trace; import android.os.Trace;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Slog; import android.util.Slog;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.SurfaceControl; 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.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider; 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.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -102,7 +104,7 @@ public class SplashscreenContentDrawer {
*/ */
private static final float NO_BACKGROUND_SCALE = 192f / 160; private static final float NO_BACKGROUND_SCALE = 192f / 160;
private final Context mContext; private final Context mContext;
private final IconProvider mIconProvider; private final HighResIconProvider mHighResIconProvider;
private int mIconSize; private int mIconSize;
private int mDefaultIconSize; private int mDefaultIconSize;
@@ -115,12 +117,10 @@ public class SplashscreenContentDrawer {
private final Handler mSplashscreenWorkerHandler; private final Handler mSplashscreenWorkerHandler;
@VisibleForTesting @VisibleForTesting
final ColorCache mColorCache; final ColorCache mColorCache;
private final ShellExecutor mSplashScreenExecutor;
SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool, SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool) {
ShellExecutor splashScreenExecutor) {
mContext = context; mContext = context;
mIconProvider = iconProvider; mHighResIconProvider = new HighResIconProvider(mContext, iconProvider);
mTransactionPool = pool; mTransactionPool = pool;
// Initialize Splashscreen worker thread // Initialize Splashscreen worker thread
@@ -131,7 +131,6 @@ public class SplashscreenContentDrawer {
shellSplashscreenWorkerThread.start(); shellSplashscreenWorkerThread.start();
mSplashscreenWorkerHandler = shellSplashscreenWorkerThread.getThreadHandler(); mSplashscreenWorkerHandler = shellSplashscreenWorkerThread.getThreadHandler();
mColorCache = new ColorCache(mContext, mSplashscreenWorkerHandler); mColorCache = new ColorCache(mContext, mSplashscreenWorkerHandler);
mSplashScreenExecutor = splashScreenExecutor;
} }
/** /**
@@ -416,18 +415,16 @@ public class SplashscreenContentDrawer {
|| mTmpAttrs.mIconBgColor == mThemeColor) { || mTmpAttrs.mIconBgColor == mThemeColor) {
mFinalIconSize *= NO_BACKGROUND_SCALE; mFinalIconSize *= NO_BACKGROUND_SCALE;
} }
createIconDrawable(iconDrawable, false); createIconDrawable(iconDrawable, false /* legacy */, false /* loadInDetail */);
} else { } else {
final float iconScale = (float) mIconSize / (float) mDefaultIconSize; final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
final int densityDpi = mContext.getResources().getConfiguration().densityDpi; final int densityDpi = mContext.getResources().getConfiguration().densityDpi;
final int scaledIconDpi = final int scaledIconDpi =
(int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE); (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon");
iconDrawable = mIconProvider.getIcon(mActivityInfo, scaledIconDpi); iconDrawable = mHighResIconProvider.getIcon(
mActivityInfo, densityDpi, scaledIconDpi);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (iconDrawable == null) {
iconDrawable = mContext.getPackageManager().getDefaultActivityIcon();
}
if (!processAdaptiveIcon(iconDrawable)) { if (!processAdaptiveIcon(iconDrawable)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"The icon is not an AdaptiveIconDrawable"); "The icon is not an AdaptiveIconDrawable");
@@ -437,7 +434,8 @@ public class SplashscreenContentDrawer {
scaledIconDpi, mFinalIconSize); scaledIconDpi, mFinalIconSize);
final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(iconDrawable); final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(iconDrawable);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 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) { if (legacy) {
mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable( mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler); iconDrawable, mDefaultIconSize, mFinalIconSize, loadInDetail,
mSplashscreenWorkerHandler);
} else { } else {
mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable( mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable(
mTmpAttrs.mIconBgColor, mThemeColor, iconDrawable, mDefaultIconSize, 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 // Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings. // current settings.
mFinalIconSize = (int) (0.5f + mIconSize * noBgScale); mFinalIconSize = (int) (0.5f + mIconSize * noBgScale);
createIconDrawable(iconForeground, false); createIconDrawable(iconForeground, false, mHighResIconProvider.mLoadInDetail);
} else { } else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"processAdaptiveIcon: draw whole icon"); "processAdaptiveIcon: draw whole icon");
createIconDrawable(iconDrawable, false); createIconDrawable(iconDrawable, false, mHighResIconProvider.mLoadInDetail);
} }
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return true; return true;
@@ -1015,4 +1015,77 @@ public class SplashscreenContentDrawer {
playAnimation.run(); 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);
}
}
} }

View File

@@ -62,7 +62,7 @@ public class SplashscreenIconDrawableFactory {
*/ */
static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor, 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) { boolean loadInDetail, Handler splashscreenWorkerHandler) {
Drawable foreground; Drawable foreground;
Drawable background = null; Drawable background = null;
boolean drawBackground = boolean drawBackground =
@@ -74,13 +74,13 @@ public class SplashscreenIconDrawableFactory {
// If the icon is Adaptive, we already use the icon background. // If the icon is Adaptive, we already use the icon background.
drawBackground = false; drawBackground = false;
foreground = new ImmobileIconDrawable(foregroundDrawable, foreground = new ImmobileIconDrawable(foregroundDrawable,
srcIconSize, iconSize, splashscreenWorkerHandler); srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
} else { } else {
// Adaptive icon don't handle transparency so we draw the background of the adaptive // 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 // icon with the same color as the window background color instead of using two layers
foreground = new ImmobileIconDrawable( foreground = new ImmobileIconDrawable(
new AdaptiveForegroundDrawable(foregroundDrawable), new AdaptiveForegroundDrawable(foregroundDrawable),
srcIconSize, iconSize, splashscreenWorkerHandler); srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
} }
if (drawBackground) { if (drawBackground) {
@@ -91,9 +91,9 @@ public class SplashscreenIconDrawableFactory {
} }
static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize, 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, return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
splashscreenWorkerHandler)}; loadInDetail, splashscreenWorkerHandler)};
} }
/** /**
@@ -106,12 +106,17 @@ public class SplashscreenIconDrawableFactory {
private final Matrix mMatrix = new Matrix(); private final Matrix mMatrix = new Matrix();
private Bitmap mIconBitmap; private Bitmap mIconBitmap;
ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, boolean loadInDetail,
Handler splashscreenWorkerHandler) { Handler splashscreenWorkerHandler) {
// This icon has lower density, don't scale it.
if (loadInDetail) {
splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, iconSize));
} else {
final float scale = (float) iconSize / srcIconSize; final float scale = (float) iconSize / srcIconSize;
mMatrix.setScale(scale, scale); mMatrix.setScale(scale, scale);
splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize)); splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
} }
}
private void preDrawIcon(Drawable drawable, int size) { private void preDrawIcon(Drawable drawable, int size) {
synchronized (mPaint) { synchronized (mPaint) {

View File

@@ -153,8 +153,7 @@ public class StartingSurfaceDrawer {
mContext = context; mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor; mSplashScreenExecutor = splashScreenExecutor;
mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool, mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool);
mSplashScreenExecutor);
mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance()); mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
mWindowManagerGlobal = WindowManagerGlobal.getInstance(); mWindowManagerGlobal = WindowManagerGlobal.getInstance();
mDisplayManager.getDisplay(DEFAULT_DISPLAY); mDisplayManager.getDisplay(DEFAULT_DISPLAY);