summaryrefslogtreecommitdiffstats
path: root/iconloaderlib
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2018-11-09 11:13:10 -0800
committerSunny Goyal <sunnygoyal@google.com>2018-11-09 15:44:07 -0800
commit202fabfe10626448b7aa2d349ed3566f0d22550f (patch)
tree94c72f84d2a243bf06ec3f1d9f6f8b5fa062df63 /iconloaderlib
parent7b3c12f90e379974c195fe7f5c109c7c5d5a0e3c (diff)
downloadandroid_packages_apps_Trebuchet-202fabfe10626448b7aa2d349ed3566f0d22550f.tar.gz
android_packages_apps_Trebuchet-202fabfe10626448b7aa2d349ed3566f0d22550f.tar.bz2
android_packages_apps_Trebuchet-202fabfe10626448b7aa2d349ed3566f0d22550f.zip
Adding reusable version of IconCache and IconFactory
> Adding resource based allowing projects to control cache behavior > Fixing missing comments from ag/5470467 > Adding support for no-immemory cache Bug: 115891474 Change-Id: I691206805430cd93d3be78119bc249cefd79790a
Diffstat (limited to 'iconloaderlib')
-rw-r--r--iconloaderlib/Android.bp18
-rw-r--r--iconloaderlib/build.gradle2
-rw-r--r--iconloaderlib/res/values/config.xml27
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java32
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java46
-rw-r--r--iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java89
-rw-r--r--iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java114
7 files changed, 301 insertions, 27 deletions
diff --git a/iconloaderlib/Android.bp b/iconloaderlib/Android.bp
index 8a71f94ed..f12d16e42 100644
--- a/iconloaderlib/Android.bp
+++ b/iconloaderlib/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_library {
- name: "iconloader",
+ name: "iconloader_base",
sdk_version: "28",
min_sdk_version: "21",
static_libs: [
@@ -26,3 +26,19 @@ android_library {
"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/build.gradle b/iconloaderlib/build.gradle
index a6433ad1a..f6a820ae9 100644
--- a/iconloaderlib/build.gradle
+++ b/iconloaderlib/build.gradle
@@ -24,7 +24,7 @@ android {
sourceSets {
main {
- java.srcDirs = ['src']
+ java.srcDirs = ['src', 'src_full_lib']
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['res']
}
diff --git a/iconloaderlib/res/values/config.xml b/iconloaderlib/res/values/config.xml
new file mode 100644
index 000000000..68c2d2e3a
--- /dev/null
+++ b/iconloaderlib/res/values/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<resources>
+
+ <!-- Various configurations to control the simple cache implementation -->
+
+ <dimen name="default_icon_bitmap_size">56dp</dimen>
+ <bool name="simple_cache_enable_im_memory">false</bool>
+ <string name="cache_db_name" translatable="false">app_icons.db</string>
+
+</resources> \ No newline at end of file
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 065a14d5f..a3185741c 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -1,5 +1,10 @@
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;
@@ -18,29 +23,26 @@ import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
-
/**
* 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 final Rect mOldBounds = new Rect();
- private final Context mContext;
+ protected final Context mContext;
private final Canvas mCanvas;
private final PackageManager mPm;
private final ColorExtractor mColorExtractor;
private boolean mDisableColorExtractor;
- private int mFillResIconDpi;
- private int mIconBitmapSize;
+ protected final int mFillResIconDpi;
+ protected final int mIconBitmapSize;
private IconNormalizer mNormalizer;
private ShadowGenerator mShadowGenerator;
@@ -302,7 +304,21 @@ public class BaseIconFactory implements AutoCloseable {
}
@Override
- public void close() { }
+ 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);
+ }
/**
* An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 2fa4b6883..63820f6d0 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -15,6 +15,7 @@
*/
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;
@@ -34,7 +35,6 @@ 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;
@@ -50,9 +50,13 @@ import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.Provider;
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.Locale;
+import java.util.Map;
+import java.util.Set;
import androidx.annotation.NonNull;
@@ -76,8 +80,7 @@ public abstract class BaseIconCache {
protected final Context mContext;
protected final PackageManager mPackageManager;
- private final HashMap<ComponentKey, CacheEntry> mCache =
- new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
+ private final Map<ComponentKey, CacheEntry> mCache;
protected final Handler mWorkerHandler;
protected int mIconDpi;
@@ -89,13 +92,30 @@ public abstract class BaseIconCache {
private final Looper mBgLooper;
public BaseIconCache(Context context, String dbFileName, Looper bgLooper,
- int iconDpi, int iconPixelSize) {
+ 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<ComponentKey, CacheEntry>() {
+ @Override
+ public Set<Entry<ComponentKey, CacheEntry>> 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;
@@ -137,27 +157,20 @@ public abstract class BaseIconCache {
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();
+ return getFullResDefaultActivityIcon(mIconDpi);
}
public Drawable getFullResIcon(String packageName, int iconId) {
try {
return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId);
} catch (PackageManager.NameNotFoundException e) { }
- return getFullResDefaultActivityIcon();
+ return getFullResDefaultActivityIcon(mIconDpi);
}
public Drawable getFullResIcon(ActivityInfo info) {
@@ -165,13 +178,12 @@ public abstract class BaseIconCache {
return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo),
info.getIconResource());
} catch (PackageManager.NameNotFoundException e) { }
- return getFullResDefaultActivityIcon();
+ return getFullResDefaultActivityIcon(mIconDpi);
}
- protected BitmapInfo makeDefaultIcon(UserHandle user) {
+ private BitmapInfo makeDefaultIcon(UserHandle user) {
try (BaseIconFactory li = getIconFactory()) {
- return li.createBadgedIconBitmap(
- getFullResDefaultActivityIcon(), user, VERSION.SDK_INT);
+ return li.makeDefaultIcon(user);
}
}
diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
new file mode 100644
index 000000000..48f11fde3
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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
new file mode 100644
index 000000000..1337975f1
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+ }
+ }
+}