From e31a09a9bf45c3983d2fab2e31877cf75521c6bc Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 3 Mar 2020 01:15:27 +0000 Subject: [PATCH] Removes iconloaderlib from Launcher3. Bug: 138964382 Test: builds Change-Id: Ic60adfb2ebdcf1a72b440df26023b861fd6e62d5 Merged-In: Ic60adfb2ebdcf1a72b440df26023b861fd6e62d5 --- iconloaderlib/Android.bp | 44 -- iconloaderlib/AndroidManifest.xml | 20 - iconloaderlib/build.gradle | 38 -- .../adaptive_icon_drawable_wrapper.xml | 22 - .../res/drawable/ic_instant_app_badge.xml | 39 -- iconloaderlib/res/values/colors.xml | 21 - iconloaderlib/res/values/config.xml | 27 - iconloaderlib/res/values/dimens.xml | 19 - .../launcher3/icons/BaseIconFactory.java | 396 ------------ .../android/launcher3/icons/BitmapInfo.java | 72 --- .../launcher3/icons/BitmapRenderer.java | 70 --- .../launcher3/icons/ColorExtractor.java | 127 ---- .../android/launcher3/icons/DotRenderer.java | 143 ----- .../launcher3/icons/FixedScaleDrawable.java | 53 -- .../launcher3/icons/GraphicsUtils.java | 85 --- .../launcher3/icons/IconNormalizer.java | 411 ------------- .../launcher3/icons/ShadowGenerator.java | 167 ----- .../launcher3/icons/cache/BaseIconCache.java | 582 ------------------ .../launcher3/icons/cache/CachingLogic.java | 65 -- .../icons/cache/HandlerRunnable.java | 67 -- .../icons/cache/IconCacheUpdateHandler.java | 313 ---------- .../android/launcher3/util/ComponentKey.java | 59 -- .../launcher3/util/NoLocaleSQLiteHelper.java | 58 -- .../launcher3/util/SQLiteCacheHelper.java | 125 ---- .../android/launcher3/icons/IconFactory.java | 89 --- .../launcher3/icons/SimpleIconCache.java | 114 ---- 26 files changed, 3226 deletions(-) delete mode 100644 iconloaderlib/Android.bp delete mode 100644 iconloaderlib/AndroidManifest.xml delete mode 100644 iconloaderlib/build.gradle delete mode 100644 iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml delete mode 100644 iconloaderlib/res/drawable/ic_instant_app_badge.xml delete mode 100644 iconloaderlib/res/values/colors.xml delete mode 100644 iconloaderlib/res/values/config.xml delete mode 100644 iconloaderlib/res/values/dimens.xml delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java delete mode 100644 iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java delete mode 100644 iconloaderlib/src/com/android/launcher3/util/ComponentKey.java delete mode 100644 iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java delete mode 100644 iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java delete mode 100644 iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java delete mode 100644 iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java diff --git a/iconloaderlib/Android.bp b/iconloaderlib/Android.bp deleted file mode 100644 index f12d16e42a..0000000000 --- a/iconloaderlib/Android.bp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -android_library { - name: "iconloader_base", - sdk_version: "28", - min_sdk_version: "21", - static_libs: [ - "androidx.core_core", - ], - resource_dirs: [ - "res", - ], - srcs: [ - "src/**/*.java", - ], -} - -android_library { - name: "iconloader", - sdk_version: "system_current", - min_sdk_version: "21", - static_libs: [ - "androidx.core_core", - ], - resource_dirs: [ - "res", - ], - srcs: [ - "src/**/*.java", - "src_full_lib/**/*.java", - ], -} diff --git a/iconloaderlib/AndroidManifest.xml b/iconloaderlib/AndroidManifest.xml deleted file mode 100644 index b30258da2a..0000000000 --- a/iconloaderlib/AndroidManifest.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle deleted file mode 100644 index d7a62e1114..0000000000 --- a/iconloaderlib/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion COMPILE_SDK - buildToolsVersion BUILD_TOOLS_VERSION - - defaultConfig { - minSdkVersion 25 - targetSdkVersion 28 - versionCode 1 - versionName "1.0" - } - - sourceSets { - main { - java.srcDirs = ['src', 'src_full_lib'] - manifest.srcFile 'AndroidManifest.xml' - res.srcDirs = ['res'] - } - } - - lintOptions { - abortOnError false - } - - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - implementation "androidx.core:core:${ANDROID_X_VERSION}" -} diff --git a/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml deleted file mode 100644 index 9f13cf5719..0000000000 --- a/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - diff --git a/iconloaderlib/res/drawable/ic_instant_app_badge.xml b/iconloaderlib/res/drawable/ic_instant_app_badge.xml deleted file mode 100644 index b74317e5f2..0000000000 --- a/iconloaderlib/res/drawable/ic_instant_app_badge.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - diff --git a/iconloaderlib/res/values/colors.xml b/iconloaderlib/res/values/colors.xml deleted file mode 100644 index 873b2fc5fb..0000000000 --- a/iconloaderlib/res/values/colors.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - #FFFFFF - diff --git a/iconloaderlib/res/values/config.xml b/iconloaderlib/res/values/config.xml deleted file mode 100644 index 68c2d2e3aa..0000000000 --- a/iconloaderlib/res/values/config.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - 56dp - false - app_icons.db - - \ No newline at end of file diff --git a/iconloaderlib/res/values/dimens.xml b/iconloaderlib/res/values/dimens.xml deleted file mode 100644 index e8c0c44f72..0000000000 --- a/iconloaderlib/res/values/dimens.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - 24dp - diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java deleted file mode 100644 index 31a923e314..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ /dev/null @@ -1,396 +0,0 @@ -package com.android.launcher3.icons; - -import static android.graphics.Paint.DITHER_FLAG; -import static android.graphics.Paint.FILTER_BITMAP_FLAG; - -import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.PaintFlagsDrawFilter; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Process; -import android.os.UserHandle; - -import androidx.annotation.NonNull; - -/** - * This class will be moved to androidx library. There shouldn't be any dependency outside - * this package. - */ -public class BaseIconFactory implements AutoCloseable { - - private static final String TAG = "BaseIconFactory"; - private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE; - static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; - static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; - - private static final float ICON_BADGE_SCALE = 0.444f; - - private final Rect mOldBounds = new Rect(); - protected final Context mContext; - private final Canvas mCanvas; - private final PackageManager mPm; - private final ColorExtractor mColorExtractor; - private boolean mDisableColorExtractor; - private boolean mBadgeOnLeft = false; - - protected final int mFillResIconDpi; - protected final int mIconBitmapSize; - - private IconNormalizer mNormalizer; - private ShadowGenerator mShadowGenerator; - private final boolean mShapeDetection; - - private Drawable mWrapperIcon; - private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; - - protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize, - boolean shapeDetection) { - mContext = context.getApplicationContext(); - mShapeDetection = shapeDetection; - mFillResIconDpi = fillResIconDpi; - mIconBitmapSize = iconBitmapSize; - - mPm = mContext.getPackageManager(); - mColorExtractor = new ColorExtractor(); - - mCanvas = new Canvas(); - mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG)); - clear(); - } - - protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) { - this(context, fillResIconDpi, iconBitmapSize, false); - } - - protected void clear() { - mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; - mDisableColorExtractor = false; - mBadgeOnLeft = false; - } - - public ShadowGenerator getShadowGenerator() { - if (mShadowGenerator == null) { - mShadowGenerator = new ShadowGenerator(mIconBitmapSize); - } - return mShadowGenerator; - } - - public IconNormalizer getNormalizer() { - if (mNormalizer == null) { - mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection); - } - return mNormalizer; - } - - @SuppressWarnings("deprecation") - public BitmapInfo createIconBitmap(Intent.ShortcutIconResource iconRes) { - try { - Resources resources = mPm.getResourcesForApplication(iconRes.packageName); - if (resources != null) { - final int id = resources.getIdentifier(iconRes.resourceName, null, null); - // do not stamp old legacy shortcuts as the app may have already forgotten about it - return createBadgedIconBitmap( - resources.getDrawableForDensity(id, mFillResIconDpi), - Process.myUserHandle() /* only available on primary user */, - false /* do not apply legacy treatment */); - } - } catch (Exception e) { - // Icon not found. - } - return null; - } - - public BitmapInfo createIconBitmap(Bitmap icon) { - if (mIconBitmapSize != icon.getWidth() || mIconBitmapSize != icon.getHeight()) { - icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f); - } - - return BitmapInfo.of(icon, extractColor(icon)); - } - - public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, - boolean shrinkNonAdaptiveIcons) { - return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, false, null); - } - - public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, - int iconAppTargetSdk) { - return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false); - } - - public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, - int iconAppTargetSdk, boolean isInstantApp) { - return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null); - } - - public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, - int iconAppTargetSdk, boolean isInstantApp, float[] scale) { - boolean shrinkNonAdaptiveIcons = ATLEAST_P || - (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O); - return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, scale); - } - - public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) { - boolean shrinkNonAdaptiveIcons = ATLEAST_P || - (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O); - return createScaledBitmapWithoutShadow(icon, shrinkNonAdaptiveIcons); - } - - /** - * Creates bitmap using the source drawable and various parameters. - * The bitmap is visually normalized with other icons and has enough spacing to add shadow. - * - * @param icon source of the icon - * @param user info can be used for a badge - * @param shrinkNonAdaptiveIcons {@code true} if non adaptive icons should be treated - * @param isInstantApp info can be used for a badge - * @param scale returns the scale result from normalization - * @return a bitmap suitable for disaplaying as an icon at various system UIs. - */ - public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon, UserHandle user, - boolean shrinkNonAdaptiveIcons, boolean isInstantApp, float[] scale) { - if (scale == null) { - scale = new float[1]; - } - icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale); - Bitmap bitmap = createIconBitmap(icon, scale[0]); - if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { - mCanvas.setBitmap(bitmap); - getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas); - mCanvas.setBitmap(null); - } - - if (isInstantApp) { - badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge)); - } - if (user != null) { - BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap); - Drawable badged = mPm.getUserBadgedIcon(drawable, user); - if (badged instanceof BitmapDrawable) { - bitmap = ((BitmapDrawable) badged).getBitmap(); - } else { - bitmap = createIconBitmap(badged, 1f); - } - } - int color = extractColor(bitmap); - return icon instanceof BitmapInfo.Extender - ? ((BitmapInfo.Extender) icon).getExtendedInfo(bitmap, color, this) - : BitmapInfo.of(bitmap, color); - } - - public Bitmap createScaledBitmapWithoutShadow(Drawable icon, boolean shrinkNonAdaptiveIcons) { - RectF iconBounds = new RectF(); - float[] scale = new float[1]; - icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, iconBounds, scale); - return createIconBitmap(icon, - Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds))); - } - - /** - * Switches badging to left/right - */ - public void setBadgeOnLeft(boolean badgeOnLeft) { - mBadgeOnLeft = badgeOnLeft; - } - - /** - * Sets the background color used for wrapped adaptive icon - */ - public void setWrapperBackgroundColor(int color) { - mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color; - } - - /** - * Disables the dominant color extraction for all icons loaded. - */ - public void disableColorExtraction() { - mDisableColorExtractor = true; - } - - private Drawable normalizeAndWrapToAdaptiveIcon(@NonNull Drawable icon, - boolean shrinkNonAdaptiveIcons, RectF outIconBounds, float[] outScale) { - if (icon == null) { - return null; - } - float scale = 1f; - - if (shrinkNonAdaptiveIcons && ATLEAST_OREO) { - if (mWrapperIcon == null) { - mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper) - .mutate(); - } - AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon; - dr.setBounds(0, 0, 1, 1); - boolean[] outShape = new boolean[1]; - scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape); - if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { - FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); - fsd.setDrawable(icon); - fsd.setScale(scale); - icon = dr; - scale = getNormalizer().getScale(icon, outIconBounds, null, null); - - ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor); - } - } else { - scale = getNormalizer().getScale(icon, outIconBounds, null, null); - } - - outScale[0] = scale; - return icon; - } - - /** - * Adds the {@param badge} on top of {@param target} using the badge dimensions. - */ - public void badgeWithDrawable(Bitmap target, Drawable badge) { - mCanvas.setBitmap(target); - badgeWithDrawable(mCanvas, badge); - mCanvas.setBitmap(null); - } - - /** - * Adds the {@param badge} on top of {@param target} using the badge dimensions. - */ - public void badgeWithDrawable(Canvas target, Drawable badge) { - int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize); - if (mBadgeOnLeft) { - badge.setBounds(0, mIconBitmapSize - badgeSize, badgeSize, mIconBitmapSize); - } else { - badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize, - mIconBitmapSize, mIconBitmapSize); - } - badge.draw(target); - } - - private Bitmap createIconBitmap(Drawable icon, float scale) { - return createIconBitmap(icon, scale, mIconBitmapSize); - } - - /** - * @param icon drawable that should be flattened to a bitmap - * @param scale the scale to apply before drawing {@param icon} on the canvas - */ - public Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size) { - Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); - if (icon == null) { - return bitmap; - } - mCanvas.setBitmap(bitmap); - mOldBounds.set(icon.getBounds()); - - if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { - int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size), - Math.round(size * (1 - scale) / 2 )); - icon.setBounds(offset, offset, size - offset, size - offset); - icon.draw(mCanvas); - } else { - if (icon instanceof BitmapDrawable) { - BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; - Bitmap b = bitmapDrawable.getBitmap(); - if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) { - bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics()); - } - } - int width = size; - int height = size; - - int intrinsicWidth = icon.getIntrinsicWidth(); - int intrinsicHeight = icon.getIntrinsicHeight(); - if (intrinsicWidth > 0 && intrinsicHeight > 0) { - // Scale the icon proportionally to the icon dimensions - final float ratio = (float) intrinsicWidth / intrinsicHeight; - if (intrinsicWidth > intrinsicHeight) { - height = (int) (width / ratio); - } else if (intrinsicHeight > intrinsicWidth) { - width = (int) (height * ratio); - } - } - final int left = (size - width) / 2; - final int top = (size - height) / 2; - icon.setBounds(left, top, left + width, top + height); - mCanvas.save(); - mCanvas.scale(scale, scale, size / 2, size / 2); - icon.draw(mCanvas); - mCanvas.restore(); - - } - icon.setBounds(mOldBounds); - mCanvas.setBitmap(null); - return bitmap; - } - - @Override - public void close() { - clear(); - } - - public BitmapInfo makeDefaultIcon(UserHandle user) { - return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi), - user, Build.VERSION.SDK_INT); - } - - public static Drawable getFullResDefaultActivityIcon(int iconDpi) { - return Resources.getSystem().getDrawableForDensity( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O - ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon, - iconDpi); - } - - /** - * Badges the provided source with the badge info - */ - public BitmapInfo badgeBitmap(Bitmap source, BitmapInfo badgeInfo) { - Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> { - getShadowGenerator().recreateIcon(source, c); - badgeWithDrawable(c, new FixedSizeBitmapDrawable(badgeInfo.icon)); - }); - return BitmapInfo.of(icon, badgeInfo.color); - } - - private int extractColor(Bitmap bitmap) { - return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap); - } - - /** - * Returns the correct badge size given an icon size - */ - public static int getBadgeSizeForIconSize(int iconSize) { - return (int) (ICON_BADGE_SCALE * iconSize); - } - - /** - * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size. - * This allows the badging to be done based on the action bitmap size rather than - * the scaled bitmap size. - */ - private static class FixedSizeBitmapDrawable extends BitmapDrawable { - - public FixedSizeBitmapDrawable(Bitmap bitmap) { - super(null, bitmap); - } - - @Override - public int getIntrinsicHeight() { - return getBitmap().getWidth(); - } - - @Override - public int getIntrinsicWidth() { - return getBitmap().getWidth(); - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java deleted file mode 100644 index d33f9b1112..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; - -import androidx.annotation.NonNull; - -public class BitmapInfo { - - public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8); - public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON); - - public final Bitmap icon; - public final int color; - - public BitmapInfo(Bitmap icon, int color) { - this.icon = icon; - this.color = color; - } - - /** - * Ideally icon should not be null, except in cases when generating hardware bitmap failed - */ - public final boolean isNullOrLowRes() { - return icon == null || icon == LOW_RES_ICON; - } - - public final boolean isLowRes() { - return LOW_RES_ICON == icon; - } - - public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) { - return of(bitmap, 0); - } - - public static BitmapInfo of(@NonNull Bitmap bitmap, int color) { - return new BitmapInfo(bitmap, color); - } - - /** - * Interface to be implemented by drawables to provide a custom BitmapInfo - */ - public interface Extender { - - /** - * Called for creating a custom BitmapInfo - */ - default BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory) { - return BitmapInfo.of(bitmap, color); - } - - /** - * Notifies the drawable that it will be drawn directly in the UI, without any preprocessing - */ - default void prepareToDrawOnUi() { } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java deleted file mode 100644 index 5751ed95cb..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Picture; -import android.graphics.Rect; -import android.graphics.RectF; -import android.os.Build; -import android.os.Build.VERSION_CODES; - -/** - * Interface representing a bitmap draw operation. - */ -public interface BitmapRenderer { - - boolean USE_HARDWARE_BITMAP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; - - static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) { - GraphicsUtils.noteNewBitmapCreated(); - Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - renderer.draw(new Canvas(result)); - return result; - } - - @TargetApi(Build.VERSION_CODES.P) - static Bitmap createHardwareBitmap(int width, int height, BitmapRenderer renderer) { - if (!USE_HARDWARE_BITMAP) { - return createSoftwareBitmap(width, height, renderer); - } - - GraphicsUtils.noteNewBitmapCreated(); - Picture picture = new Picture(); - renderer.draw(picture.beginRecording(width, height)); - picture.endRecording(); - return Bitmap.createBitmap(picture); - } - - /** - * Returns a bitmap from subset of the source bitmap. The new bitmap may be the - * same object as source, or a copy may have been made. - */ - static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { - if (Build.VERSION.SDK_INT >= VERSION_CODES.O && source.getConfig() == Config.HARDWARE) { - return createHardwareBitmap(width, height, c -> c.drawBitmap(source, - new Rect(x, y, x + width, y + height), new RectF(0, 0, width, height), null)); - } else { - GraphicsUtils.noteNewBitmapCreated(); - return Bitmap.createBitmap(source, x, y, width, height); - } - } - - void draw(Canvas out); -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java b/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java deleted file mode 100644 index 87bda825cc..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.util.SparseArray; -import java.util.Arrays; - -/** - * Utility class for extracting colors from a bitmap. - */ -public class ColorExtractor { - - private final int NUM_SAMPLES = 20; - private final float[] mTmpHsv = new float[3]; - private final float[] mTmpHueScoreHistogram = new float[360]; - private final int[] mTmpPixels = new int[NUM_SAMPLES]; - private final SparseArray mTmpRgbScores = new SparseArray<>(); - - /** - * This picks a dominant color, looking for high-saturation, high-value, repeated hues. - * @param bitmap The bitmap to scan - */ - public int findDominantColorByHue(Bitmap bitmap) { - return findDominantColorByHue(bitmap, NUM_SAMPLES); - } - - /** - * This picks a dominant color, looking for high-saturation, high-value, repeated hues. - * @param bitmap The bitmap to scan - */ - public int findDominantColorByHue(Bitmap bitmap, int samples) { - final int height = bitmap.getHeight(); - final int width = bitmap.getWidth(); - int sampleStride = (int) Math.sqrt((height * width) / samples); - if (sampleStride < 1) { - sampleStride = 1; - } - - // This is an out-param, for getting the hsv values for an rgb - float[] hsv = mTmpHsv; - Arrays.fill(hsv, 0); - - // First get the best hue, by creating a histogram over 360 hue buckets, - // where each pixel contributes a score weighted by saturation, value, and alpha. - float[] hueScoreHistogram = mTmpHueScoreHistogram; - Arrays.fill(hueScoreHistogram, 0); - float highScore = -1; - int bestHue = -1; - - int[] pixels = mTmpPixels; - Arrays.fill(pixels, 0); - int pixelCount = 0; - - for (int y = 0; y < height; y += sampleStride) { - for (int x = 0; x < width; x += sampleStride) { - int argb = bitmap.getPixel(x, y); - int alpha = 0xFF & (argb >> 24); - if (alpha < 0x80) { - // Drop mostly-transparent pixels. - continue; - } - // Remove the alpha channel. - int rgb = argb | 0xFF000000; - Color.colorToHSV(rgb, hsv); - // Bucket colors by the 360 integer hues. - int hue = (int) hsv[0]; - if (hue < 0 || hue >= hueScoreHistogram.length) { - // Defensively avoid array bounds violations. - continue; - } - if (pixelCount < samples) { - pixels[pixelCount++] = rgb; - } - float score = hsv[1] * hsv[2]; - hueScoreHistogram[hue] += score; - if (hueScoreHistogram[hue] > highScore) { - highScore = hueScoreHistogram[hue]; - bestHue = hue; - } - } - } - - SparseArray rgbScores = mTmpRgbScores; - rgbScores.clear(); - int bestColor = 0xff000000; - highScore = -1; - // Go back over the RGB colors that match the winning hue, - // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets. - // The highest-scoring RGB color wins. - for (int i = 0; i < pixelCount; i++) { - int rgb = pixels[i]; - Color.colorToHSV(rgb, hsv); - int hue = (int) hsv[0]; - if (hue == bestHue) { - float s = hsv[1]; - float v = hsv[2]; - int bucket = (int) (s * 100) + (int) (v * 10000); - // Score by cumulative saturation * value. - float score = s * v; - Float oldTotal = rgbScores.get(bucket); - float newTotal = oldTotal == null ? score : oldTotal + score; - rgbScores.put(bucket, newTotal); - if (newTotal > highScore) { - highScore = newTotal; - // All the colors in the winning bucket are very similar. Last in wins. - bestColor = rgb; - } - } - } - return bestColor; - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java deleted file mode 100644 index 97a0fd3ffc..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.icons; - -import static android.graphics.Paint.ANTI_ALIAS_FLAG; -import static android.graphics.Paint.FILTER_BITMAP_FLAG; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.graphics.Rect; -import android.graphics.RectF; -import android.util.Log; -import android.view.ViewDebug; - -/** - * Used to draw a notification dot on top of an icon. - */ -public class DotRenderer { - - private static final String TAG = "DotRenderer"; - - // The dot size is defined as a percentage of the app icon size. - private static final float SIZE_PERCENTAGE = 0.228f; - - private final float mCircleRadius; - private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); - - private final Bitmap mBackgroundWithShadow; - private final float mBitmapOffset; - - // Stores the center x and y position as a percentage (0 to 1) of the icon size - private final float[] mRightDotPosition; - private final float[] mLeftDotPosition; - - public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) { - int size = Math.round(SIZE_PERCENTAGE * iconSizePx); - ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT); - builder.ambientShadowAlpha = 88; - mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size); - mCircleRadius = builder.radius; - - mBitmapOffset = -mBackgroundWithShadow.getHeight() * 0.5f; // Same as width. - - // Find the points on the path that are closest to the top left and right corners. - mLeftDotPosition = getPathPoint(iconShapePath, pathSize, -1); - mRightDotPosition = getPathPoint(iconShapePath, pathSize, 1); - } - - private static float[] getPathPoint(Path path, float size, float direction) { - float halfSize = size / 2; - // Small delta so that we don't get a zero size triangle - float delta = 1; - - float x = halfSize + direction * halfSize; - Path trianglePath = new Path(); - trianglePath.moveTo(halfSize, halfSize); - trianglePath.lineTo(x + delta * direction, 0); - trianglePath.lineTo(x, -delta); - trianglePath.close(); - - trianglePath.op(path, Path.Op.INTERSECT); - float[] pos = new float[2]; - new PathMeasure(trianglePath, false).getPosTan(0, pos, null); - - pos[0] = pos[0] / size; - pos[1] = pos[1] / size; - return pos; - } - - public float[] getLeftDotPosition() { - return mLeftDotPosition; - } - - public float[] getRightDotPosition() { - return mRightDotPosition; - } - - /** - * Draw a circle on top of the canvas according to the given params. - */ - public void draw(Canvas canvas, DrawParams params) { - if (params == null) { - Log.e(TAG, "Invalid null argument(s) passed in call to draw."); - return; - } - canvas.save(); - - Rect iconBounds = params.iconBounds; - float[] dotPosition = params.leftAlign ? mLeftDotPosition : mRightDotPosition; - float dotCenterX = iconBounds.left + iconBounds.width() * dotPosition[0]; - float dotCenterY = iconBounds.top + iconBounds.height() * dotPosition[1]; - - // Ensure dot fits entirely in canvas clip bounds. - Rect canvasBounds = canvas.getClipBounds(); - float offsetX = params.leftAlign - ? Math.max(0, canvasBounds.left - (dotCenterX + mBitmapOffset)) - : Math.min(0, canvasBounds.right - (dotCenterX - mBitmapOffset)); - float offsetY = Math.max(0, canvasBounds.top - (dotCenterY + mBitmapOffset)); - - // We draw the dot relative to its center. - canvas.translate(dotCenterX + offsetX, dotCenterY + offsetY); - canvas.scale(params.scale, params.scale); - - mCirclePaint.setColor(Color.BLACK); - canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint); - mCirclePaint.setColor(params.color); - canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); - canvas.restore(); - } - - public static class DrawParams { - /** The color (possibly based on the icon) to use for the dot. */ - @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true) - public int color; - /** The bounds of the icon that the dot is drawn on top of. */ - @ViewDebug.ExportedProperty(category = "notification dot") - public Rect iconBounds = new Rect(); - /** The progress of the animation, from 0 to 1. */ - @ViewDebug.ExportedProperty(category = "notification dot") - public float scale; - /** Whether the dot should align to the top left of the icon rather than the top right. */ - @ViewDebug.ExportedProperty(category = "notification dot") - public boolean leftAlign; - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java b/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java deleted file mode 100644 index 516965ec2b..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.android.launcher3.icons; - -import android.content.res.Resources; -import android.content.res.Resources.Theme; -import android.graphics.Canvas; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.DrawableWrapper; -import android.util.AttributeSet; - -import org.xmlpull.v1.XmlPullParser; - -/** - * Extension of {@link DrawableWrapper} which scales the child drawables by a fixed amount. - */ -public class FixedScaleDrawable extends DrawableWrapper { - - // TODO b/33553066 use the constant defined in MaskableIconDrawable - private static final float LEGACY_ICON_SCALE = .7f * .6667f; - private float mScaleX, mScaleY; - - public FixedScaleDrawable() { - super(new ColorDrawable()); - mScaleX = LEGACY_ICON_SCALE; - mScaleY = LEGACY_ICON_SCALE; - } - - @Override - public void draw(Canvas canvas) { - int saveCount = canvas.save(); - canvas.scale(mScaleX, mScaleY, - getBounds().exactCenterX(), getBounds().exactCenterY()); - super.draw(canvas); - canvas.restoreToCount(saveCount); - } - - @Override - public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) { } - - @Override - public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { } - - public void setScale(float scale) { - float h = getIntrinsicHeight(); - float w = getIntrinsicWidth(); - mScaleX = scale * LEGACY_ICON_SCALE; - mScaleY = scale * LEGACY_ICON_SCALE; - if (h > w && w > 0) { - mScaleX *= w / h; - } else if (w > h && h > 0) { - mScaleY *= h / w; - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java b/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java deleted file mode 100644 index 22f1f2357e..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.Region; -import android.graphics.RegionIterator; -import android.util.Log; - -import androidx.annotation.ColorInt; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class GraphicsUtils { - - private static final String TAG = "GraphicsUtils"; - - public static Runnable sOnNewBitmapRunnable = () -> { }; - - /** - * Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version, - * it bounds the alpha in valid range instead of throwing an exception to allow for safer - * interpolation of color animations - */ - @ColorInt - public static int setColorAlphaBound(int color, int alpha) { - if (alpha < 0) { - alpha = 0; - } else if (alpha > 255) { - alpha = 255; - } - return (color & 0x00ffffff) | (alpha << 24); - } - - /** - * Compresses the bitmap to a byte array for serialization. - */ - public static byte[] flattenBitmap(Bitmap bitmap) { - // Try go guesstimate how much space the icon will take when serialized - // to avoid unnecessary allocations/copies during the write (4 bytes per pixel). - int size = bitmap.getWidth() * bitmap.getHeight() * 4; - ByteArrayOutputStream out = new ByteArrayOutputStream(size); - try { - bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); - out.flush(); - out.close(); - return out.toByteArray(); - } catch (IOException e) { - Log.w(TAG, "Could not write bitmap"); - return null; - } - } - - public static int getArea(Region r) { - RegionIterator itr = new RegionIterator(r); - int area = 0; - Rect tempRect = new Rect(); - while (itr.next(tempRect)) { - area += tempRect.width() * tempRect.height(); - } - return area; - } - - /** - * Utility method to track new bitmap creation - */ - public static void noteNewBitmapCreated() { - sOnNewBitmapRunnable.run(); - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java deleted file mode 100644 index de39e79fec..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.icons; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.util.Log; - -import java.nio.ByteBuffer; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -public class IconNormalizer { - - private static final String TAG = "IconNormalizer"; - private static final boolean DEBUG = false; - // Ratio of icon visible area to full icon size for a square shaped icon - private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576; - // Ratio of icon visible area to full icon size for a circular shaped icon - private static final float MAX_CIRCLE_AREA_FACTOR = 380.0f / 576; - - private static final float CIRCLE_AREA_BY_RECT = (float) Math.PI / 4; - - // Slope used to calculate icon visible area to full icon size for any generic shaped icon. - private static final float LINEAR_SCALE_SLOPE = - (MAX_CIRCLE_AREA_FACTOR - MAX_SQUARE_AREA_FACTOR) / (1 - CIRCLE_AREA_BY_RECT); - - private static final int MIN_VISIBLE_ALPHA = 40; - - // Shape detection related constants - private static final float BOUND_RATIO_MARGIN = .05f; - private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f; - private static final float SCALE_NOT_INITIALIZED = 0; - - // Ratio of the diameter of an normalized circular icon to the actual icon size. - public static final float ICON_VISIBLE_AREA_FACTOR = 0.92f; - - private final int mMaxSize; - private final Bitmap mBitmap; - private final Canvas mCanvas; - private final Paint mPaintMaskShape; - private final Paint mPaintMaskShapeOutline; - private final byte[] mPixels; - - private final RectF mAdaptiveIconBounds; - private float mAdaptiveIconScale; - - private boolean mEnableShapeDetection; - - // for each y, stores the position of the leftmost x and the rightmost x - private final float[] mLeftBorder; - private final float[] mRightBorder; - private final Rect mBounds; - private final Path mShapePath; - private final Matrix mMatrix; - - /** package private **/ - IconNormalizer(Context context, int iconBitmapSize, boolean shapeDetection) { - // Use twice the icon size as maximum size to avoid scaling down twice. - mMaxSize = iconBitmapSize * 2; - mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8); - mCanvas = new Canvas(mBitmap); - mPixels = new byte[mMaxSize * mMaxSize]; - mLeftBorder = new float[mMaxSize]; - mRightBorder = new float[mMaxSize]; - mBounds = new Rect(); - mAdaptiveIconBounds = new RectF(); - - mPaintMaskShape = new Paint(); - mPaintMaskShape.setColor(Color.RED); - mPaintMaskShape.setStyle(Paint.Style.FILL); - mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); - - mPaintMaskShapeOutline = new Paint(); - mPaintMaskShapeOutline.setStrokeWidth( - 2 * context.getResources().getDisplayMetrics().density); - mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE); - mPaintMaskShapeOutline.setColor(Color.BLACK); - mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); - - mShapePath = new Path(); - mMatrix = new Matrix(); - mAdaptiveIconScale = SCALE_NOT_INITIALIZED; - mEnableShapeDetection = shapeDetection; - } - - private static float getScale(float hullArea, float boundingArea, float fullArea) { - float hullByRect = hullArea / boundingArea; - float scaleRequired; - if (hullByRect < CIRCLE_AREA_BY_RECT) { - scaleRequired = MAX_CIRCLE_AREA_FACTOR; - } else { - scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect); - } - - float areaScale = hullArea / fullArea; - // Use sqrt of the final ratio as the images is scaled across both width and height. - return areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1; - } - - /** - * @param d Should be AdaptiveIconDrawable - * @param size Canvas size to use - */ - @TargetApi(Build.VERSION_CODES.O) - public static float normalizeAdaptiveIcon(Drawable d, int size, @Nullable RectF outBounds) { - Rect tmpBounds = new Rect(d.getBounds()); - d.setBounds(0, 0, size, size); - - Path path = ((AdaptiveIconDrawable) d).getIconMask(); - Region region = new Region(); - region.setPath(path, new Region(0, 0, size, size)); - - Rect hullBounds = region.getBounds(); - int hullArea = GraphicsUtils.getArea(region); - - if (outBounds != null) { - float sizeF = size; - outBounds.set( - hullBounds.left / sizeF, - hullBounds.top / sizeF, - 1 - (hullBounds.right / sizeF), - 1 - (hullBounds.bottom / sizeF)); - } - d.setBounds(tmpBounds); - return getScale(hullArea, hullArea, size * size); - } - - /** - * Returns if the shape of the icon is same as the path. - * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds. - */ - private boolean isShape(Path maskPath) { - // Condition1: - // If width and height of the path not close to a square, then the icon shape is - // not same as the mask shape. - float iconRatio = ((float) mBounds.width()) / mBounds.height(); - if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) { - if (DEBUG) { - Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio); - } - return false; - } - - // Condition 2: - // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation - // should generate transparent image, if the actual icon is equivalent to the shape. - - // Fit the shape within the icon's bounding box - mMatrix.reset(); - mMatrix.setScale(mBounds.width(), mBounds.height()); - mMatrix.postTranslate(mBounds.left, mBounds.top); - maskPath.transform(mMatrix, mShapePath); - - // XOR operation - mCanvas.drawPath(mShapePath, mPaintMaskShape); - - // DST_OUT operation around the mask path outline - mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline); - - // Check if the result is almost transparent - return isTransparentBitmap(); - } - - /** - * Used to determine if certain the bitmap is transparent. - */ - private boolean isTransparentBitmap() { - ByteBuffer buffer = ByteBuffer.wrap(mPixels); - buffer.rewind(); - mBitmap.copyPixelsToBuffer(buffer); - - int y = mBounds.top; - // buffer position - int index = y * mMaxSize; - // buffer shift after every row, width of buffer = mMaxSize - int rowSizeDiff = mMaxSize - mBounds.right; - - int sum = 0; - for (; y < mBounds.bottom; y++) { - index += mBounds.left; - for (int x = mBounds.left; x < mBounds.right; x++) { - if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) { - sum++; - } - index++; - } - index += rowSizeDiff; - } - - float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height()); - return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD; - } - - /** - * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it - * matches the design guidelines for a launcher icon. - * - * We first calculate the convex hull of the visible portion of the icon. - * This hull then compared with the bounding rectangle of the hull to find how closely it - * resembles a circle and a square, by comparing the ratio of the areas. Note that this is not an - * ideal solution but it gives satisfactory result without affecting the performance. - * - * This closeness is used to determine the ratio of hull area to the full icon size. - * Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR} - * - * @param outBounds optional rect to receive the fraction distance from each edge. - */ - public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds, - @Nullable Path path, @Nullable boolean[] outMaskShape) { - if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) { - if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) { - mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds); - } - if (outBounds != null) { - outBounds.set(mAdaptiveIconBounds); - } - return mAdaptiveIconScale; - } - int width = d.getIntrinsicWidth(); - int height = d.getIntrinsicHeight(); - if (width <= 0 || height <= 0) { - width = width <= 0 || width > mMaxSize ? mMaxSize : width; - height = height <= 0 || height > mMaxSize ? mMaxSize : height; - } else if (width > mMaxSize || height > mMaxSize) { - int max = Math.max(width, height); - width = mMaxSize * width / max; - height = mMaxSize * height / max; - } - - mBitmap.eraseColor(Color.TRANSPARENT); - d.setBounds(0, 0, width, height); - d.draw(mCanvas); - - ByteBuffer buffer = ByteBuffer.wrap(mPixels); - buffer.rewind(); - mBitmap.copyPixelsToBuffer(buffer); - - // Overall bounds of the visible icon. - int topY = -1; - int bottomY = -1; - int leftX = mMaxSize + 1; - int rightX = -1; - - // Create border by going through all pixels one row at a time and for each row find - // the first and the last non-transparent pixel. Set those values to mLeftBorder and - // mRightBorder and use -1 if there are no visible pixel in the row. - - // buffer position - int index = 0; - // buffer shift after every row, width of buffer = mMaxSize - int rowSizeDiff = mMaxSize - width; - // first and last position for any row. - int firstX, lastX; - - for (int y = 0; y < height; y++) { - firstX = lastX = -1; - for (int x = 0; x < width; x++) { - if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) { - if (firstX == -1) { - firstX = x; - } - lastX = x; - } - index++; - } - index += rowSizeDiff; - - mLeftBorder[y] = firstX; - mRightBorder[y] = lastX; - - // If there is at least one visible pixel, update the overall bounds. - if (firstX != -1) { - bottomY = y; - if (topY == -1) { - topY = y; - } - - leftX = Math.min(leftX, firstX); - rightX = Math.max(rightX, lastX); - } - } - - if (topY == -1 || rightX == -1) { - // No valid pixels found. Do not scale. - return 1; - } - - convertToConvexArray(mLeftBorder, 1, topY, bottomY); - convertToConvexArray(mRightBorder, -1, topY, bottomY); - - // Area of the convex hull - float area = 0; - for (int y = 0; y < height; y++) { - if (mLeftBorder[y] <= -1) { - continue; - } - area += mRightBorder[y] - mLeftBorder[y] + 1; - } - - mBounds.left = leftX; - mBounds.right = rightX; - - mBounds.top = topY; - mBounds.bottom = bottomY; - - if (outBounds != null) { - outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height, - 1 - ((float) mBounds.right) / width, - 1 - ((float) mBounds.bottom) / height); - } - if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) { - outMaskShape[0] = isShape(path); - } - // Area of the rectangle required to fit the convex hull - float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX); - return getScale(area, rectArea, width * height); - } - - /** - * Modifies {@param xCoordinates} to represent a convex border. Fills in all missing values - * (except on either ends) with appropriate values. - * @param xCoordinates map of x coordinate per y. - * @param direction 1 for left border and -1 for right border. - * @param topY the first Y position (inclusive) with a valid value. - * @param bottomY the last Y position (inclusive) with a valid value. - */ - private static void convertToConvexArray( - float[] xCoordinates, int direction, int topY, int bottomY) { - int total = xCoordinates.length; - // The tangent at each pixel. - float[] angles = new float[total - 1]; - - int first = topY; // First valid y coordinate - int last = -1; // Last valid y coordinate which didn't have a missing value - - float lastAngle = Float.MAX_VALUE; - - for (int i = topY + 1; i <= bottomY; i++) { - if (xCoordinates[i] <= -1) { - continue; - } - int start; - - if (lastAngle == Float.MAX_VALUE) { - start = first; - } else { - float currentAngle = (xCoordinates[i] - xCoordinates[last]) / (i - last); - start = last; - // If this position creates a concave angle, keep moving up until we find a - // position which creates a convex angle. - if ((currentAngle - lastAngle) * direction < 0) { - while (start > first) { - start --; - currentAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start); - if ((currentAngle - angles[start]) * direction >= 0) { - break; - } - } - } - } - - // Reset from last check - lastAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start); - // Update all the points from start. - for (int j = start; j < i; j++) { - angles[j] = lastAngle; - xCoordinates[j] = xCoordinates[start] + lastAngle * (j - start); - } - last = i; - } - } - - /** - * @return The diameter of the normalized circle that fits inside of the square (size x size). - */ - public static int getNormalizedCircleSize(int size) { - float area = size * size * MAX_CIRCLE_AREA_FACTOR; - return (int) Math.round(Math.sqrt((4 * area) / Math.PI)); - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java b/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java deleted file mode 100644 index 770272728d..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.icons; - -import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; - -import android.graphics.Bitmap; -import android.graphics.BlurMaskFilter; -import android.graphics.BlurMaskFilter.Blur; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; - -/** - * Utility class to add shadows to bitmaps. - */ -public class ShadowGenerator { - public static final float BLUR_FACTOR = 0.5f/48; - - // Percent of actual icon size - public static final float KEY_SHADOW_DISTANCE = 1f/48; - private static final int KEY_SHADOW_ALPHA = 61; - // Percent of actual icon size - private static final float HALF_DISTANCE = 0.5f; - private static final int AMBIENT_SHADOW_ALPHA = 30; - - private final int mIconSize; - - private final Paint mBlurPaint; - private final Paint mDrawPaint; - private final BlurMaskFilter mDefaultBlurMaskFilter; - - public ShadowGenerator(int iconSize) { - mIconSize = iconSize; - mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL); - } - - public synchronized void recreateIcon(Bitmap icon, Canvas out) { - recreateIcon(icon, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA, KEY_SHADOW_ALPHA, out); - } - - public synchronized void recreateIcon(Bitmap icon, BlurMaskFilter blurMaskFilter, - int ambientAlpha, int keyAlpha, Canvas out) { - int[] offset = new int[2]; - mBlurPaint.setMaskFilter(blurMaskFilter); - Bitmap shadow = icon.extractAlpha(mBlurPaint, offset); - - // Draw ambient shadow - mDrawPaint.setAlpha(ambientAlpha); - out.drawBitmap(shadow, offset[0], offset[1], mDrawPaint); - - // Draw key shadow - mDrawPaint.setAlpha(keyAlpha); - out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint); - - // Draw the icon - mDrawPaint.setAlpha(255); - out.drawBitmap(icon, 0, 0, mDrawPaint); - } - - /** - * Returns the minimum amount by which an icon with {@param bounds} should be scaled - * so that the shadows do not get clipped. - */ - public static float getScaleForBounds(RectF bounds) { - float scale = 1; - - // For top, left & right, we need same space. - float minSide = Math.min(Math.min(bounds.left, bounds.right), bounds.top); - if (minSide < BLUR_FACTOR) { - scale = (HALF_DISTANCE - BLUR_FACTOR) / (HALF_DISTANCE - minSide); - } - - float bottomSpace = BLUR_FACTOR + KEY_SHADOW_DISTANCE; - if (bounds.bottom < bottomSpace) { - scale = Math.min(scale, (HALF_DISTANCE - bottomSpace) / (HALF_DISTANCE - bounds.bottom)); - } - return scale; - } - - public static class Builder { - - public final RectF bounds = new RectF(); - public final int color; - - public int ambientShadowAlpha = AMBIENT_SHADOW_ALPHA; - - public float shadowBlur; - - public float keyShadowDistance; - public int keyShadowAlpha = KEY_SHADOW_ALPHA; - public float radius; - - public Builder(int color) { - this.color = color; - } - - public Builder setupBlurForSize(int height) { - shadowBlur = height * 1f / 24; - keyShadowDistance = height * 1f / 16; - return this; - } - - public Bitmap createPill(int width, int height) { - return createPill(width, height, height / 2f); - } - - public Bitmap createPill(int width, int height, float r) { - radius = r; - - int centerX = Math.round(width / 2f + shadowBlur); - int centerY = Math.round(radius + shadowBlur + keyShadowDistance); - int center = Math.max(centerX, centerY); - bounds.set(0, 0, width, height); - bounds.offsetTo(center - width / 2f, center - height / 2f); - - int size = center * 2; - return BitmapRenderer.createHardwareBitmap(size, size, this::drawShadow); - } - - public void drawShadow(Canvas c) { - Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - p.setColor(color); - - // Key shadow - p.setShadowLayer(shadowBlur, 0, keyShadowDistance, - setColorAlphaBound(Color.BLACK, keyShadowAlpha)); - c.drawRoundRect(bounds, radius, radius, p); - - // Ambient shadow - p.setShadowLayer(shadowBlur, 0, 0, - setColorAlphaBound(Color.BLACK, ambientShadowAlpha)); - c.drawRoundRect(bounds, radius, radius, p); - - if (Color.alpha(color) < 255) { - // Clear any content inside the pill-rect for translucent fill. - p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); - p.clearShadowLayer(); - p.setColor(Color.BLACK); - c.drawRoundRect(bounds, radius, radius, p); - - p.setXfermode(null); - p.setColor(color); - c.drawRoundRect(bounds, radius, radius, p); - } - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java deleted file mode 100644 index 4c634cbc26..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons.cache; - -import static com.android.launcher3.icons.BaseIconFactory.getFullResDefaultActivityIcon; -import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON; -import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; - -import android.content.ComponentName; -import android.content.ContentValues; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Handler; -import android.os.LocaleList; -import android.os.Looper; -import android.os.Process; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.launcher3.icons.BaseIconFactory; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.icons.BitmapRenderer; -import com.android.launcher3.icons.GraphicsUtils; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.SQLiteCacheHelper; - -import java.util.AbstractMap; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public abstract class BaseIconCache { - - private static final String TAG = "BaseIconCache"; - private static final boolean DEBUG = false; - - private static final int INITIAL_ICON_CACHE_CAPACITY = 50; - - // Empty class name is used for storing package default entry. - public static final String EMPTY_CLASS_NAME = "."; - - public static class CacheEntry { - - @NonNull - public BitmapInfo bitmap = BitmapInfo.LOW_RES_INFO; - public CharSequence title = ""; - public CharSequence contentDescription = ""; - } - - private final HashMap mDefaultIcons = new HashMap<>(); - - protected final Context mContext; - protected final PackageManager mPackageManager; - - private final Map mCache; - protected final Handler mWorkerHandler; - - protected int mIconDpi; - protected IconDB mIconDb; - protected LocaleList mLocaleList = LocaleList.getEmptyLocaleList(); - protected String mSystemState = ""; - - private final String mDbFileName; - private final BitmapFactory.Options mDecodeOptions; - private final Looper mBgLooper; - - public BaseIconCache(Context context, String dbFileName, Looper bgLooper, - int iconDpi, int iconPixelSize, boolean inMemoryCache) { - mContext = context; - mDbFileName = dbFileName; - mPackageManager = context.getPackageManager(); - mBgLooper = bgLooper; - mWorkerHandler = new Handler(mBgLooper); - - if (inMemoryCache) { - mCache = new HashMap<>(INITIAL_ICON_CACHE_CAPACITY); - } else { - // Use a dummy cache - mCache = new AbstractMap() { - @Override - public Set> entrySet() { - return Collections.emptySet(); - } - - @Override - public CacheEntry put(ComponentKey key, CacheEntry value) { - return value; - } - }; - } - - if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mDecodeOptions = new BitmapFactory.Options(); - mDecodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE; - } else { - mDecodeOptions = null; - } - - updateSystemState(); - mIconDpi = iconDpi; - mIconDb = new IconDB(context, dbFileName, iconPixelSize); - } - - /** - * Returns the persistable serial number for {@param user}. Subclass should implement proper - * caching strategy to avoid making binder call every time. - */ - protected abstract long getSerialNumberForUser(UserHandle user); - - /** - * Return true if the given app is an instant app and should be badged appropriately. - */ - protected abstract boolean isInstantApp(ApplicationInfo info); - - /** - * Opens and returns an icon factory. The factory is recycled by the caller. - */ - protected abstract BaseIconFactory getIconFactory(); - - public void updateIconParams(int iconDpi, int iconPixelSize) { - mWorkerHandler.post(() -> updateIconParamsBg(iconDpi, iconPixelSize)); - } - - private synchronized void updateIconParamsBg(int iconDpi, int iconPixelSize) { - mIconDpi = iconDpi; - mDefaultIcons.clear(); - mIconDb.clear(); - mIconDb.close(); - mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize); - mCache.clear(); - } - - private Drawable getFullResIcon(Resources resources, int iconId) { - if (resources != null && iconId != 0) { - try { - return resources.getDrawableForDensity(iconId, mIconDpi); - } catch (Resources.NotFoundException e) { } - } - return getFullResDefaultActivityIcon(mIconDpi); - } - - public Drawable getFullResIcon(String packageName, int iconId) { - try { - return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId); - } catch (PackageManager.NameNotFoundException e) { } - return getFullResDefaultActivityIcon(mIconDpi); - } - - public Drawable getFullResIcon(ActivityInfo info) { - try { - return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo), - info.getIconResource()); - } catch (PackageManager.NameNotFoundException e) { } - return getFullResDefaultActivityIcon(mIconDpi); - } - - private BitmapInfo makeDefaultIcon(UserHandle user) { - try (BaseIconFactory li = getIconFactory()) { - return li.makeDefaultIcon(user); - } - } - - /** - * Remove any records for the supplied ComponentName. - */ - public synchronized void remove(ComponentName componentName, UserHandle user) { - mCache.remove(new ComponentKey(componentName, user)); - } - - /** - * Remove any records for the supplied package name from memory. - */ - private void removeFromMemCacheLocked(String packageName, UserHandle user) { - HashSet forDeletion = new HashSet<>(); - for (ComponentKey key: mCache.keySet()) { - if (key.componentName.getPackageName().equals(packageName) - && key.user.equals(user)) { - forDeletion.add(key); - } - } - for (ComponentKey condemned: forDeletion) { - mCache.remove(condemned); - } - } - - /** - * Removes the entries related to the given package in memory and persistent DB. - */ - public synchronized void removeIconsForPkg(String packageName, UserHandle user) { - removeFromMemCacheLocked(packageName, user); - long userSerial = getSerialNumberForUser(user); - mIconDb.delete( - IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?", - new String[]{packageName + "/%", Long.toString(userSerial)}); - } - - public IconCacheUpdateHandler getUpdateHandler() { - updateSystemState(); - return new IconCacheUpdateHandler(this); - } - - /** - * Refreshes the system state definition used to check the validity of the cache. It - * incorporates all the properties that can affect the cache like the list of enabled locale - * and system-version. - */ - private void updateSystemState() { - mLocaleList = mContext.getResources().getConfiguration().getLocales(); - mSystemState = mLocaleList.toLanguageTags() + "," + Build.VERSION.SDK_INT; - } - - protected String getIconSystemState(String packageName) { - return mSystemState; - } - - /** - * Adds an entry into the DB and the in-memory cache. - * @param replaceExisting if true, it will recreate the bitmap even if it already exists in - * the memory. This is useful then the previous bitmap was created using - * old data. - */ - @VisibleForTesting - public synchronized void addIconToDBAndMemCache(T object, CachingLogic cachingLogic, - PackageInfo info, long userSerial, boolean replaceExisting) { - UserHandle user = cachingLogic.getUser(object); - ComponentName componentName = cachingLogic.getComponent(object); - - final ComponentKey key = new ComponentKey(componentName, user); - CacheEntry entry = null; - if (!replaceExisting) { - entry = mCache.get(key); - // We can't reuse the entry if the high-res icon is not present. - if (entry == null || entry.bitmap.isNullOrLowRes()) { - entry = null; - } - } - if (entry == null) { - entry = new CacheEntry(); - entry.bitmap = cachingLogic.loadIcon(mContext, object); - } - // Icon can't be loaded from cachingLogic, which implies alternative icon was loaded - // (e.g. fallback icon, default icon). So we drop here since there's no point in caching - // an empty entry. - if (entry.bitmap.isNullOrLowRes()) return; - entry.title = cachingLogic.getLabel(object); - entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); - if (cachingLogic.addToMemCache()) mCache.put(key, entry); - - ContentValues values = newContentValues(entry.bitmap, entry.title.toString(), - componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); - addIconToDB(values, componentName, info, userSerial, - cachingLogic.getLastUpdatedTime(object, info)); - } - - /** - * Updates {@param values} to contain versioning information and adds it to the DB. - * @param values {@link ContentValues} containing icon & title - */ - private void addIconToDB(ContentValues values, ComponentName key, - PackageInfo info, long userSerial, long lastUpdateTime) { - values.put(IconDB.COLUMN_COMPONENT, key.flattenToString()); - values.put(IconDB.COLUMN_USER, userSerial); - values.put(IconDB.COLUMN_LAST_UPDATED, lastUpdateTime); - values.put(IconDB.COLUMN_VERSION, info.versionCode); - mIconDb.insertOrReplace(values); - } - - public synchronized BitmapInfo getDefaultIcon(UserHandle user) { - if (!mDefaultIcons.containsKey(user)) { - mDefaultIcons.put(user, makeDefaultIcon(user)); - } - return mDefaultIcons.get(user); - } - - public boolean isDefaultIcon(BitmapInfo icon, UserHandle user) { - return getDefaultIcon(user).icon == icon.icon; - } - - /** - * Retrieves the entry from the cache. If the entry is not present, it creates a new entry. - * This method is not thread safe, it must be called from a synchronized method. - */ - protected CacheEntry cacheLocked( - @NonNull ComponentName componentName, @NonNull UserHandle user, - @NonNull Supplier infoProvider, @NonNull CachingLogic cachingLogic, - boolean usePackageIcon, boolean useLowResIcon) { - assertWorkerThread(); - ComponentKey cacheKey = new ComponentKey(componentName, user); - CacheEntry entry = mCache.get(cacheKey); - if (entry == null || (entry.bitmap.isLowRes() && !useLowResIcon)) { - entry = new CacheEntry(); - if (cachingLogic.addToMemCache()) { - mCache.put(cacheKey, entry); - } - - // Check the DB first. - T object = null; - boolean providerFetchedOnce = false; - - if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) { - object = infoProvider.get(); - providerFetchedOnce = true; - - if (object != null) { - entry.bitmap = cachingLogic.loadIcon(mContext, object); - } else { - if (usePackageIcon) { - CacheEntry packageEntry = getEntryForPackageLocked( - componentName.getPackageName(), user, false); - if (packageEntry != null) { - if (DEBUG) Log.d(TAG, "using package default icon for " + - componentName.toShortString()); - entry.bitmap = packageEntry.bitmap; - entry.title = packageEntry.title; - entry.contentDescription = packageEntry.contentDescription; - } - } - if (entry.bitmap == null) { - if (DEBUG) Log.d(TAG, "using default icon for " + - componentName.toShortString()); - entry.bitmap = getDefaultIcon(user); - } - } - } - - if (TextUtils.isEmpty(entry.title)) { - if (object == null && !providerFetchedOnce) { - object = infoProvider.get(); - providerFetchedOnce = true; - } - if (object != null) { - entry.title = cachingLogic.getLabel(object); - entry.contentDescription = mPackageManager.getUserBadgedLabel( - cachingLogic.getDescription(object, entry.title), user); - } - } - } - return entry; - } - - public synchronized void clear() { - assertWorkerThread(); - mIconDb.clear(); - } - - /** - * Adds a default package entry in the cache. This entry is not persisted and will be removed - * when the cache is flushed. - */ - protected synchronized void cachePackageInstallInfo(String packageName, UserHandle user, - Bitmap icon, CharSequence title) { - removeFromMemCacheLocked(packageName, user); - - ComponentKey cacheKey = getPackageKey(packageName, user); - CacheEntry entry = mCache.get(cacheKey); - - // For icon caching, do not go through DB. Just update the in-memory entry. - if (entry == null) { - entry = new CacheEntry(); - } - if (!TextUtils.isEmpty(title)) { - entry.title = title; - } - if (icon != null) { - BaseIconFactory li = getIconFactory(); - entry.bitmap = li.createIconBitmap(icon); - li.close(); - } - if (!TextUtils.isEmpty(title) && entry.bitmap.icon != null) { - mCache.put(cacheKey, entry); - } - } - - private static ComponentKey getPackageKey(String packageName, UserHandle user) { - ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME); - return new ComponentKey(cn, user); - } - - /** - * Gets an entry for the package, which can be used as a fallback entry for various components. - * This method is not thread safe, it must be called from a synchronized method. - */ - protected CacheEntry getEntryForPackageLocked(String packageName, UserHandle user, - boolean useLowResIcon) { - assertWorkerThread(); - ComponentKey cacheKey = getPackageKey(packageName, user); - CacheEntry entry = mCache.get(cacheKey); - - if (entry == null || (entry.bitmap.isLowRes() && !useLowResIcon)) { - entry = new CacheEntry(); - boolean entryUpdated = true; - - // Check the DB first. - if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) { - try { - int flags = Process.myUserHandle().equals(user) ? 0 : - PackageManager.GET_UNINSTALLED_PACKAGES; - PackageInfo info = mPackageManager.getPackageInfo(packageName, flags); - ApplicationInfo appInfo = info.applicationInfo; - if (appInfo == null) { - throw new NameNotFoundException("ApplicationInfo is null"); - } - - BaseIconFactory li = getIconFactory(); - // Load the full res icon for the application, but if useLowResIcon is set, then - // only keep the low resolution icon instead of the larger full-sized icon - BitmapInfo iconInfo = li.createBadgedIconBitmap( - appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion, - isInstantApp(appInfo)); - li.close(); - - entry.title = appInfo.loadLabel(mPackageManager); - entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); - entry.bitmap = BitmapInfo.of( - useLowResIcon ? LOW_RES_ICON : iconInfo.icon, iconInfo.color); - - // Add the icon in the DB here, since these do not get written during - // package updates. - ContentValues values = newContentValues( - iconInfo, entry.title.toString(), packageName, null); - addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user), - info.lastUpdateTime); - - } catch (NameNotFoundException e) { - if (DEBUG) Log.d(TAG, "Application not installed " + packageName); - entryUpdated = false; - } - } - - // Only add a filled-out entry to the cache - if (entryUpdated) { - mCache.put(cacheKey, entry); - } - } - return entry; - } - - protected boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) { - Cursor c = null; - try { - c = mIconDb.query( - lowRes ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES, - IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?", - new String[]{ - cacheKey.componentName.flattenToString(), - Long.toString(getSerialNumberForUser(cacheKey.user))}); - if (c.moveToNext()) { - // Set the alpha to be 255, so that we never have a wrong color - entry.bitmap = BitmapInfo.of(LOW_RES_ICON, setColorAlphaBound(c.getInt(0), 255)); - entry.title = c.getString(1); - if (entry.title == null) { - entry.title = ""; - entry.contentDescription = ""; - } else { - entry.contentDescription = mPackageManager.getUserBadgedLabel( - entry.title, cacheKey.user); - } - - if (!lowRes) { - byte[] data = c.getBlob(2); - try { - entry.bitmap = BitmapInfo.of( - BitmapFactory.decodeByteArray(data, 0, data.length, mDecodeOptions), - entry.bitmap.color); - } catch (Exception e) { } - } - return true; - } - } catch (SQLiteException e) { - Log.d(TAG, "Error reading icon cache", e); - } finally { - if (c != null) { - c.close(); - } - } - return false; - } - - /** - * Returns a cursor for an arbitrary query to the cache db - */ - public synchronized Cursor queryCacheDb(String[] columns, String selection, - String[] selectionArgs) { - return mIconDb.query(columns, selection, selectionArgs); - } - - /** - * Cache class to store the actual entries on disk - */ - public static final class IconDB extends SQLiteCacheHelper { - private static final int RELEASE_VERSION = 27; - - public static final String TABLE_NAME = "icons"; - public static final String COLUMN_ROWID = "rowid"; - public static final String COLUMN_COMPONENT = "componentName"; - public static final String COLUMN_USER = "profileId"; - public static final String COLUMN_LAST_UPDATED = "lastUpdated"; - public static final String COLUMN_VERSION = "version"; - public static final String COLUMN_ICON = "icon"; - public static final String COLUMN_ICON_COLOR = "icon_color"; - public static final String COLUMN_LABEL = "label"; - public static final String COLUMN_SYSTEM_STATE = "system_state"; - public static final String COLUMN_KEYWORDS = "keywords"; - - public static final String[] COLUMNS_HIGH_RES = new String[] { - IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON }; - public static final String[] COLUMNS_LOW_RES = new String[] { - IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL }; - - public IconDB(Context context, String dbFileName, int iconPixelSize) { - super(context, dbFileName, (RELEASE_VERSION << 16) + iconPixelSize, TABLE_NAME); - } - - @Override - protected void onCreateTable(SQLiteDatabase db) { - db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" - + COLUMN_COMPONENT + " TEXT NOT NULL, " - + COLUMN_USER + " INTEGER NOT NULL, " - + COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " - + COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " - + COLUMN_ICON + " BLOB, " - + COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " - + COLUMN_LABEL + " TEXT, " - + COLUMN_SYSTEM_STATE + " TEXT, " - + COLUMN_KEYWORDS + " TEXT, " - + "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " - + ");"); - } - } - - private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, - String packageName, @Nullable String keywords) { - ContentValues values = new ContentValues(); - values.put(IconDB.COLUMN_ICON, - bitmapInfo.isLowRes() ? null : GraphicsUtils.flattenBitmap(bitmapInfo.icon)); - values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color); - - values.put(IconDB.COLUMN_LABEL, label); - values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName)); - values.put(IconDB.COLUMN_KEYWORDS, keywords); - return values; - } - - private void assertWorkerThread() { - if (Looper.myLooper() != mBgLooper) { - throw new IllegalStateException("Cache accessed on wrong thread " + Looper.myLooper()); - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java deleted file mode 100644 index c12e9dcc15..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons.cache; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.os.LocaleList; -import android.os.UserHandle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.icons.BitmapInfo; - -public interface CachingLogic { - - ComponentName getComponent(T object); - - UserHandle getUser(T object); - - CharSequence getLabel(T object); - - default CharSequence getDescription(T object, CharSequence fallback) { - return fallback; - } - - @NonNull - BitmapInfo loadIcon(Context context, T object); - - /** - * Provides a option list of keywords to associate with this object - */ - @Nullable - default String getKeywords(T object, LocaleList localeList) { - return null; - } - - /** - * Returns the timestamp the entry was last updated in cache. - */ - default long getLastUpdatedTime(T object, PackageInfo info) { - return info.lastUpdateTime; - } - - /** - * Returns true the object should be added to mem cache; otherwise returns false. - */ - default boolean addToMemCache() { - return true; - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java b/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java deleted file mode 100644 index ee52934543..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons.cache; - -import android.os.Handler; - -/** - * A runnable that can be posted to a {@link Handler} which can be canceled. - */ -public abstract class HandlerRunnable implements Runnable { - - private final Handler mHandler; - private final Runnable mEndRunnable; - - private boolean mEnded = false; - private boolean mCanceled = false; - - public HandlerRunnable(Handler handler, Runnable endRunnable) { - mHandler = handler; - mEndRunnable = endRunnable; - } - - /** - * Cancels this runnable from being run, only if it has not already run. - */ - public void cancel() { - mHandler.removeCallbacks(this); - // TODO: This can actually cause onEnd to be called twice if the handler is already running - // this runnable - // NOTE: This is currently run on whichever thread the caller is run on. - mCanceled = true; - onEnd(); - } - - /** - * @return whether this runnable was canceled. - */ - protected boolean isCanceled() { - return mCanceled; - } - - /** - * To be called by the implemention of this runnable. The end callback is done on whichever - * thread the caller is calling from. - */ - public void onEnd() { - if (!mEnded) { - mEnded = true; - if (mEndRunnable != null) { - mEndRunnable.run(); - } - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java deleted file mode 100644 index 9e1ad7b7b2..0000000000 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons.cache; - -import android.content.ComponentName; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.database.sqlite.SQLiteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseBooleanArray; - -import com.android.launcher3.icons.cache.BaseIconCache.IconDB; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Stack; - -/** - * Utility class to handle updating the Icon cache - */ -public class IconCacheUpdateHandler { - - private static final String TAG = "IconCacheUpdateHandler"; - - /** - * In this mode, all invalid icons are marked as to-be-deleted in {@link #mItemsToDelete}. - * This mode is used for the first run. - */ - private static final boolean MODE_SET_INVALID_ITEMS = true; - - /** - * In this mode, any valid icon is removed from {@link #mItemsToDelete}. This is used for all - * subsequent runs, which essentially acts as set-union of all valid items. - */ - private static final boolean MODE_CLEAR_VALID_ITEMS = false; - - private static final Object ICON_UPDATE_TOKEN = new Object(); - - private final HashMap mPkgInfoMap; - private final BaseIconCache mIconCache; - - private final ArrayMap> mPackagesToIgnore = new ArrayMap<>(); - - private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray(); - private boolean mFilterMode = MODE_SET_INVALID_ITEMS; - - IconCacheUpdateHandler(BaseIconCache cache) { - mIconCache = cache; - - mPkgInfoMap = new HashMap<>(); - - // Remove all active icon update tasks. - mIconCache.mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN); - - createPackageInfoMap(); - } - - /** - * Sets a package to ignore for processing - */ - public void addPackagesToIgnore(UserHandle userHandle, String packageName) { - Set packages = mPackagesToIgnore.get(userHandle); - if (packages == null) { - packages = new HashSet<>(); - mPackagesToIgnore.put(userHandle, packages); - } - packages.add(packageName); - } - - private void createPackageInfoMap() { - PackageManager pm = mIconCache.mPackageManager; - for (PackageInfo info : - pm.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES)) { - mPkgInfoMap.put(info.packageName, info); - } - } - - /** - * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in - * the DB and are updated. - * @return The set of packages for which icons have updated. - */ - public void updateIcons(List apps, CachingLogic cachingLogic, - OnUpdateCallback onUpdateCallback) { - // Filter the list per user - HashMap> userComponentMap = new HashMap<>(); - int count = apps.size(); - for (int i = 0; i < count; i++) { - T app = apps.get(i); - UserHandle userHandle = cachingLogic.getUser(app); - HashMap componentMap = userComponentMap.get(userHandle); - if (componentMap == null) { - componentMap = new HashMap<>(); - userComponentMap.put(userHandle, componentMap); - } - componentMap.put(cachingLogic.getComponent(app), app); - } - - for (Entry> entry : userComponentMap.entrySet()) { - updateIconsPerUser(entry.getKey(), entry.getValue(), cachingLogic, onUpdateCallback); - } - - // From now on, clear every valid item from the global valid map. - mFilterMode = MODE_CLEAR_VALID_ITEMS; - } - - /** - * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in - * the DB and are updated. - * @return The set of packages for which icons have updated. - */ - @SuppressWarnings("unchecked") - private void updateIconsPerUser(UserHandle user, HashMap componentMap, - CachingLogic cachingLogic, OnUpdateCallback onUpdateCallback) { - Set ignorePackages = mPackagesToIgnore.get(user); - if (ignorePackages == null) { - ignorePackages = Collections.emptySet(); - } - long userSerial = mIconCache.getSerialNumberForUser(user); - - Stack appsToUpdate = new Stack<>(); - - try (Cursor c = mIconCache.mIconDb.query( - new String[]{IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT, - IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION, - IconDB.COLUMN_SYSTEM_STATE}, - IconDB.COLUMN_USER + " = ? ", - new String[]{Long.toString(userSerial)})) { - - final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT); - final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED); - final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION); - final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID); - final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE); - - while (c.moveToNext()) { - String cn = c.getString(indexComponent); - ComponentName component = ComponentName.unflattenFromString(cn); - PackageInfo info = mPkgInfoMap.get(component.getPackageName()); - - int rowId = c.getInt(rowIndex); - if (info == null) { - if (!ignorePackages.contains(component.getPackageName())) { - - if (mFilterMode == MODE_SET_INVALID_ITEMS) { - mIconCache.remove(component, user); - mItemsToDelete.put(rowId, true); - } - } - continue; - } - if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) { - // Application is not present - continue; - } - - long updateTime = c.getLong(indexLastUpdate); - int version = c.getInt(indexVersion); - T app = componentMap.remove(component); - if (version == info.versionCode && updateTime == info.lastUpdateTime - && TextUtils.equals(c.getString(systemStateIndex), - mIconCache.getIconSystemState(info.packageName))) { - - if (mFilterMode == MODE_CLEAR_VALID_ITEMS) { - mItemsToDelete.put(rowId, false); - } - continue; - } - - if (app == null) { - if (mFilterMode == MODE_SET_INVALID_ITEMS) { - mIconCache.remove(component, user); - mItemsToDelete.put(rowId, true); - } - } else { - appsToUpdate.add(app); - } - } - } catch (SQLiteException e) { - Log.d(TAG, "Error reading icon cache", e); - // Continue updating whatever we have read so far - } - - // Insert remaining apps. - if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) { - Stack appsToAdd = new Stack<>(); - appsToAdd.addAll(componentMap.values()); - new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic, - onUpdateCallback).scheduleNext(); - } - } - - /** - * Commits all updates as part of the update handler to disk. Not more calls should be made - * to this class after this. - */ - public void finish() { - // Commit all deletes - int deleteCount = 0; - StringBuilder queryBuilder = new StringBuilder() - .append(IconDB.COLUMN_ROWID) - .append(" IN ("); - - int count = mItemsToDelete.size(); - for (int i = 0; i < count; i++) { - if (mItemsToDelete.valueAt(i)) { - if (deleteCount > 0) { - queryBuilder.append(", "); - } - queryBuilder.append(mItemsToDelete.keyAt(i)); - deleteCount++; - } - } - queryBuilder.append(')'); - - if (deleteCount > 0) { - mIconCache.mIconDb.delete(queryBuilder.toString(), null); - } - } - - /** - * A runnable that updates invalid icons and adds missing icons in the DB for the provided - * LauncherActivityInfo list. Items are updated/added one at a time, so that the - * worker thread doesn't get blocked. - */ - private class SerializedIconUpdateTask implements Runnable { - private final long mUserSerial; - private final UserHandle mUserHandle; - private final Stack mAppsToAdd; - private final Stack mAppsToUpdate; - private final CachingLogic mCachingLogic; - private final HashSet mUpdatedPackages = new HashSet<>(); - private final OnUpdateCallback mOnUpdateCallback; - - SerializedIconUpdateTask(long userSerial, UserHandle userHandle, - Stack appsToAdd, Stack appsToUpdate, CachingLogic cachingLogic, - OnUpdateCallback onUpdateCallback) { - mUserHandle = userHandle; - mUserSerial = userSerial; - mAppsToAdd = appsToAdd; - mAppsToUpdate = appsToUpdate; - mCachingLogic = cachingLogic; - mOnUpdateCallback = onUpdateCallback; - } - - @Override - public void run() { - if (!mAppsToUpdate.isEmpty()) { - T app = mAppsToUpdate.pop(); - String pkg = mCachingLogic.getComponent(app).getPackageName(); - PackageInfo info = mPkgInfoMap.get(pkg); - - mIconCache.addIconToDBAndMemCache( - app, mCachingLogic, info, mUserSerial, true /*replace existing*/); - mUpdatedPackages.add(pkg); - - if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) { - // No more app to update. Notify callback. - mOnUpdateCallback.onPackageIconsUpdated(mUpdatedPackages, mUserHandle); - } - - // Let it run one more time. - scheduleNext(); - } else if (!mAppsToAdd.isEmpty()) { - T app = mAppsToAdd.pop(); - PackageInfo info = mPkgInfoMap.get(mCachingLogic.getComponent(app).getPackageName()); - // We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every - // app should have package info, this is not guaranteed by the api - if (info != null) { - mIconCache.addIconToDBAndMemCache(app, mCachingLogic, info, - mUserSerial, false /*replace existing*/); - } - - if (!mAppsToAdd.isEmpty()) { - scheduleNext(); - } - } - } - - public void scheduleNext() { - mIconCache.mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN, - SystemClock.uptimeMillis() + 1); - } - } - - public interface OnUpdateCallback { - - void onPackageIconsUpdated(HashSet updatedPackages, UserHandle user); - } -} diff --git a/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java b/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java deleted file mode 100644 index 34bed94270..0000000000 --- a/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.android.launcher3.util; - -/** - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.content.ComponentName; -import android.os.UserHandle; - -import java.util.Arrays; - -public class ComponentKey { - - public final ComponentName componentName; - public final UserHandle user; - - private final int mHashCode; - - public ComponentKey(ComponentName componentName, UserHandle user) { - if (componentName == null || user == null) { - throw new NullPointerException(); - } - this.componentName = componentName; - this.user = user; - mHashCode = Arrays.hashCode(new Object[] {componentName, user}); - - } - - @Override - public int hashCode() { - return mHashCode; - } - - @Override - public boolean equals(Object o) { - ComponentKey other = (ComponentKey) o; - return other.componentName.equals(componentName) && other.user.equals(user); - } - - /** - * Encodes a component key as a string of the form [flattenedComponentString#userId]. - */ - @Override - public String toString() { - return componentName.flattenToString() + "#" + user; - } -} \ No newline at end of file diff --git a/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java b/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java deleted file mode 100644 index fe864a2847..0000000000 --- a/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.util; - -import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS; - -import android.content.Context; -import android.content.ContextWrapper; -import android.database.DatabaseErrorHandler; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDatabase.CursorFactory; -import android.database.sqlite.SQLiteDatabase.OpenParams; -import android.database.sqlite.SQLiteOpenHelper; -import android.os.Build; - -/** - * Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by - * A context wrapper which creates databases without support for localized collators. - */ -public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper { - - private static final boolean ATLEAST_P = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; - - public NoLocaleSQLiteHelper(Context context, String name, int version) { - super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version); - if (ATLEAST_P) { - setOpenParams(new OpenParams.Builder().addOpenFlags(NO_LOCALIZED_COLLATORS).build()); - } - } - - private static class NoLocalContext extends ContextWrapper { - public NoLocalContext(Context base) { - super(base); - } - - @Override - public SQLiteDatabase openOrCreateDatabase( - String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) { - return super.openOrCreateDatabase( - name, mode | Context.MODE_NO_LOCALIZED_COLLATORS, factory, errorHandler); - } - } -} diff --git a/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java b/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java deleted file mode 100644 index 49de4bd1bf..0000000000 --- a/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.android.launcher3.util; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteFullException; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -/** - * An extension of {@link SQLiteOpenHelper} with utility methods for a single table cache DB. - * Any exception during write operations are ignored, and any version change causes a DB reset. - */ -public abstract class SQLiteCacheHelper { - private static final String TAG = "SQLiteCacheHelper"; - - private static final boolean IN_MEMORY_CACHE = false; - - private final String mTableName; - private final MySQLiteOpenHelper mOpenHelper; - - private boolean mIgnoreWrites; - - public SQLiteCacheHelper(Context context, String name, int version, String tableName) { - if (IN_MEMORY_CACHE) { - name = null; - } - mTableName = tableName; - mOpenHelper = new MySQLiteOpenHelper(context, name, version); - - mIgnoreWrites = false; - } - - /** - * @see SQLiteDatabase#delete(String, String, String[]) - */ - public void delete(String whereClause, String[] whereArgs) { - if (mIgnoreWrites) { - return; - } - try { - mOpenHelper.getWritableDatabase().delete(mTableName, whereClause, whereArgs); - } catch (SQLiteFullException e) { - onDiskFull(e); - } catch (SQLiteException e) { - Log.d(TAG, "Ignoring sqlite exception", e); - } - } - - /** - * @see SQLiteDatabase#insertWithOnConflict(String, String, ContentValues, int) - */ - public void insertOrReplace(ContentValues values) { - if (mIgnoreWrites) { - return; - } - try { - mOpenHelper.getWritableDatabase().insertWithOnConflict( - mTableName, null, values, SQLiteDatabase.CONFLICT_REPLACE); - } catch (SQLiteFullException e) { - onDiskFull(e); - } catch (SQLiteException e) { - Log.d(TAG, "Ignoring sqlite exception", e); - } - } - - private void onDiskFull(SQLiteFullException e) { - Log.e(TAG, "Disk full, all write operations will be ignored", e); - mIgnoreWrites = true; - } - - /** - * @see SQLiteDatabase#query(String, String[], String, String[], String, String, String) - */ - public Cursor query(String[] columns, String selection, String[] selectionArgs) { - return mOpenHelper.getReadableDatabase().query( - mTableName, columns, selection, selectionArgs, null, null, null); - } - - public void clear() { - mOpenHelper.clearDB(mOpenHelper.getWritableDatabase()); - } - - public void close() { - mOpenHelper.close(); - } - - protected abstract void onCreateTable(SQLiteDatabase db); - - /** - * A private inner class to prevent direct DB access. - */ - private class MySQLiteOpenHelper extends NoLocaleSQLiteHelper { - - public MySQLiteOpenHelper(Context context, String name, int version) { - super(context, name, version); - } - - @Override - public void onCreate(SQLiteDatabase db) { - onCreateTable(db); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion != newVersion) { - clearDB(db); - } - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion != newVersion) { - clearDB(db); - } - } - - private void clearDB(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + mTableName); - onCreate(db); - } - } -} diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java deleted file mode 100644 index 48f11fde3b..0000000000 --- a/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.icons; - -import android.content.Context; - -/** - * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class - * that are threadsafe. - */ -public class IconFactory extends BaseIconFactory { - - private static final Object sPoolSync = new Object(); - private static IconFactory sPool; - private static int sPoolId = 0; - - /** - * Return a new Message instance from the global pool. Allows us to - * avoid allocating new objects in many cases. - */ - public static IconFactory obtain(Context context) { - int poolId; - synchronized (sPoolSync) { - if (sPool != null) { - IconFactory m = sPool; - sPool = m.next; - m.next = null; - return m; - } - poolId = sPoolId; - } - - return new IconFactory(context, - context.getResources().getConfiguration().densityDpi, - context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size), - poolId); - } - - public static void clearPool() { - synchronized (sPoolSync) { - sPool = null; - sPoolId++; - } - } - - private final int mPoolId; - - private IconFactory next; - - private IconFactory(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) { - super(context, fillResIconDpi, iconBitmapSize); - mPoolId = poolId; - } - - /** - * Recycles a LauncherIcons that may be in-use. - */ - public void recycle() { - synchronized (sPoolSync) { - if (sPoolId != mPoolId) { - return; - } - // Clear any temporary state variables - clear(); - - next = sPool; - sPool = this; - } - } - - @Override - public void close() { - recycle(); - } -} diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java deleted file mode 100644 index 1337975f19..0000000000 --- a/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED; -import static android.content.Intent.ACTION_MANAGED_PROFILE_REMOVED; - -import android.annotation.TargetApi; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.os.Build; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.SparseLongArray; - -import com.android.launcher3.icons.cache.BaseIconCache; - -/** - * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class - * that are threadsafe. - */ -@TargetApi(Build.VERSION_CODES.P) -public class SimpleIconCache extends BaseIconCache { - - private static SimpleIconCache sIconCache = null; - private static final Object CACHE_LOCK = new Object(); - - private final SparseLongArray mUserSerialMap = new SparseLongArray(2); - private final UserManager mUserManager; - - public SimpleIconCache(Context context, String dbFileName, Looper bgLooper, int iconDpi, - int iconPixelSize, boolean inMemoryCache) { - super(context, dbFileName, bgLooper, iconDpi, iconPixelSize, inMemoryCache); - mUserManager = context.getSystemService(UserManager.class); - - // Listen for user cache changes. - IntentFilter filter = new IntentFilter(ACTION_MANAGED_PROFILE_ADDED); - filter.addAction(ACTION_MANAGED_PROFILE_REMOVED); - context.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - resetUserCache(); - } - }, filter, null, new Handler(bgLooper), 0); - } - - @Override - protected long getSerialNumberForUser(UserHandle user) { - synchronized (mUserSerialMap) { - int index = mUserSerialMap.indexOfKey(user.getIdentifier()); - if (index >= 0) { - return mUserSerialMap.valueAt(index); - } - long serial = mUserManager.getSerialNumberForUser(user); - mUserSerialMap.put(user.getIdentifier(), serial); - return serial; - } - } - - private void resetUserCache() { - synchronized (mUserSerialMap) { - mUserSerialMap.clear(); - } - } - - @Override - protected boolean isInstantApp(ApplicationInfo info) { - return info.isInstantApp(); - } - - @Override - protected BaseIconFactory getIconFactory() { - return IconFactory.obtain(mContext); - } - - public static SimpleIconCache getIconCache(Context context) { - synchronized (CACHE_LOCK) { - if (sIconCache != null) { - return sIconCache; - } - boolean inMemoryCache = - context.getResources().getBoolean(R.bool.simple_cache_enable_im_memory); - String dbFileName = context.getString(R.string.cache_db_name); - - HandlerThread bgThread = new HandlerThread("simple-icon-cache"); - bgThread.start(); - - sIconCache = new SimpleIconCache(context.getApplicationContext(), dbFileName, - bgThread.getLooper(), context.getResources().getConfiguration().densityDpi, - context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size), - inMemoryCache); - return sIconCache; - } - } -}