Moving BaseIconCache to icon lib
Change-Id: I4fb56dcd6231a848d152e690edaf8885efbc995a
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index ed8d03c..e1ef954 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -3,38 +3,19 @@
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import com.android.launcher3.util.ResourceBasedOverride;
-import java.util.Locale;
-
public class IconProvider implements ResourceBasedOverride {
- protected String mSystemState;
-
public static IconProvider newInstance(Context context) {
- IconProvider provider = Overrides.getObject(
- IconProvider.class, context, R.string.icon_provider_class);
- provider.updateSystemStateString(context);
- return provider;
+ return Overrides.getObject(IconProvider.class, context, R.string.icon_provider_class);
}
public IconProvider() { }
- public void updateSystemStateString(Context context) {
- final String locale;
- if (Utilities.ATLEAST_NOUGAT) {
- locale = context.getResources().getConfiguration().getLocales().toLanguageTags();
- } else {
- locale = Locale.getDefault().toString();
- }
-
- mSystemState = locale + "," + Build.VERSION.SDK_INT;
- }
-
- public String getIconSystemState(String packageName) {
- return mSystemState;
+ public String getSystemStateForPackage(String systemState, String packageName) {
+ return systemState;
}
/**
diff --git a/src/com/android/launcher3/icons/BaseIconCache.java b/src/com/android/launcher3/icons/BaseIconCache.java
deleted file mode 100644
index 61c8ccc..0000000
--- a/src/com/android/launcher3/icons/BaseIconCache.java
+++ /dev/null
@@ -1,526 +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 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.Build.VERSION;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.IconProvider;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Provider;
-import com.android.launcher3.util.SQLiteCacheHelper;
-
-import java.util.HashMap;
-import java.util.HashSet;
-
-import androidx.annotation.NonNull;
-
-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 extends BitmapInfo {
- public CharSequence title = "";
- public CharSequence contentDescription = "";
- }
-
- private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
-
- protected final Context mContext;
- protected final PackageManager mPackageManager;
- protected final IconProvider mIconProvider;
-
- private final HashMap<ComponentKey, CacheEntry> mCache =
- new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
- protected final Handler mWorkerHandler;
-
- protected int mIconDpi;
- IconDB mIconDb;
-
- 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) {
- mContext = context;
- mDbFileName = dbFileName;
- mPackageManager = context.getPackageManager();
- mBgLooper = bgLooper;
-
- mIconProvider = IconProvider.newInstance(context);
- mWorkerHandler = new Handler(mBgLooper);
-
- 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;
- }
-
- 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);
-
-
- 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.close();
- mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize);
- mCache.clear();
- }
-
- private Drawable getFullResDefaultActivityIcon() {
- 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,
- mIconDpi);
- }
-
- private Drawable getFullResIcon(Resources resources, int iconId) {
- if (resources != null && iconId != 0) {
- try {
- return resources.getDrawableForDensity(iconId, mIconDpi);
- } catch (Resources.NotFoundException e) { }
- }
- return getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(String packageName, int iconId) {
- try {
- return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId);
- } catch (PackageManager.NameNotFoundException e) { }
- return getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(ActivityInfo info) {
- try {
- return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo),
- info.getIconResource());
- } catch (PackageManager.NameNotFoundException e) { }
- return getFullResDefaultActivityIcon();
- }
-
- protected BitmapInfo makeDefaultIcon(UserHandle user) {
- try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
- return li.createBadgedIconBitmap(
- getFullResDefaultActivityIcon(), user, VERSION.SDK_INT);
- }
- }
-
- /**
- * 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<ComponentKey> 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() {
- mIconProvider.updateSystemStateString(mContext);
- return new IconCacheUpdateHandler(this);
- }
-
- /**
- * 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.
- * package private
- */
- synchronized <T> void addIconToDBAndMemCache(T object, CachingLogic<T> 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.icon == null || entry.isLowRes()) {
- entry = null;
- }
- }
- if (entry == null) {
- entry = new CacheEntry();
- cachingLogic.loadIcon(mContext, object, entry);
- }
- entry.title = cachingLogic.getLabel(object);
- entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
- mCache.put(key, entry);
-
- ContentValues values = newContentValues(entry, entry.title.toString(),
- componentName.getPackageName());
- addIconToDB(values, componentName, info, userSerial);
- }
-
- /**
- * 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) {
- values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
- values.put(IconDB.COLUMN_USER, userSerial);
- values.put(IconDB.COLUMN_LAST_UPDATED, info.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(Bitmap icon, UserHandle user) {
- return getDefaultIcon(user).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 <T> CacheEntry cacheLocked(
- @NonNull ComponentName componentName, @NonNull UserHandle user,
- @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
- boolean usePackageIcon, boolean useLowResIcon) {
- return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon,
- useLowResIcon, true);
- }
-
- protected <T> CacheEntry cacheLocked(
- @NonNull ComponentName componentName, @NonNull UserHandle user,
- @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
- boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) {
- Preconditions.assertWorkerThread();
- ComponentKey cacheKey = new ComponentKey(componentName, user);
- CacheEntry entry = mCache.get(cacheKey);
- if (entry == null || (entry.isLowRes() && !useLowResIcon)) {
- entry = new CacheEntry();
- if (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) {
- cachingLogic.loadIcon(mContext, object, entry);
- } 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());
- packageEntry.applyTo(entry);
- entry.title = packageEntry.title;
- entry.contentDescription = packageEntry.contentDescription;
- }
- }
- if (entry.icon == null) {
- if (DEBUG) Log.d(TAG, "using default icon for " +
- componentName.toShortString());
- getDefaultIcon(user).applyTo(entry);
- }
- }
- }
-
- 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(entry.title, user);
- }
- }
- }
- return entry;
- }
-
- public synchronized void clear() {
- Preconditions.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.
- */
- public 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) {
- LauncherIcons li = LauncherIcons.obtain(mContext);
- li.createIconBitmap(icon).applyTo(entry);
- li.recycle();
- }
- if (!TextUtils.isEmpty(title) && entry.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) {
- Preconditions.assertWorkerThread();
- ComponentKey cacheKey = getPackageKey(packageName, user);
- CacheEntry entry = mCache.get(cacheKey);
-
- if (entry == null || (entry.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");
- }
-
- LauncherIcons li = LauncherIcons.obtain(mContext);
- // 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.recycle();
-
- entry.title = appInfo.loadLabel(mPackageManager);
- entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
- entry.icon = useLowResIcon ? LOW_RES_ICON : iconInfo.icon;
- entry.color = 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);
- addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user));
-
- } 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;
- }
-
- private 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.color = 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) {
- entry.icon = LOW_RES_ICON;
- } else {
- byte[] data = c.getBlob(2);
- try {
- entry.icon = BitmapFactory.decodeByteArray(data, 0, data.length,
- mDecodeOptions);
- } catch (Exception e) { }
- }
- return true;
- }
- } catch (SQLiteException e) {
- Log.d(TAG, "Error reading icon cache", e);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return false;
- }
-
- static final class IconDB extends SQLiteCacheHelper {
- private final static int RELEASE_VERSION = 25;
-
- public final static String TABLE_NAME = "icons";
- public final static String COLUMN_ROWID = "rowid";
- public final static String COLUMN_COMPONENT = "componentName";
- public final static String COLUMN_USER = "profileId";
- public final static String COLUMN_LAST_UPDATED = "lastUpdated";
- public final static String COLUMN_VERSION = "version";
- public final static String COLUMN_ICON = "icon";
- public final static String COLUMN_ICON_COLOR = "icon_color";
- public final static String COLUMN_LABEL = "label";
- public final static String COLUMN_SYSTEM_STATE = "system_state";
-
- public final static String[] COLUMNS_HIGH_RES = new String[] {
- IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON };
- public final static 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, " +
- "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
- ");");
- }
- }
-
- private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) {
- 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, mIconProvider.getIconSystemState(packageName));
-
- return values;
- }
-}
diff --git a/src/com/android/launcher3/icons/CachingLogic.java b/src/com/android/launcher3/icons/CachingLogic.java
deleted file mode 100644
index 0a3da04..0000000
--- a/src/com/android/launcher3/icons/CachingLogic.java
+++ /dev/null
@@ -1,31 +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.ComponentName;
-import android.content.Context;
-import android.os.UserHandle;
-
-public interface CachingLogic<T> {
-
- ComponentName getComponent(T object);
-
- UserHandle getUser(T object);
-
- CharSequence getLabel(T object);
-
- void loadIcon(Context context, T object, BitmapInfo target);
-}
diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java
index 7bb8832..46b5002 100644
--- a/src/com/android/launcher3/icons/ComponentWithLabel.java
+++ b/src/com/android/launcher3/icons/ComponentWithLabel.java
@@ -20,6 +20,8 @@
import android.content.pm.PackageManager;
import android.os.UserHandle;
+import com.android.launcher3.icons.cache.CachingLogic;
+
public interface ComponentWithLabel {
ComponentName getComponent();
diff --git a/src/com/android/launcher3/icons/HandlerRunnable.java b/src/com/android/launcher3/icons/HandlerRunnable.java
deleted file mode 100644
index e7132cd..0000000
--- a/src/com/android/launcher3/icons/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;
-
-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/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 7b31804..6bb9dab 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -30,6 +30,7 @@
import android.util.Log;
import com.android.launcher3.AppInfo;
+import com.android.launcher3.IconProvider;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.LauncherFiles;
@@ -40,6 +41,9 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
+import com.android.launcher3.icons.cache.BaseIconCache;
+import com.android.launcher3.icons.cache.CachingLogic;
+import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.Preconditions;
@@ -62,6 +66,7 @@
private final LauncherAppsCompat mLauncherApps;
private final UserManagerCompat mUserManager;
private final InstantAppResolver mInstantAppResolver;
+ private final IconProvider mIconProvider;
private int mPendingIconRequestCount = 0;
@@ -73,6 +78,7 @@
mLauncherApps = LauncherAppsCompat.getInstance(mContext);
mUserManager = UserManagerCompat.getInstance(mContext);
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
+ mIconProvider = IconProvider.newInstance(context);
}
@Override
@@ -85,6 +91,11 @@
return mInstantAppResolver.isInstantApp(info);
}
+ @Override
+ protected BaseIconFactory getIconFactory() {
+ return LauncherIcons.obtain(mContext);
+ }
+
/**
* Updates the entries related to the given package in memory and persistent DB.
*/
@@ -223,6 +234,11 @@
return mIconProvider.getIcon(info, mIconDpi, flattenDrawable);
}
+ @Override
+ protected String getIconSystemState(String packageName) {
+ return mIconProvider.getSystemStateForPackage(mSystemState, packageName);
+ }
+
public static abstract class IconLoadRequest extends HandlerRunnable {
IconLoadRequest(Handler handler, Runnable endRunnable) {
super(handler, endRunnable);
diff --git a/src/com/android/launcher3/icons/IconCacheUpdateHandler.java b/src/com/android/launcher3/icons/IconCacheUpdateHandler.java
deleted file mode 100644
index 0c601b9..0000000
--- a/src/com/android/launcher3/icons/IconCacheUpdateHandler.java
+++ /dev/null
@@ -1,301 +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.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.Log;
-import android.util.SparseBooleanArray;
-
-import com.android.launcher3.icons.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<String, PackageInfo> mPkgInfoMap;
- private final BaseIconCache mIconCache;
-
- private final HashMap<UserHandle, Set<String>> mPackagesToIgnore = new HashMap<>();
-
- 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();
- }
-
- public void setPackagesToIgnore(UserHandle userHandle, Set<String> packages) {
- mPackagesToIgnore.put(userHandle, packages);
- }
-
- private void createPackageInfoMap() {
- PackageManager pm = mIconCache.mPackageManager;
- for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_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 <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic,
- OnUpdateCallback onUpdateCallback) {
- // Filter the list per user
- HashMap<UserHandle, HashMap<ComponentName, T>> 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<ComponentName, T> componentMap = userComponentMap.get(userHandle);
- if (componentMap == null) {
- componentMap = new HashMap<>();
- userComponentMap.put(userHandle, componentMap);
- }
- componentMap.put(cachingLogic.getComponent(app), app);
- }
-
- for (Entry<UserHandle, HashMap<ComponentName, T>> 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.
- */
- private <T> void updateIconsPerUser(UserHandle user, HashMap<ComponentName, T> componentMap,
- CachingLogic<T> cachingLogic, OnUpdateCallback onUpdateCallback) {
- Set<String> ignorePackages = mPackagesToIgnore.get(user);
- if (ignorePackages == null) {
- ignorePackages = Collections.emptySet();
- }
- long userSerial = mIconCache.getSerialNumberForUser(user);
-
- Stack<T> 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.mIconProvider.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<T> 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<T> implements Runnable {
- private final long mUserSerial;
- private final UserHandle mUserHandle;
- private final Stack<T> mAppsToAdd;
- private final Stack<T> mAppsToUpdate;
- private final CachingLogic<T> mCachingLogic;
- private final HashSet<String> mUpdatedPackages = new HashSet<>();
- private final OnUpdateCallback mOnUpdateCallback;
-
- SerializedIconUpdateTask(long userSerial, UserHandle userHandle,
- Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> 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<String> updatedPackages, UserHandle user);
- }
-}
diff --git a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java
index 8c85b1c..7c99633 100644
--- a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java
+++ b/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java
@@ -20,6 +20,8 @@
import android.content.pm.LauncherActivityInfo;
import android.os.UserHandle;
+import com.android.launcher3.icons.cache.CachingLogic;
+
public class LauncherActivtiyCachingLogic implements CachingLogic<LauncherActivityInfo> {
private final IconCache mCache;
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 0cf1a72..153c565 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -21,16 +21,13 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Process;
-import android.os.UserHandle;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -112,29 +109,6 @@
recycle();
}
- 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 = Utilities.ATLEAST_P ||
- (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
- return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, scale);
- }
-
- public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) {
- boolean shrinkNonAdaptiveIcons = Utilities.ATLEAST_P ||
- (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
- return createScaledBitmapWithoutShadow(icon, shrinkNonAdaptiveIcons);
- }
-
// below methods should also migrate to BaseIconFactory
public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 8551e6f..2ecebb7 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -45,7 +45,7 @@
import com.android.launcher3.FolderInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
-import com.android.launcher3.icons.IconCacheUpdateHandler;
+import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;