Merge "Updating IconCache to maintain a persistent of icons" into ub-launcher3-burnaby
This commit is contained in:
@@ -98,14 +98,14 @@ class AllAppsList {
|
||||
user);
|
||||
|
||||
for (LauncherActivityInfoCompat info : matches) {
|
||||
add(new AppInfo(context, info, user, mIconCache, null));
|
||||
add(new AppInfo(context, info, user, mIconCache));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the apps for the given apk identified by packageName.
|
||||
*/
|
||||
public void removePackage(String packageName, UserHandleCompat user, boolean clearCache) {
|
||||
public void removePackage(String packageName, UserHandleCompat user) {
|
||||
final List<AppInfo> data = this.data;
|
||||
for (int i = data.size() - 1; i >= 0; i--) {
|
||||
AppInfo info = data.get(i);
|
||||
@@ -115,9 +115,6 @@ class AllAppsList {
|
||||
data.remove(i);
|
||||
}
|
||||
}
|
||||
if (clearCache) {
|
||||
mIconCache.remove(packageName, user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +134,6 @@ class AllAppsList {
|
||||
&& packageName.equals(component.getPackageName())) {
|
||||
if (!findActivity(matches, component)) {
|
||||
removed.add(applicationInfo);
|
||||
mIconCache.remove(component, user);
|
||||
data.remove(i);
|
||||
}
|
||||
}
|
||||
@@ -150,10 +146,9 @@ class AllAppsList {
|
||||
info.getComponentName().getPackageName(), user,
|
||||
info.getComponentName().getClassName());
|
||||
if (applicationInfo == null) {
|
||||
add(new AppInfo(context, info, user, mIconCache, null));
|
||||
add(new AppInfo(context, info, user, mIconCache));
|
||||
} else {
|
||||
mIconCache.remove(applicationInfo.componentName, user);
|
||||
mIconCache.getTitleAndIcon(applicationInfo, info, null);
|
||||
mIconCache.getTitleAndIcon(applicationInfo, info);
|
||||
modified.add(applicationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,15 @@ package com.android.launcher3;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Represents an app in AllAppsView.
|
||||
@@ -77,13 +73,13 @@ public class AppInfo extends ItemInfo {
|
||||
* Must not hold the Context.
|
||||
*/
|
||||
public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandleCompat user,
|
||||
IconCache iconCache, HashMap<Object, CharSequence> labelCache) {
|
||||
IconCache iconCache) {
|
||||
this.componentName = info.getComponentName();
|
||||
this.container = ItemInfo.NO_ID;
|
||||
|
||||
flags = initFlags(info);
|
||||
firstInstallTime = info.getFirstInstallTime();
|
||||
iconCache.getTitleAndIcon(this, info, labelCache);
|
||||
iconCache.getTitleAndIcon(this, info);
|
||||
intent = makeLaunchIntent(context, info, user);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@@ -18,15 +18,19 @@ package com.android.launcher3;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
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.SQLiteOpenHelper;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
@@ -37,15 +41,10 @@ import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
@@ -56,7 +55,6 @@ public class IconCache {
|
||||
private static final String TAG = "Launcher.IconCache";
|
||||
|
||||
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
|
||||
private static final String RESOURCE_FILE_PREFIX = "icon_";
|
||||
|
||||
// Empty class name is used for storing package default entry.
|
||||
private static final String EMPTY_CLASS_NAME = ".";
|
||||
@@ -98,7 +96,8 @@ public class IconCache {
|
||||
private final LauncherAppsCompat mLauncherApps;
|
||||
private final HashMap<CacheKey, CacheEntry> mCache =
|
||||
new HashMap<CacheKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
|
||||
private int mIconDpi;
|
||||
private final int mIconDpi;
|
||||
private final IconDB mIconDb;
|
||||
|
||||
public IconCache(Context context) {
|
||||
ActivityManager activityManager =
|
||||
@@ -109,13 +108,10 @@ public class IconCache {
|
||||
mUserManager = UserManagerCompat.getInstance(mContext);
|
||||
mLauncherApps = LauncherAppsCompat.getInstance(mContext);
|
||||
mIconDpi = activityManager.getLauncherLargeIconDensity();
|
||||
|
||||
// need to set mIconDpi before getting default icon
|
||||
UserHandleCompat myUser = UserHandleCompat.myUserHandle();
|
||||
mDefaultIcons.put(myUser, makeDefaultIcon(myUser));
|
||||
mIconDb = new IconDB(context);
|
||||
}
|
||||
|
||||
public Drawable getFullResDefaultActivityIcon() {
|
||||
private Drawable getFullResDefaultActivityIcon() {
|
||||
return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
|
||||
}
|
||||
|
||||
@@ -188,9 +184,9 @@ public class IconCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any records for the supplied package name.
|
||||
* Remove any records for the supplied package name from memory.
|
||||
*/
|
||||
public synchronized void remove(String packageName, UserHandleCompat user) {
|
||||
private void removeFromMemCacheLocked(String packageName, UserHandleCompat user) {
|
||||
HashSet<CacheKey> forDeletion = new HashSet<CacheKey>();
|
||||
for (CacheKey key: mCache.keySet()) {
|
||||
if (key.componentName.getPackageName().equals(packageName)
|
||||
@@ -203,6 +199,140 @@ public class IconCache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the entries related to the given package in memory and persistent DB.
|
||||
*/
|
||||
public synchronized void updateIconsForPkg(String packageName, UserHandleCompat user) {
|
||||
removeIconsForPkg(packageName, user);
|
||||
try {
|
||||
PackageInfo info = mPackageManager.getPackageInfo(packageName,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
long userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
for (LauncherActivityInfoCompat app : mLauncherApps.getActivityList(packageName, user)) {
|
||||
addIconToDB(app, info, userSerial);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.d(TAG, "Package not found", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the entries related to the given package in memory and persistent DB.
|
||||
*/
|
||||
public synchronized void removeIconsForPkg(String packageName, UserHandleCompat user) {
|
||||
removeFromMemCacheLocked(packageName, user);
|
||||
long userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
mIconDb.getWritableDatabase().delete(IconDB.TABLE_NAME,
|
||||
IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
|
||||
new String[] {packageName + "/%", Long.toString(userSerial)});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 HashSet<String> updateDBIcons(UserHandleCompat user, List<LauncherActivityInfoCompat> apps) {
|
||||
long userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
|
||||
for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
|
||||
pkgInfoMap.put(info.packageName, info);
|
||||
}
|
||||
|
||||
HashMap<ComponentName, LauncherActivityInfoCompat> componentMap = new HashMap<>();
|
||||
for (LauncherActivityInfoCompat app : apps) {
|
||||
componentMap.put(app.getComponentName(), app);
|
||||
}
|
||||
|
||||
Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME,
|
||||
new String[] {IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
|
||||
IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION},
|
||||
IconDB.COLUMN_USER + " = ? ",
|
||||
new String[] {Long.toString(userSerial)},
|
||||
null, null, null);
|
||||
|
||||
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);
|
||||
|
||||
HashSet<Integer> itemsToRemove = new HashSet<Integer>();
|
||||
HashSet<String> updatedPackages = new HashSet<String>();
|
||||
|
||||
while (c.moveToNext()) {
|
||||
String cn = c.getString(indexComponent);
|
||||
ComponentName component = ComponentName.unflattenFromString(cn);
|
||||
PackageInfo info = pkgInfoMap.get(component.getPackageName());
|
||||
if (info == null) {
|
||||
itemsToRemove.add(c.getInt(rowIndex));
|
||||
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);
|
||||
LauncherActivityInfoCompat app = componentMap.remove(component);
|
||||
if (version == info.versionCode && updateTime == info.lastUpdateTime) {
|
||||
continue;
|
||||
}
|
||||
if (app == null) {
|
||||
itemsToRemove.add(c.getInt(rowIndex));
|
||||
continue;
|
||||
}
|
||||
ContentValues values = updateCacheAndGetContentValues(app);
|
||||
mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
|
||||
IconDB.COLUMN_COMPONENT + " = ?",
|
||||
new String[] { cn });
|
||||
|
||||
updatedPackages.add(component.getPackageName());
|
||||
}
|
||||
c.close();
|
||||
if (!itemsToRemove.isEmpty()) {
|
||||
mIconDb.getWritableDatabase().delete(IconDB.TABLE_NAME,
|
||||
IconDB.COLUMN_ROWID + " IN ( " + TextUtils.join(", ", itemsToRemove) +" )",
|
||||
null);
|
||||
}
|
||||
|
||||
// Insert remaining apps.
|
||||
for (LauncherActivityInfoCompat app : componentMap.values()) {
|
||||
PackageInfo info = pkgInfoMap.get(app.getComponentName().getPackageName());
|
||||
if (info == null) {
|
||||
continue;
|
||||
}
|
||||
addIconToDB(app, info, userSerial);
|
||||
}
|
||||
return updatedPackages;
|
||||
}
|
||||
|
||||
private void addIconToDB(LauncherActivityInfoCompat app, PackageInfo info, long userSerial) {
|
||||
ContentValues values = updateCacheAndGetContentValues(app);
|
||||
values.put(IconDB.COLUMN_COMPONENT, app.getComponentName().flattenToString());
|
||||
values.put(IconDB.COLUMN_USER, userSerial);
|
||||
values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime);
|
||||
values.put(IconDB.COLUMN_VERSION, info.versionCode);
|
||||
mIconDb.getWritableDatabase().insertWithOnConflict(IconDB.TABLE_NAME, null, values,
|
||||
SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
private ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app) {
|
||||
CacheEntry entry = new CacheEntry();
|
||||
entry.icon = Utilities.createIconBitmap(app.getBadgedIcon(mIconDpi), mContext);
|
||||
entry.title = app.getLabel();
|
||||
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, app.getUser());
|
||||
mCache.put(new CacheKey(app.getComponentName(), app.getUser()), entry);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(IconDB.COLUMN_ICON, ItemInfo.flattenBitmap(entry.icon));
|
||||
values.put(IconDB.COLUMN_LABEL, entry.title.toString());
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Empty out the cache.
|
||||
*/
|
||||
@@ -227,10 +357,8 @@ public class IconCache {
|
||||
/**
|
||||
* Fill in "application" with the icon and label for "info."
|
||||
*/
|
||||
public synchronized void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info,
|
||||
HashMap<Object, CharSequence> labelCache) {
|
||||
CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
|
||||
info.getUser(), false);
|
||||
public synchronized void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info) {
|
||||
CacheEntry entry = cacheLocked(application.componentName, info, info.getUser(), false);
|
||||
|
||||
application.title = entry.title;
|
||||
application.iconBitmap = entry.icon;
|
||||
@@ -246,15 +374,16 @@ public class IconCache {
|
||||
}
|
||||
|
||||
LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
|
||||
CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, true);
|
||||
CacheEntry entry = cacheLocked(component, launcherActInfo, user, true);
|
||||
return entry.icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in "shortcutInfo" with the icon and label for "info."
|
||||
* Fill in {@param shortcutInfo} with the icon and label for {@param intent}. If the
|
||||
* corresponding activity is not found, it reverts to the package icon.
|
||||
*/
|
||||
public synchronized void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent,
|
||||
UserHandleCompat user, boolean usePkgIcon) {
|
||||
UserHandleCompat user) {
|
||||
ComponentName component = intent.getComponent();
|
||||
// null info means not installed, but if we have a component from the intent then
|
||||
// we should still look in the cache for restored app icons.
|
||||
@@ -263,16 +392,22 @@ public class IconCache {
|
||||
shortcutInfo.title = "";
|
||||
shortcutInfo.usingFallbackIcon = true;
|
||||
} else {
|
||||
LauncherActivityInfoCompat launcherActInfo =
|
||||
mLauncherApps.resolveActivity(intent, user);
|
||||
CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon);
|
||||
|
||||
shortcutInfo.setIcon(entry.icon);
|
||||
shortcutInfo.title = entry.title;
|
||||
shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
|
||||
LauncherActivityInfoCompat info = mLauncherApps.resolveActivity(intent, user);
|
||||
getTitleAndIcon(shortcutInfo, component, info, user, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in {@param shortcutInfo} with the icon and label for {@param info}
|
||||
*/
|
||||
public synchronized void getTitleAndIcon(
|
||||
ShortcutInfo shortcutInfo, ComponentName component, LauncherActivityInfoCompat info,
|
||||
UserHandleCompat user, boolean usePkgIcon) {
|
||||
CacheEntry entry = cacheLocked(component, info, user, usePkgIcon);
|
||||
shortcutInfo.setIcon(entry.icon);
|
||||
shortcutInfo.title = entry.title;
|
||||
shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
|
||||
}
|
||||
|
||||
public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
|
||||
if (!mDefaultIcons.containsKey(user)) {
|
||||
@@ -281,16 +416,6 @@ public class IconCache {
|
||||
return mDefaultIcons.get(user);
|
||||
}
|
||||
|
||||
public synchronized Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info,
|
||||
HashMap<Object, CharSequence> labelCache) {
|
||||
if (info == null || component == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false);
|
||||
return entry.icon;
|
||||
}
|
||||
|
||||
public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) {
|
||||
return mDefaultIcons.get(user) == icon;
|
||||
}
|
||||
@@ -300,35 +425,17 @@ public class IconCache {
|
||||
* This method is not thread safe, it must be called from a synchronized method.
|
||||
*/
|
||||
private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info,
|
||||
HashMap<Object, CharSequence> labelCache, UserHandleCompat user, boolean usePackageIcon) {
|
||||
UserHandleCompat user, boolean usePackageIcon) {
|
||||
CacheKey cacheKey = new CacheKey(componentName, user);
|
||||
CacheEntry entry = mCache.get(cacheKey);
|
||||
if (entry == null) {
|
||||
entry = new CacheEntry();
|
||||
|
||||
mCache.put(cacheKey, entry);
|
||||
|
||||
if (info != null) {
|
||||
ComponentName labelKey = info.getComponentName();
|
||||
if (labelCache != null && labelCache.containsKey(labelKey)) {
|
||||
entry.title = labelCache.get(labelKey).toString();
|
||||
} else {
|
||||
entry.title = info.getLabel().toString();
|
||||
if (labelCache != null) {
|
||||
labelCache.put(labelKey, entry.title);
|
||||
}
|
||||
}
|
||||
|
||||
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
|
||||
entry.icon = Utilities.createIconBitmap(
|
||||
info.getBadgedIcon(mIconDpi), mContext);
|
||||
} else {
|
||||
entry.title = "";
|
||||
Bitmap preloaded = getPreloadedIcon(componentName, user);
|
||||
if (preloaded != null) {
|
||||
if (DEBUG) Log.d(TAG, "using preloaded icon for " +
|
||||
componentName.toShortString());
|
||||
entry.icon = preloaded;
|
||||
// Check the DB first.
|
||||
if (!getEntryFromDB(componentName, user, entry)) {
|
||||
if (info != null) {
|
||||
entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
|
||||
} else {
|
||||
if (usePackageIcon) {
|
||||
CacheEntry packageEntry = getEntryForPackage(
|
||||
@@ -338,6 +445,7 @@ public class IconCache {
|
||||
componentName.toShortString());
|
||||
entry.icon = packageEntry.icon;
|
||||
entry.title = packageEntry.title;
|
||||
entry.contentDescription = packageEntry.contentDescription;
|
||||
}
|
||||
}
|
||||
if (entry.icon == null) {
|
||||
@@ -347,6 +455,11 @@ public class IconCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(entry.title) && info != null) {
|
||||
entry.title = info.getLabel().toString();
|
||||
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@@ -357,7 +470,7 @@ public class IconCache {
|
||||
*/
|
||||
public synchronized void cachePackageInstallInfo(String packageName, UserHandleCompat user,
|
||||
Bitmap icon, CharSequence title) {
|
||||
remove(packageName, user);
|
||||
removeFromMemCacheLocked(packageName, user);
|
||||
|
||||
CacheEntry entry = getEntryForPackage(packageName, user);
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
@@ -379,48 +492,36 @@ public class IconCache {
|
||||
if (entry == null) {
|
||||
entry = new CacheEntry();
|
||||
entry.title = "";
|
||||
entry.contentDescription = "";
|
||||
mCache.put(cacheKey, entry);
|
||||
|
||||
try {
|
||||
ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
|
||||
entry.title = info.loadLabel(mPackageManager);
|
||||
entry.icon = Utilities.createIconBitmap(info.loadIcon(mPackageManager), mContext);
|
||||
entry.title = info.loadLabel(mPackageManager);
|
||||
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
|
||||
} catch (NameNotFoundException e) {
|
||||
if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
|
||||
}
|
||||
|
||||
if (entry.icon == null) {
|
||||
entry.icon = getPreloadedIcon(cn, user);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
public synchronized HashMap<ComponentName,Bitmap> getAllIcons() {
|
||||
HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
|
||||
for (CacheKey ck : mCache.keySet()) {
|
||||
final CacheEntry e = mCache.get(ck);
|
||||
set.put(ck.componentName, e.icon);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-load an icon into the persistent cache.
|
||||
*
|
||||
* <P>Queries for a component that does not exist in the package manager
|
||||
* will be answered by the persistent cache.
|
||||
*
|
||||
* @param context application context
|
||||
* @param componentName the icon should be returned for this component
|
||||
* @param icon the icon to be persisted
|
||||
* @param dpi the native density of the icon
|
||||
*/
|
||||
public static void preloadIcon(Context context, ComponentName componentName, Bitmap icon,
|
||||
int dpi) {
|
||||
public void preloadIcon(ComponentName componentName, Bitmap icon, int dpi, String label,
|
||||
long userSerial) {
|
||||
// TODO rescale to the correct native DPI
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
packageManager.getActivityIcon(componentName);
|
||||
// component is present on the system already, do nothing
|
||||
return;
|
||||
@@ -428,100 +529,86 @@ public class IconCache {
|
||||
// pass
|
||||
}
|
||||
|
||||
final String key = componentName.flattenToString();
|
||||
FileOutputStream resourceFile = null;
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(IconDB.COLUMN_COMPONENT, componentName.flattenToString());
|
||||
values.put(IconDB.COLUMN_USER, userSerial);
|
||||
values.put(IconDB.COLUMN_ICON, ItemInfo.flattenBitmap(icon));
|
||||
values.put(IconDB.COLUMN_LABEL, label);
|
||||
mIconDb.getWritableDatabase().insertWithOnConflict(IconDB.TABLE_NAME, null, values,
|
||||
SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
private boolean getEntryFromDB(ComponentName component, UserHandleCompat user, CacheEntry entry) {
|
||||
Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME,
|
||||
new String[] {IconDB.COLUMN_ICON, IconDB.COLUMN_LABEL},
|
||||
IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
|
||||
new String[] {component.flattenToString(),
|
||||
Long.toString(mUserManager.getSerialNumberForUser(user))},
|
||||
null, null, null);
|
||||
try {
|
||||
resourceFile = context.openFileOutput(getResourceFilename(componentName),
|
||||
Context.MODE_PRIVATE);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
if (icon.compress(android.graphics.Bitmap.CompressFormat.PNG, 75, os)) {
|
||||
byte[] buffer = os.toByteArray();
|
||||
resourceFile.write(buffer, 0, buffer.length);
|
||||
} else {
|
||||
Log.w(TAG, "failed to encode cache for " + key);
|
||||
return;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, "failed to pre-load cache for " + key, e);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "failed to pre-load cache for " + key, e);
|
||||
} finally {
|
||||
if (resourceFile != null) {
|
||||
try {
|
||||
resourceFile.close();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "failed to save restored icon for: " + key, e);
|
||||
if (c.moveToNext()) {
|
||||
entry.icon = Utilities.createIconBitmap(c, 0, mContext);
|
||||
entry.title = c.getString(1);
|
||||
if (entry.title == null) {
|
||||
entry.title = "";
|
||||
entry.contentDescription = "";
|
||||
} else {
|
||||
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a pre-loaded icon from the persistent icon cache.
|
||||
*
|
||||
* @param componentName the component that should own the icon
|
||||
* @returns a bitmap if one is cached, or null.
|
||||
*/
|
||||
private Bitmap getPreloadedIcon(ComponentName componentName, UserHandleCompat user) {
|
||||
final String key = componentName.flattenToShortString();
|
||||
|
||||
// We don't keep icons for other profiles in persistent cache.
|
||||
if (!user.equals(UserHandleCompat.myUserHandle())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key);
|
||||
Bitmap icon = null;
|
||||
FileInputStream resourceFile = null;
|
||||
try {
|
||||
resourceFile = mContext.openFileInput(getResourceFilename(componentName));
|
||||
byte[] buffer = new byte[1024];
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
int bytesRead = 0;
|
||||
while(bytesRead >= 0) {
|
||||
bytes.write(buffer, 0, bytesRead);
|
||||
bytesRead = resourceFile.read(buffer, 0, buffer.length);
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "read " + bytes.size());
|
||||
icon = BitmapFactory.decodeByteArray(bytes.toByteArray(), 0, bytes.size());
|
||||
if (icon == null) {
|
||||
Log.w(TAG, "failed to decode pre-load icon for " + key);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "failed to read pre-load icon for: " + key, e);
|
||||
} finally {
|
||||
if(resourceFile != null) {
|
||||
try {
|
||||
resourceFile.close();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "failed to manage pre-load icon file: " + key, e);
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class IconDB extends SQLiteOpenHelper {
|
||||
private final static int DB_VERSION = 1;
|
||||
|
||||
private final static String TABLE_NAME = "icons";
|
||||
private final static String COLUMN_ROWID = "rowid";
|
||||
private final static String COLUMN_COMPONENT = "componentName";
|
||||
private final static String COLUMN_USER = "profileId";
|
||||
private final static String COLUMN_LAST_UPDATED = "lastUpdated";
|
||||
private final static String COLUMN_VERSION = "version";
|
||||
private final static String COLUMN_ICON = "icon";
|
||||
private final static String COLUMN_LABEL = "label";
|
||||
|
||||
public IconDB(Context context) {
|
||||
super(context, LauncherFiles.APP_ICONS_DB, null, DB_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(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_LABEL + " TEXT, " +
|
||||
"PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
|
||||
");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion != newVersion) {
|
||||
clearDB(db);
|
||||
}
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a pre-loaded icon from the persistent icon cache.
|
||||
*
|
||||
* @param componentName the component that should own the icon
|
||||
*/
|
||||
public void deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) {
|
||||
// We don't keep icons for other profiles in persistent cache.
|
||||
if (!user.equals(UserHandleCompat.myUserHandle()) || componentName == null) {
|
||||
return;
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion != newVersion) {
|
||||
clearDB(db);
|
||||
}
|
||||
}
|
||||
remove(componentName, user);
|
||||
boolean success = mContext.deleteFile(getResourceFilename(componentName));
|
||||
if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache");
|
||||
}
|
||||
|
||||
private static String getResourceFilename(ComponentName component) {
|
||||
String resourceName = component.flattenToShortString();
|
||||
String filename = resourceName.replace(File.separatorChar, '_');
|
||||
return RESOURCE_FILE_PREFIX + filename;
|
||||
private void clearDB(SQLiteDatabase db) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5033,7 +5033,7 @@ public class Launcher extends Activity
|
||||
if (activityInfo == null) {
|
||||
return null;
|
||||
}
|
||||
return new AppInfo(this, activityInfo, myUser, mIconCache, null);
|
||||
return new AppInfo(this, activityInfo, myUser, mIconCache);
|
||||
}
|
||||
|
||||
public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
|
||||
|
||||
@@ -144,6 +144,7 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
private final HashSet<String> mExistingKeys;
|
||||
private final ArrayList<Key> mKeys;
|
||||
private final ItemTypeMatcher[] mItemTypeMatchers;
|
||||
private final long mUserSerial;
|
||||
|
||||
private IconCache mIconCache;
|
||||
private BackupManager mBackupManager;
|
||||
@@ -161,6 +162,9 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
mKeys = new ArrayList<Key>();
|
||||
restoreSuccessful = true;
|
||||
mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
|
||||
|
||||
UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
|
||||
mUserSerial = userManager.getSerialNumberForUser(UserHandleCompat.myUserHandle());
|
||||
}
|
||||
|
||||
private void dataChanged() {
|
||||
@@ -297,6 +301,12 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
if (!restoreSuccessful) {
|
||||
return;
|
||||
}
|
||||
if (!initializeIconCache()) {
|
||||
// During restore we do not need an initialized instance of IconCache. We can create
|
||||
// a temporary icon cache here, as the process will be rebooted after restore
|
||||
// is complete.
|
||||
mIconCache = new IconCache(mContext);
|
||||
}
|
||||
|
||||
int dataSize = data.size();
|
||||
if (mBuffer.length < dataSize) {
|
||||
@@ -601,7 +611,8 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
Log.w(TAG, "failed to unpack icon for " + key.name);
|
||||
}
|
||||
if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name);
|
||||
IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi);
|
||||
mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi,
|
||||
"" /* label */, mUserSerial);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -693,8 +704,8 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
if (icon == null) {
|
||||
Log.w(TAG, "failed to unpack widget icon for " + key.name);
|
||||
} else {
|
||||
IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider),
|
||||
icon, widget.icon.dpi);
|
||||
mIconCache.preloadIcon(ComponentName.unflattenFromString(widget.provider),
|
||||
icon, widget.icon.dpi, widget.label, mUserSerial);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1145,9 +1156,11 @@ public class LauncherBackupHelper implements BackupHelper {
|
||||
|
||||
final LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
|
||||
if (appState == null) {
|
||||
Throwable stackTrace = new Throwable();
|
||||
stackTrace.fillInStackTrace();
|
||||
Log.w(TAG, "Failed to get app state during backup/restore", stackTrace);
|
||||
if (DEBUG) {
|
||||
Throwable stackTrace = new Throwable();
|
||||
stackTrace.fillInStackTrace();
|
||||
Log.w(TAG, "Failed to get app state during backup/restore", stackTrace);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
mIconCache = appState.getIconCache();
|
||||
|
||||
@@ -25,6 +25,7 @@ public class LauncherFiles {
|
||||
WallpaperCropActivity.class.getName();
|
||||
public static final String WALLPAPER_IMAGES_DB = "saved_wallpaper_images.db";
|
||||
public static final String WIDGET_PREVIEWS_DB = "widgetpreviews.db";
|
||||
public static final String APP_ICONS_DB = "app_icons.db";
|
||||
|
||||
public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
|
||||
DEFAULT_WALLPAPER_THUMBNAIL,
|
||||
@@ -36,5 +37,6 @@ public class LauncherFiles {
|
||||
STATS_LOG,
|
||||
WALLPAPER_CROP_PREFERENCES_KEY + XML,
|
||||
WALLPAPER_IMAGES_DB,
|
||||
WIDGET_PREVIEWS_DB));
|
||||
WIDGET_PREVIEWS_DB,
|
||||
APP_ICONS_DB));
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
@@ -163,9 +162,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
// sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
|
||||
static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
|
||||
|
||||
// sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database
|
||||
static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();
|
||||
|
||||
// sBgWorkspaceScreens is the ordered set of workspace screens.
|
||||
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
|
||||
|
||||
@@ -1131,7 +1127,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
break;
|
||||
}
|
||||
sBgItemsIdMap.remove(item.id);
|
||||
sBgDbIconCache.remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1204,7 +1199,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (sBgLock) {
|
||||
sBgItemsIdMap.remove(info.id);
|
||||
sBgFolders.remove(info.id);
|
||||
sBgDbIconCache.remove(info);
|
||||
sBgWorkspaceItems.remove(info);
|
||||
}
|
||||
|
||||
@@ -1214,7 +1208,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (sBgLock) {
|
||||
for (ItemInfo childInfo : info.contents) {
|
||||
sBgItemsIdMap.remove(childInfo.id);
|
||||
sBgDbIconCache.remove(childInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1481,12 +1474,9 @@ public class LauncherModel extends BroadcastReceiver
|
||||
private boolean mLoadAndBindStepFinished;
|
||||
private int mFlags;
|
||||
|
||||
private HashMap<Object, CharSequence> mLabelCache;
|
||||
|
||||
LoaderTask(Context context, boolean isLaunching, int flags) {
|
||||
mContext = context;
|
||||
mIsLaunching = isLaunching;
|
||||
mLabelCache = new HashMap<Object, CharSequence>();
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
@@ -1635,15 +1625,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// Update the saved icons if necessary
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
|
||||
synchronized (sBgLock) {
|
||||
for (Object key : sBgDbIconCache.keySet()) {
|
||||
updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));
|
||||
}
|
||||
sBgDbIconCache.clear();
|
||||
}
|
||||
|
||||
if (LauncherAppState.isDisableAllApps()) {
|
||||
// Ensure that all the applications that are in the system are
|
||||
// represented on the home screen.
|
||||
@@ -1819,7 +1800,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
sBgAppWidgets.clear();
|
||||
sBgFolders.clear();
|
||||
sBgItemsIdMap.clear();
|
||||
sBgDbIconCache.clear();
|
||||
sBgWorkspaceScreens.clear();
|
||||
}
|
||||
}
|
||||
@@ -2068,8 +2048,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
if (itemReplaced) {
|
||||
if (user.equals(UserHandleCompat.myUserHandle())) {
|
||||
info = getShortcutInfo(manager, intent, user, context, null,
|
||||
iconIndex, titleIndex, mLabelCache, false);
|
||||
info = getAppShortcutInfo(manager, intent, user, context, null,
|
||||
iconIndex, titleIndex, false);
|
||||
} else {
|
||||
// Don't replace items for other profiles.
|
||||
itemsToRemove.add(id);
|
||||
@@ -2089,8 +2069,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
} else if (itemType ==
|
||||
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
||||
info = getShortcutInfo(manager, intent, user, context, c,
|
||||
iconIndex, titleIndex, mLabelCache, allowMissingTarget);
|
||||
info = getAppShortcutInfo(manager, intent, user, context, c,
|
||||
iconIndex, titleIndex, allowMissingTarget);
|
||||
} else {
|
||||
info = getShortcutInfo(c, context, iconTypeIndex,
|
||||
iconPackageIndex, iconResourceIndex, iconIndex,
|
||||
@@ -2145,10 +2125,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
break;
|
||||
}
|
||||
sBgItemsIdMap.put(info.id, info);
|
||||
|
||||
// now that we've loaded everthing re-save it with the
|
||||
// icon in case it disappears somehow.
|
||||
queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected null ShortcutInfo");
|
||||
}
|
||||
@@ -2842,20 +2818,48 @@ public class LauncherModel extends BroadcastReceiver
|
||||
if (apps == null || apps.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Sort the applications by name
|
||||
final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
|
||||
Collections.sort(apps,
|
||||
new LauncherModel.ShortcutNameComparator(mLabelCache));
|
||||
if (DEBUG_LOADERS) {
|
||||
Log.d(TAG, "sort took "
|
||||
+ (SystemClock.uptimeMillis()-sortTime) + "ms");
|
||||
|
||||
// Update icon cache
|
||||
HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);
|
||||
|
||||
// If any package icon has changed (app was updated while launcher was dead),
|
||||
// update the corresponding shortcuts.
|
||||
if (!updatedPackages.isEmpty()) {
|
||||
final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();
|
||||
synchronized (sBgLock) {
|
||||
for (ItemInfo info : sBgItemsIdMap.values()) {
|
||||
if (info instanceof ShortcutInfo && user.equals(info.user)
|
||||
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
||||
ShortcutInfo si = (ShortcutInfo) info;
|
||||
ComponentName cn = si.getTargetComponent();
|
||||
if (cn != null && updatedPackages.contains(cn.getPackageName())) {
|
||||
si.updateIcon(mIconCache);
|
||||
updates.add(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
final UserHandleCompat userFinal = user;
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
Callbacks cb = getCallback();
|
||||
if (cb != null) {
|
||||
cb.bindShortcutsChanged(
|
||||
updates, new ArrayList<ShortcutInfo>(), userFinal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create the ApplicationInfos
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
LauncherActivityInfoCompat app = apps.get(i);
|
||||
// This builds the icon bitmaps.
|
||||
mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
|
||||
mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));
|
||||
}
|
||||
|
||||
if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {
|
||||
@@ -2987,7 +2991,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
case OP_ADD:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
|
||||
mIconCache.remove(packages[i], mUser);
|
||||
mIconCache.updateIconsForPkg(packages[i], mUser);
|
||||
mBgAllAppsList.addPackage(context, packages[i], mUser);
|
||||
}
|
||||
|
||||
@@ -3019,6 +3023,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
case OP_UPDATE:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
|
||||
mIconCache.updateIconsForPkg(packages[i], mUser);
|
||||
mBgAllAppsList.updatePackage(context, packages[i], mUser);
|
||||
WidgetPreviewLoader.removePackageFromDb(
|
||||
mApp.getWidgetPreviewCacheDb(), packages[i]);
|
||||
@@ -3038,12 +3043,15 @@ public class LauncherModel extends BroadcastReceiver
|
||||
shortcutSet.removeAll(Arrays.asList(mPackages));
|
||||
prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();
|
||||
}
|
||||
// Fall through
|
||||
case OP_UNAVAILABLE:
|
||||
boolean clearCache = mOp == OP_REMOVE;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
|
||||
mBgAllAppsList.removePackage(packages[i], mUser, clearCache);
|
||||
mIconCache.removeIconsForPkg(packages[i], mUser);
|
||||
}
|
||||
// Fall through
|
||||
case OP_UNAVAILABLE:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
|
||||
mBgAllAppsList.removePackage(packages[i], mUser);
|
||||
WidgetPreviewLoader.removePackageFromDb(
|
||||
mApp.getWidgetPreviewCacheDb(), packages[i]);
|
||||
}
|
||||
@@ -3136,7 +3144,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
AppInfo appInfo = addedOrUpdatedApps.get(cn);
|
||||
|
||||
if (si.isPromise()) {
|
||||
mIconCache.deletePreloadedIcon(cn, mUser);
|
||||
if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
|
||||
// Auto install icon
|
||||
PackageManager pm = context.getPackageManager();
|
||||
@@ -3381,7 +3388,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
int promiseType) {
|
||||
final ShortcutInfo info = new ShortcutInfo();
|
||||
info.user = UserHandleCompat.myUserHandle();
|
||||
mIconCache.getTitleAndIcon(info, intent, info.user, true);
|
||||
mIconCache.getTitleAndIcon(info, intent, info.user);
|
||||
|
||||
if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
|
||||
String title = (cursor != null) ? cursor.getString(titleIndex) : null;
|
||||
@@ -3423,23 +3430,14 @@ public class LauncherModel extends BroadcastReceiver
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called from the code that adds shortcuts from the intent receiver. This
|
||||
* doesn't have a Cursor, but
|
||||
*/
|
||||
public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
|
||||
UserHandleCompat user, Context context) {
|
||||
return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an ShortcutInfo object for a shortcut that is an application.
|
||||
*
|
||||
* If c is not null, then it will be used to fill in missing data like the title and icon.
|
||||
*/
|
||||
public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
|
||||
public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,
|
||||
UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
|
||||
HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {
|
||||
boolean allowMissingTarget) {
|
||||
if (user == null) {
|
||||
Log.d(TAG, "Null user found in getShortcutInfo");
|
||||
return null;
|
||||
@@ -3461,48 +3459,22 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
|
||||
final ShortcutInfo info = new ShortcutInfo();
|
||||
|
||||
// the resource -- This may implicitly give us back the fallback icon,
|
||||
// but don't worry about that. All we're doing with usingFallbackIcon is
|
||||
// to avoid saving lots of copies of that in the database, and most apps
|
||||
// have icons anyway.
|
||||
Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);
|
||||
|
||||
// the db
|
||||
if (icon == null) {
|
||||
if (c != null) {
|
||||
icon = getIconFromCursor(c, iconIndex, context);
|
||||
}
|
||||
}
|
||||
// the fallback icon
|
||||
if (icon == null) {
|
||||
icon = mIconCache.getDefaultIcon(user);
|
||||
info.usingFallbackIcon = true;
|
||||
}
|
||||
info.setIcon(icon);
|
||||
|
||||
// From the cache.
|
||||
if (labelCache != null) {
|
||||
info.title = labelCache.get(componentName);
|
||||
mIconCache.getTitleAndIcon(info, componentName, lai, user, false);
|
||||
if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {
|
||||
Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);
|
||||
info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);
|
||||
}
|
||||
|
||||
// from the resource
|
||||
if (info.title == null && lai != null) {
|
||||
info.title = lai.getLabel();
|
||||
if (labelCache != null) {
|
||||
labelCache.put(componentName, info.title);
|
||||
}
|
||||
}
|
||||
// from the db
|
||||
if (info.title == null) {
|
||||
if (c != null) {
|
||||
info.title = c.getString(titleIndex);
|
||||
}
|
||||
if (TextUtils.isEmpty(info.title) && c != null) {
|
||||
info.title = c.getString(titleIndex);
|
||||
}
|
||||
|
||||
// fall back to the class name of the activity
|
||||
if (info.title == null) {
|
||||
info.title = componentName.getClassName();
|
||||
}
|
||||
|
||||
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
info.user = user;
|
||||
info.contentDescription = mUserManager.getBadgedLabelForUser(
|
||||
@@ -3581,7 +3553,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);
|
||||
// the db
|
||||
if (icon == null) {
|
||||
icon = getIconFromCursor(c, iconIndex, context);
|
||||
icon = Utilities.createIconBitmap(c, iconIndex, context);
|
||||
}
|
||||
// the fallback icon
|
||||
if (icon == null) {
|
||||
@@ -3590,7 +3562,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
break;
|
||||
case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
|
||||
icon = getIconFromCursor(c, iconIndex, context);
|
||||
icon = Utilities.createIconBitmap(c, iconIndex, context);
|
||||
if (icon == null) {
|
||||
icon = mIconCache.getDefaultIcon(info.user);
|
||||
info.customIcon = false;
|
||||
@@ -3609,22 +3581,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return info;
|
||||
}
|
||||
|
||||
Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {
|
||||
@SuppressWarnings("all") // suppress dead code warning
|
||||
final boolean debug = false;
|
||||
if (debug) {
|
||||
Log.d(TAG, "getIconFromCursor app="
|
||||
+ c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));
|
||||
}
|
||||
byte[] data = c.getBlob(iconIndex);
|
||||
try {
|
||||
return Utilities.createIconBitmap(
|
||||
BitmapFactory.decodeByteArray(data, 0, data.length), context);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
|
||||
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
|
||||
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
|
||||
@@ -3673,45 +3629,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return info;
|
||||
}
|
||||
|
||||
boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,
|
||||
int iconIndex) {
|
||||
// If apps can't be on SD, don't even bother.
|
||||
if (!mAppsCanBeOnRemoveableStorage) {
|
||||
return false;
|
||||
}
|
||||
// If this icon doesn't have a custom icon, check to see
|
||||
// what's stored in the DB, and if it doesn't match what
|
||||
// we're going to show, store what we are going to show back
|
||||
// into the DB. We do this so when we're loading, if the
|
||||
// package manager can't find an icon (for example because
|
||||
// the app is on SD) then we can use that instead.
|
||||
if (!info.customIcon && !info.usingFallbackIcon) {
|
||||
cache.put(info, c.getBlob(iconIndex));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {
|
||||
boolean needSave = false;
|
||||
try {
|
||||
if (data != null) {
|
||||
Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||
Bitmap loaded = info.getIcon(mIconCache);
|
||||
needSave = !saved.sameAs(loaded);
|
||||
} else {
|
||||
needSave = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
needSave = true;
|
||||
}
|
||||
if (needSave) {
|
||||
Log.d(TAG, "going to save icon bitmap for info=" + info);
|
||||
// This is slower than is ideal, but this only happens once
|
||||
// or when the app is updated with a new icon.
|
||||
updateItemInDatabase(context, info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an existing FolderInfo object if we have encountered this ID previously,
|
||||
* or make a new one.
|
||||
@@ -3761,38 +3678,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
|
||||
}
|
||||
}
|
||||
public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {
|
||||
private Collator mCollator;
|
||||
private HashMap<Object, CharSequence> mLabelCache;
|
||||
ShortcutNameComparator(PackageManager pm) {
|
||||
mLabelCache = new HashMap<Object, CharSequence>();
|
||||
mCollator = Collator.getInstance();
|
||||
}
|
||||
ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {
|
||||
mLabelCache = labelCache;
|
||||
mCollator = Collator.getInstance();
|
||||
}
|
||||
public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {
|
||||
String labelA, labelB;
|
||||
ComponentName keyA = a.getComponentName();
|
||||
ComponentName keyB = b.getComponentName();
|
||||
if (mLabelCache.containsKey(keyA)) {
|
||||
labelA = mLabelCache.get(keyA).toString();
|
||||
} else {
|
||||
labelA = a.getLabel().toString().trim();
|
||||
|
||||
mLabelCache.put(keyA, labelA);
|
||||
}
|
||||
if (mLabelCache.containsKey(keyB)) {
|
||||
labelB = mLabelCache.get(keyB).toString();
|
||||
} else {
|
||||
labelB = b.getLabel().toString().trim();
|
||||
|
||||
mLabelCache.put(keyB, labelB);
|
||||
}
|
||||
return mCollator.compare(labelA, labelB);
|
||||
}
|
||||
};
|
||||
public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
|
||||
private final AppWidgetManagerCompat mManager;
|
||||
private final PackageManager mPackageManager;
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -190,8 +191,9 @@ public class ShortcutInfo extends ItemInfo {
|
||||
}
|
||||
|
||||
public void updateIcon(IconCache iconCache) {
|
||||
mIcon = iconCache.getIcon(promisedIntent != null ? promisedIntent : intent, user);
|
||||
usingFallbackIcon = iconCache.isDefaultIcon(mIcon, user);
|
||||
if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
|
||||
iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,9 +215,9 @@ public class ShortcutInfo extends ItemInfo {
|
||||
if (!usingFallbackIcon) {
|
||||
writeBitmap(values, mIcon);
|
||||
}
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
|
||||
LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
|
||||
if (iconResource != null) {
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
|
||||
LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
|
||||
iconResource.packageName);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
|
||||
|
||||
@@ -31,7 +31,9 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
@@ -112,6 +114,15 @@ public final class Utilities {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
||||
}
|
||||
|
||||
static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
|
||||
byte[] data = c.getBlob(iconIndex);
|
||||
try {
|
||||
return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitmap suitable for the all apps view. If the package or the resource do not
|
||||
* exist, it returns null.
|
||||
|
||||
@@ -4772,7 +4772,7 @@ public class Workspace extends SmoothPagedView
|
||||
if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
|
||||
// For auto install apps update the icon as well as label.
|
||||
mIconCache.getTitleAndIcon(shortcutInfo,
|
||||
shortcutInfo.promisedIntent, user, true);
|
||||
shortcutInfo.promisedIntent, user);
|
||||
} else {
|
||||
// Only update the icon for restored apps.
|
||||
shortcutInfo.updateIcon(mIconCache);
|
||||
|
||||
Reference in New Issue
Block a user