diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2018-11-09 11:13:10 -0800 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2018-11-09 15:44:07 -0800 |
commit | 202fabfe10626448b7aa2d349ed3566f0d22550f (patch) | |
tree | 94c72f84d2a243bf06ec3f1d9f6f8b5fa062df63 /iconloaderlib | |
parent | 7b3c12f90e379974c195fe7f5c109c7c5d5a0e3c (diff) | |
download | android_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')
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; + } + } +} |