Fix crash when rotating all apps
Bug: 8134296
This commit is contained in:
@@ -75,7 +75,7 @@ class AsyncTaskPageData {
|
||||
}
|
||||
|
||||
AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR,
|
||||
AsyncTaskCallback postR) {
|
||||
AsyncTaskCallback postR, WidgetPreviewLoader w) {
|
||||
page = p;
|
||||
items = l;
|
||||
generatedImages = new ArrayList<Bitmap>();
|
||||
@@ -83,13 +83,14 @@ class AsyncTaskPageData {
|
||||
maxImageHeight = ch;
|
||||
doInBackgroundCallback = bgR;
|
||||
postExecuteCallback = postR;
|
||||
widgetPreviewLoader = w;
|
||||
}
|
||||
void cleanup(boolean cancelled) {
|
||||
// Clean up any references to source/generated bitmaps
|
||||
if (generatedImages != null) {
|
||||
if (cancelled) {
|
||||
for (int i = 0; i < generatedImages.size(); i++) {
|
||||
WidgetPreviewLoader.releaseBitmap(items.get(i), generatedImages.get(i));
|
||||
widgetPreviewLoader.releaseBitmap(items.get(i), generatedImages.get(i));
|
||||
}
|
||||
}
|
||||
generatedImages.clear();
|
||||
@@ -103,6 +104,7 @@ class AsyncTaskPageData {
|
||||
int maxImageHeight;
|
||||
AsyncTaskCallback doInBackgroundCallback;
|
||||
AsyncTaskCallback postExecuteCallback;
|
||||
WidgetPreviewLoader widgetPreviewLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,6 +348,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
}
|
||||
|
||||
protected void onDataReady(int width, int height) {
|
||||
if (mWidgetPreviewLoader == null) {
|
||||
mWidgetPreviewLoader = new WidgetPreviewLoader(mLauncher);
|
||||
}
|
||||
|
||||
// Note that we transpose the counts in portrait so that we get a similar layout
|
||||
boolean isLandscape = getResources().getConfiguration().orientation ==
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
@@ -1110,7 +1116,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
// do cleanup inside onSyncWidgetPageItems
|
||||
onSyncWidgetPageItems(data);
|
||||
}
|
||||
});
|
||||
}, mWidgetPreviewLoader);
|
||||
|
||||
// Ensure that the task is appropriately prioritized and runs in parallel
|
||||
AppsCustomizeAsyncTask t = new AppsCustomizeAsyncTask(page,
|
||||
@@ -1174,7 +1180,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
createItemInfo.minSpanX = minSpanXY[0];
|
||||
createItemInfo.minSpanY = minSpanXY[1];
|
||||
|
||||
widget.applyFromAppWidgetProviderInfo(info, -1, spanXY);
|
||||
widget.applyFromAppWidgetProviderInfo(info, -1, spanXY, mWidgetPreviewLoader);
|
||||
widget.setTag(createItemInfo);
|
||||
widget.setShortPressListener(this);
|
||||
} else if (rawInfo instanceof ResolveInfo) {
|
||||
@@ -1184,7 +1190,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||
createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
|
||||
info.activityInfo.name);
|
||||
widget.applyFromResolveInfo(mPackageManager, info);
|
||||
widget.applyFromResolveInfo(mPackageManager, info, mWidgetPreviewLoader);
|
||||
widget.setTag(createItemInfo);
|
||||
}
|
||||
widget.setOnClickListener(this);
|
||||
@@ -1221,13 +1227,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
maxPreviewHeight = maxSize[1];
|
||||
}
|
||||
|
||||
if (mWidgetPreviewLoader == null) {
|
||||
mWidgetPreviewLoader = new WidgetPreviewLoader(
|
||||
maxPreviewWidth, maxPreviewHeight, mLauncher, mWidgetSpacingLayout);
|
||||
}
|
||||
mWidgetPreviewLoader.setPreviewSize(
|
||||
maxPreviewWidth, maxPreviewHeight, mWidgetSpacingLayout);
|
||||
if (immediate) {
|
||||
AsyncTaskPageData data = new AsyncTaskPageData(page, items,
|
||||
maxPreviewWidth, maxPreviewHeight, null, null);
|
||||
maxPreviewWidth, maxPreviewHeight, null, null, mWidgetPreviewLoader);
|
||||
loadWidgetPreviewsInBackground(null, data);
|
||||
onSyncWidgetPageItems(data);
|
||||
} else {
|
||||
|
||||
@@ -47,6 +47,7 @@ public class PagedViewWidget extends LinearLayout {
|
||||
boolean mIsAppWidget;
|
||||
private final Rect mOriginalImagePadding = new Rect();
|
||||
private Object mInfo;
|
||||
private WidgetPreviewLoader mWidgetPreviewLoader;
|
||||
|
||||
public PagedViewWidget(Context context) {
|
||||
this(context, null);
|
||||
@@ -90,7 +91,7 @@ public class PagedViewWidget extends LinearLayout {
|
||||
if (image != null) {
|
||||
FastBitmapDrawable preview = (FastBitmapDrawable) image.getDrawable();
|
||||
if (mInfo != null && preview != null && preview.getBitmap() != null) {
|
||||
WidgetPreviewLoader.releaseBitmap(mInfo, preview.getBitmap());
|
||||
mWidgetPreviewLoader.releaseBitmap(mInfo, preview.getBitmap());
|
||||
}
|
||||
image.setImageDrawable(null);
|
||||
}
|
||||
@@ -98,7 +99,7 @@ public class PagedViewWidget extends LinearLayout {
|
||||
}
|
||||
|
||||
public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info,
|
||||
int maxWidth, int[] cellSpan) {
|
||||
int maxWidth, int[] cellSpan, WidgetPreviewLoader loader) {
|
||||
mIsAppWidget = true;
|
||||
mInfo = info;
|
||||
final ImageView image = (ImageView) findViewById(R.id.widget_preview);
|
||||
@@ -114,9 +115,11 @@ public class PagedViewWidget extends LinearLayout {
|
||||
int vSpan = Math.min(cellSpan[1], LauncherModel.getCellCountY());
|
||||
dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
|
||||
}
|
||||
mWidgetPreviewLoader = loader;
|
||||
}
|
||||
|
||||
public void applyFromResolveInfo(PackageManager pm, ResolveInfo info) {
|
||||
public void applyFromResolveInfo(
|
||||
PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
|
||||
mIsAppWidget = false;
|
||||
mInfo = info;
|
||||
CharSequence label = info.loadLabel(pm);
|
||||
@@ -128,6 +131,7 @@ public class PagedViewWidget extends LinearLayout {
|
||||
if (dims != null) {
|
||||
dims.setText(String.format(mDimensionsFormatString, 1, 1));
|
||||
}
|
||||
mWidgetPreviewLoader = loader;
|
||||
}
|
||||
|
||||
public int[] getPreviewSize() {
|
||||
|
||||
@@ -103,8 +103,8 @@ class BitmapFactoryOptionsCache extends SoftReferenceThreadLocal<BitmapFactory.O
|
||||
public class WidgetPreviewLoader {
|
||||
static final String TAG = "WidgetPreviewLoader";
|
||||
|
||||
private int mPreviewBitmapMaxWidth;
|
||||
private int mPreviewBitmapMaxHeight;
|
||||
private int mPreviewBitmapWidth;
|
||||
private int mPreviewBitmapHeight;
|
||||
private String mSize;
|
||||
private Context mContext;
|
||||
private Launcher mLauncher;
|
||||
@@ -131,27 +131,30 @@ public class WidgetPreviewLoader {
|
||||
|
||||
private WidgetPreviewCacheDb mDb;
|
||||
|
||||
private static HashMap<String, WeakReference<Bitmap>> sLoadedPreviews;
|
||||
private static ArrayList<SoftReference<Bitmap>> sUnusedBitmaps;
|
||||
private HashMap<String, WeakReference<Bitmap>> mLoadedPreviews;
|
||||
private ArrayList<SoftReference<Bitmap>> mUnusedBitmaps;
|
||||
private static HashSet<String> sInvalidPackages;
|
||||
|
||||
static {
|
||||
sLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
|
||||
sUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
|
||||
sInvalidPackages = new HashSet<String>();
|
||||
}
|
||||
|
||||
public WidgetPreviewLoader(int previewWidth, int previewHeight,
|
||||
Launcher launcher, PagedViewCellLayout widgetSpacingLayout) {
|
||||
mPreviewBitmapMaxWidth = previewWidth;
|
||||
mPreviewBitmapMaxHeight = previewHeight;
|
||||
mSize = previewWidth + "x" + previewHeight;
|
||||
public WidgetPreviewLoader(Launcher launcher) {
|
||||
mContext = mLauncher = launcher;
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mAppIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.app_icon_size);
|
||||
mIconCache = ((LauncherApplication) launcher.getApplicationContext()).getIconCache();
|
||||
mWidgetSpacingLayout = widgetSpacingLayout;
|
||||
mDb = new WidgetPreviewCacheDb(mContext);
|
||||
mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
|
||||
mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
|
||||
}
|
||||
|
||||
public void setPreviewSize(int previewWidth, int previewHeight,
|
||||
PagedViewCellLayout widgetSpacingLayout) {
|
||||
mPreviewBitmapWidth = previewWidth;
|
||||
mPreviewBitmapHeight = previewHeight;
|
||||
mSize = previewWidth + "x" + previewHeight;
|
||||
mWidgetSpacingLayout = widgetSpacingLayout;
|
||||
}
|
||||
|
||||
public Bitmap getPreview(final Object o) {
|
||||
@@ -165,20 +168,22 @@ public class WidgetPreviewLoader {
|
||||
return null;
|
||||
}
|
||||
if (packageValid) {
|
||||
synchronized(sLoadedPreviews) {
|
||||
synchronized(mLoadedPreviews) {
|
||||
// check if it exists in our existing cache
|
||||
if (sLoadedPreviews.containsKey(name) && sLoadedPreviews.get(name).get() != null) {
|
||||
return sLoadedPreviews.get(name).get();
|
||||
if (mLoadedPreviews.containsKey(name) && mLoadedPreviews.get(name).get() != null) {
|
||||
return mLoadedPreviews.get(name).get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap unusedBitmap = null;
|
||||
synchronized(sUnusedBitmaps) {
|
||||
synchronized(mUnusedBitmaps) {
|
||||
// not in cache; we need to load it from the db
|
||||
while ((unusedBitmap == null || !unusedBitmap.isMutable())
|
||||
&& sUnusedBitmaps.size() > 0) {
|
||||
unusedBitmap = sUnusedBitmaps.remove(0).get();
|
||||
while ((unusedBitmap == null || !unusedBitmap.isMutable() ||
|
||||
unusedBitmap.getWidth() != mPreviewBitmapWidth ||
|
||||
unusedBitmap.getHeight() != mPreviewBitmapHeight)
|
||||
&& mUnusedBitmaps.size() > 0) {
|
||||
unusedBitmap = mUnusedBitmaps.remove(0).get();
|
||||
}
|
||||
if (unusedBitmap != null) {
|
||||
final Canvas c = mCachedAppWidgetPreviewCanvas.get();
|
||||
@@ -189,7 +194,7 @@ public class WidgetPreviewLoader {
|
||||
}
|
||||
|
||||
if (unusedBitmap == null) {
|
||||
unusedBitmap = Bitmap.createBitmap(mPreviewBitmapMaxWidth, mPreviewBitmapMaxHeight,
|
||||
unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
@@ -200,8 +205,8 @@ public class WidgetPreviewLoader {
|
||||
}
|
||||
|
||||
if (preview != null) {
|
||||
synchronized(sLoadedPreviews) {
|
||||
sLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
|
||||
synchronized(mLoadedPreviews) {
|
||||
mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
|
||||
}
|
||||
return preview;
|
||||
} else {
|
||||
@@ -212,8 +217,8 @@ public class WidgetPreviewLoader {
|
||||
throw new RuntimeException("generatePreview is not recycling the bitmap " + o);
|
||||
}
|
||||
|
||||
synchronized(sLoadedPreviews) {
|
||||
sLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
|
||||
synchronized(mLoadedPreviews) {
|
||||
mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
|
||||
}
|
||||
|
||||
// write to db on a thread pool... this can be done lazily and improves the performance
|
||||
@@ -229,16 +234,16 @@ public class WidgetPreviewLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public static void releaseBitmap(Object o, Bitmap bitmapToFree) {
|
||||
public void releaseBitmap(Object o, Bitmap bitmapToFree) {
|
||||
// enable this code when doDecode doesn't force Bitmaps to become immutable
|
||||
String name = getObjectName(o);
|
||||
synchronized(sLoadedPreviews) {
|
||||
synchronized(sUnusedBitmaps) {
|
||||
Bitmap b = sLoadedPreviews.get(name).get();
|
||||
synchronized(mLoadedPreviews) {
|
||||
synchronized(mUnusedBitmaps) {
|
||||
Bitmap b = mLoadedPreviews.get(name).get();
|
||||
if (b == bitmapToFree) {
|
||||
sLoadedPreviews.remove(name);
|
||||
mLoadedPreviews.remove(name);
|
||||
if (bitmapToFree.isMutable()) {
|
||||
sUnusedBitmaps.add(new SoftReference<Bitmap>(b));
|
||||
mUnusedBitmaps.add(new SoftReference<Bitmap>(b));
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Bitmap passed in doesn't match up");
|
||||
@@ -378,15 +383,15 @@ public class WidgetPreviewLoader {
|
||||
|
||||
public Bitmap generatePreview(Object info, Bitmap preview) {
|
||||
if (preview != null &&
|
||||
(preview.getWidth() != mPreviewBitmapMaxWidth ||
|
||||
preview.getHeight() != mPreviewBitmapMaxHeight)) {
|
||||
(preview.getWidth() != mPreviewBitmapWidth ||
|
||||
preview.getHeight() != mPreviewBitmapHeight)) {
|
||||
throw new RuntimeException("Improperly sized bitmap passed as argument");
|
||||
}
|
||||
if (info instanceof AppWidgetProviderInfo) {
|
||||
return generateWidgetPreview((AppWidgetProviderInfo) info, preview);
|
||||
} else {
|
||||
return generateShortcutPreview(
|
||||
(ResolveInfo) info, mPreviewBitmapMaxWidth, mPreviewBitmapMaxHeight, preview);
|
||||
(ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,12 +409,12 @@ public class WidgetPreviewLoader {
|
||||
}
|
||||
|
||||
public int maxWidthForWidgetPreview(int spanX) {
|
||||
return Math.min(mPreviewBitmapMaxWidth,
|
||||
return Math.min(mPreviewBitmapWidth,
|
||||
mWidgetSpacingLayout.estimateCellWidth(spanX));
|
||||
}
|
||||
|
||||
public int maxHeightForWidgetPreview(int spanY) {
|
||||
return Math.min(mPreviewBitmapMaxHeight,
|
||||
return Math.min(mPreviewBitmapHeight,
|
||||
mWidgetSpacingLayout.estimateCellHeight(spanY));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user