WidgetPreviewLoader.java revision 091440a9cb9d4f42406631004aa484cbb79214ca
1325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.appwidget.AppWidgetProviderInfo; 405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ComponentName; 505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ContentValues; 605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.Context; 78ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurkaimport android.content.SharedPreferences; 805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.ResolveInfo; 905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.res.Resources; 1005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.Cursor; 111f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport android.database.sqlite.SQLiteCantOpenDatabaseException; 1205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteDatabase; 136e27f642ae66dd1920b25b527fced7268943d11aMichael Jurkaimport android.database.sqlite.SQLiteDiskIOException; 1405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteOpenHelper; 155f05913f71da68a6c406f905ec6979586e3ba27aWinson Chungimport android.database.sqlite.SQLiteReadOnlyDatabaseException; 1605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap; 1705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap.Config; 1805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.BitmapFactory; 1905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Canvas; 2005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrix; 2105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrixColorFilter; 2205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Paint; 2305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.PorterDuff; 2405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Rect; 254cad7538c9615303d291f5b52e960aaf0985828fSunny Goyalimport android.graphics.RectF; 2605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.BitmapDrawable; 2705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.Drawable; 2805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.os.AsyncTask; 295f05913f71da68a6c406f905ec6979586e3ba27aWinson Chungimport android.os.Build; 3005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.util.Log; 314cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 32ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalimport com.android.launcher3.compat.AppWidgetManagerCompat; 33091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 34ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 3505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.ByteArrayOutputStream; 3605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.File; 371f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.io.IOException; 3805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.SoftReference; 3905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.WeakReference; 4005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.ArrayList; 411f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.util.Arrays; 4205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 4305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 441f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.util.List; 4565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.Callable; 4665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.ExecutionException; 4705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 48ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalpublic class WidgetPreviewLoader { 4905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final String TAG = "WidgetPreviewLoader"; 51ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version"; 52ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 53ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; 54091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static final HashSet<String> sInvalidPackages = new HashSet<String>(); 55ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 56b745afbdd75157c73d581b345118cdaff99e912dWinson Chung private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>(); 57b745afbdd75157c73d581b345118cdaff99e912dWinson Chung private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>(); 58ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 59ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final int mAppIconSize; 604cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal private final int mCellWidth; 614cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal private final Context mContext; 63ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final IconCache mIconCache; 64ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final AppWidgetManagerCompat mManager; 6505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 663f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapWidth; 673f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapHeight; 6805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mSize; 6905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mCachedSelectQuery; 71d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka private CacheDb mDb; 7205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); 7465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos 75fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren public WidgetPreviewLoader(Context context) { 765f8afe6280eae34620067696173e71943e1a30a3Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 775f8afe6280eae34620067696173e71943e1a30a3Winson Chung DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); 785f8afe6280eae34620067696173e71943e1a30a3Winson Chung 79fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 805f8afe6280eae34620067696173e71943e1a30a3Winson Chung mAppIconSize = grid.iconSizePx; 814cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal mCellWidth = grid.cellWidthPx; 824cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 83d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mIconCache = app.getIconCache(); 84ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal mManager = AppWidgetManagerCompat.getInstance(context); 85d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mDb = app.getWidgetPreviewCacheDb(); 868ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 878ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka SharedPreferences sp = context.getSharedPreferences( 888ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); 898ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka final String lastVersionName = sp.getString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, null); 908ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka final String versionName = android.os.Build.VERSION.INCREMENTAL; 910250945759f7ac58aab912448d62dc108b1770c5Adam Cohen final boolean isLollipopOrGreater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 928ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka if (!versionName.equals(lastVersionName)) { 935f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung try { 945f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung // clear all the previews whenever the system version changes, to ensure that 955f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung // previews are up-to-date for any apps that might have been updated with the system 965f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung clearDb(); 975f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung } catch (SQLiteReadOnlyDatabaseException e) { 980250945759f7ac58aab912448d62dc108b1770c5Adam Cohen if (isLollipopOrGreater) { 995f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung // Workaround for Bug. 18554839, if we fail to clear the db due to the read-only 1005f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung // issue, then ignore this error and leave the old previews 1015f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung } else { 1025f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung throw e; 1035f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung } 1045f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung } finally { 1055f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung SharedPreferences.Editor editor = sp.edit(); 1065f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung editor.putString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, versionName); 1075f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung editor.commit(); 1085f05913f71da68a6c406f905ec6979586e3ba27aWinson Chung } 1098ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 1103f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 111ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 1126e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka public void recreateDb() { 1136e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka LauncherAppState app = LauncherAppState.getInstance(); 1146e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka app.recreateWidgetPreviewDb(); 1156e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka mDb = app.getWidgetPreviewCacheDb(); 1166e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 1173f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka 1184cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal public void setPreviewSize(int previewWidth, int previewHeight) { 1193f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapWidth = previewWidth; 1203f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapHeight = previewHeight; 1213f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mSize = previewWidth + "x" + previewHeight; 12205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap getPreview(final Object o) { 125eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String name = getObjectName(o); 126eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String packageName = getObjectPackage(o); 12705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // check if the package is valid 12805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 1295d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos boolean packageValid = !sInvalidPackages.contains(packageName); 1305d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (!packageValid) { 1315d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos return null; 1325d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos } 13305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 1345d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos synchronized(mLoadedPreviews) { 1355d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos // check if it exists in our existing cache 1365d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (mLoadedPreviews.containsKey(name)) { 1375d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos WeakReference<Bitmap> bitmapReference = mLoadedPreviews.get(name); 1385d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap bitmap = bitmapReference.get(); 1395d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (bitmap != null) { 1405d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos return bitmap; 14105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 14205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 14305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 14405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 14505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap unusedBitmap = null; 1463f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mUnusedBitmaps) { 14705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // not in cache; we need to load it from the db 1485d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos while (unusedBitmap == null && mUnusedBitmaps.size() > 0) { 1495d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap candidate = mUnusedBitmaps.remove(0).get(); 1505d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (candidate != null && candidate.isMutable() && 1515d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos candidate.getWidth() == mPreviewBitmapWidth && 1525d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos candidate.getHeight() == mPreviewBitmapHeight) { 1535d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos unusedBitmap = candidate; 1545d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos } 15505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 15805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (unusedBitmap == null) { 1593f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight, 16005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap.Config.ARGB_8888); 16105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 1625d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap preview = readFromDb(name, unusedBitmap); 16305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 16405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null) { 1653f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 1663f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 16705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 16905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 17005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // it's not in the db... we need to generate it 17105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Bitmap generatedPreview = generatePreview(o, unusedBitmap); 17205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = generatedPreview; 17305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != unusedBitmap) { 17405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("generatePreview is not recycling the bitmap " + o); 17505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 17605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1773f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 1783f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 17905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 18005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 18105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // write to db on a thread pool... this can be done lazily and improves the performance 18205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // of the first time widget previews are loaded 18305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 18405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 18505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka writeToDb(o, generatedPreview); 18605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 18705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 18805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 18905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 19005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 19105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 19205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 19305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 194ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka public void recycleBitmap(Object o, Bitmap bitmapToRecycle) { 19505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 1965140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mLoadedPreviews) { 1975140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka if (mLoadedPreviews.containsKey(name)) { 1983f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka Bitmap b = mLoadedPreviews.get(name).get(); 199ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (b == bitmapToRecycle) { 2003f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.remove(name); 201ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (bitmapToRecycle.isMutable()) { 2025140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mUnusedBitmaps) { 2035140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka mUnusedBitmaps.add(new SoftReference<Bitmap>(b)); 2045140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka } 20505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 20605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 20705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Bitmap passed in doesn't match up"); 20805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 20905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 213d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka static class CacheDb extends SQLiteOpenHelper { 214e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka final static int DB_VERSION = 2; 21505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String TABLE_NAME = "shortcut_and_widget_previews"; 21605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_NAME = "name"; 21705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_SIZE = "size"; 21805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 21905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Context mContext; 22005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 221d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 2224fbbb3e3e0e135bc5b304bc63637bbc8b54fb5d8Helena Josol super(context, new File(context.getCacheDir(), 2234fbbb3e3e0e135bc5b304bc63637bbc8b54fb5d8Helena Josol LauncherFiles.WIDGET_PREVIEWS_DB).getPath(), null, DB_VERSION); 22405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Store the context for later use 22505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mContext = context; 22605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 22705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 22805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 22905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onCreate(SQLiteDatabase database) { 23032b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 23105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_NAME + " TEXT NOT NULL, " + 23205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 23305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_PREVIEW_BITMAP + " BLOB NOT NULL, " + 23405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka "PRIMARY KEY (" + COLUMN_NAME + ", " + COLUMN_SIZE + ") " + 23532b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 23605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 23805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 23905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 240e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka if (oldVersion != newVersion) { 241e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka // Delete all the records; they'll be repopulated as this is a cache 242e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka db.execSQL("DELETE FROM " + TABLE_NAME); 243e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka } 24405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 24505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 24605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 24705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String WIDGET_PREFIX = "Widget:"; 24805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String SHORTCUT_PREFIX = "Shortcut:"; 24905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 25005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static String getObjectName(Object o) { 25105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // should cache the string builder 25205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka StringBuilder sb = new StringBuilder(); 25305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String output; 25405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 25505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(WIDGET_PREFIX); 256ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal sb.append(((AppWidgetProviderInfo) o).toString()); 25705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 25805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 25905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 26005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(SHORTCUT_PREFIX); 26105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 26205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(new ComponentName(info.activityInfo.packageName, 26305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka info.activityInfo.name).flattenToString()); 26405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 26505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 26605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 26705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return output; 26805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 26905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 27005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String getObjectPackage(Object o) { 27105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 27205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return ((AppWidgetProviderInfo) o).provider.getPackageName(); 27305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 27405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 27505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return info.activityInfo.packageName; 27605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 279091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk void writeToDb(Object o, Bitmap preview) { 28005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 28105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getWritableDatabase(); 28205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 28305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 284d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_NAME, name); 28505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ByteArrayOutputStream stream = new ByteArrayOutputStream(); 28605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview.compress(Bitmap.CompressFormat.PNG, 100, stream); 287d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_PREVIEW_BITMAP, stream.toByteArray()); 288d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_SIZE, mSize); 2896e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 2906e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.insert(CacheDb.TABLE_NAME, null, values); 2916e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 2926e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka recreateDb(); 2931f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 2941f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 2951f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 2966e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 29705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 29805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2998ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka private void clearDb() { 3008ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka SQLiteDatabase db = mDb.getWritableDatabase(); 3018ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka // Delete everything 3026e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3036e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, null, null); 3046e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3051f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3061f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3071f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3086e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 3098ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 3108ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 311eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) { 31205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 31305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.add(packageName); 31405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 31605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 317d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 3186e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3196e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, 3206e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " LIKE ? OR " + 3216e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query 3226e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { 3236e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka WIDGET_PREFIX + packageName + "/%", 3246e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka SHORTCUT_PREFIX + packageName + "/%" 3256e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } // args to SELECT query 3266e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka ); 3276e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3281f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3291f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3301f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3316e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 33205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 33305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.remove(packageName); 33405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 33605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 33805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 340ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static void removeItemFromDb(final CacheDb cacheDb, final String objectName) { 341eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka new AsyncTask<Void, Void, Void>() { 342eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public Void doInBackground(Void ... args) { 343eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 3446e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3456e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, 3466e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " = ? ", // SELECT query 3476e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { objectName }); // args to SELECT query 3486e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3491f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3501f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3511f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3526e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 353eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 354eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 355eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 356eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 357eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 35805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap readFromDb(String name, Bitmap b) { 35905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (mCachedSelectQuery == null) { 360d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mCachedSelectQuery = CacheDb.COLUMN_NAME + " = ? AND " + 361d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka CacheDb.COLUMN_SIZE + " = ?"; 36205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 36305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getReadableDatabase(); 3646e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka Cursor result; 3656e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3666e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka result = db.query(CacheDb.TABLE_NAME, 3676e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return 3686e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka mCachedSelectQuery, // select query 3696e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { name, mSize }, // args to select query 3706e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 3716e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 3726e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 3736e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null); 3746e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3756e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka recreateDb(); 3766e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka return null; 3771f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3781f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3791f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3806e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 38105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (result.getCount() > 0) { 38205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.moveToFirst(); 38305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka byte[] blob = result.getBlob(0); 38405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 3854cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final BitmapFactory.Options opts = new BitmapFactory.Options(); 38605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inBitmap = b; 38705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inSampleSize = 1; 388eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka try { 389eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 390eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } catch (IllegalArgumentException e) { 391eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka removeItemFromDb(mDb, name); 392eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 393eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 39405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 39505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 39605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 39705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 400ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private Bitmap generatePreview(Object info, Bitmap preview) { 40105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null && 4023f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (preview.getWidth() != mPreviewBitmapWidth || 4033f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka preview.getHeight() != mPreviewBitmapHeight)) { 40405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Improperly sized bitmap passed as argument"); 40505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4065940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen if (info instanceof LauncherAppWidgetProviderInfo) { 4075940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen return generateWidgetPreview((LauncherAppWidgetProviderInfo) info, preview); 40805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 40905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateShortcutPreview( 4103f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview); 41105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4145940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, Bitmap preview) { 4155940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen int maxWidth = maxWidthForWidgetPreview(info.spanX); 4164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal return generateWidgetPreview(info, maxWidth, preview, null); 41705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 41905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public int maxWidthForWidgetPreview(int spanX) { 4204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal return Math.min(mPreviewBitmapWidth, spanX * mCellWidth); 42105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 42205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4234cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, 4244cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) { 42505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 42605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 42705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 42805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 429ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal if (info.previewImage != 0) { 430ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal drawable = mManager.loadPreview(info); 431fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (drawable != null) { 432fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mutateOnMainThread(drawable); 433fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } else { 43405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 435ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal Integer.toHexString(info.previewImage) + " for provider: " + info.provider); 43605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 43705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 43805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4394cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final boolean widgetPreviewExists = (drawable != null); 4404cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final int spanX = info.spanX < 1 ? 1 : info.spanX; 4414cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final int spanY = info.spanY < 1 ? 1 : info.spanY; 4424cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 44305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 44405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 4454cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Bitmap tileBitmap = null; 4464cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 44705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 44805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 44905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 45005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 45105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 4524cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable( 4534cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal R.drawable.widget_tile)).getBitmap(); 4544cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewWidth = tileBitmap.getWidth() * spanX; 4554cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewHeight = tileBitmap.getHeight() * spanY; 45605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 45905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 46005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 46105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 46205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 46305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 46405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 46505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka scale = maxPreviewWidth / (float) previewWidth; 46605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 46705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 46805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 46905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 47005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 47105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 47205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 4734cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 47405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 47505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 4764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else { 4784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4794cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4804cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawColor(0, PorterDuff.Mode.CLEAR); 48105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 48205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 48305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 48405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int x = (preview.getWidth() - previewWidth) / 2; 48505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 4864cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.setBounds(x, 0, x + previewWidth, previewHeight); 4874cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.draw(c); 48805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4894cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Paint p = new Paint(); 4904cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal p.setFilterBitmap(true); 4914cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4924cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // draw the spanX x spanY tiles 4934cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight()); 4944cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4954cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileW = scale * tileBitmap.getWidth(); 4964cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileH = scale * tileBitmap.getHeight(); 4974cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final RectF dst = new RectF(0, 0, tileW, tileH); 4984cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4994cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tx = x; 5004cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int i = 0; i < spanX; i++, tx += tileW) { 5014cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float ty = 0; 5024cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int j = 0; j < spanY; j++, ty += tileH) { 5034cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal dst.offsetTo(tx, ty); 5044cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawBitmap(tileBitmap, src, dst, p); 5054cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 50605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 5074cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 5084cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the icon in the top left corner 5094cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 5104cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); 5114cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int smallestSide = Math.min(previewWidth, previewHeight); 5124cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), scale); 5134cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 5144cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal try { 5154cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mManager.loadIcon(info, mIconCache)); 5164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (icon != null) { 5174cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int hoffset = (int) ((tileW - mAppIconSize * iconScale) / 2) + x; 5184cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int yoffset = (int) ((tileH - mAppIconSize * iconScale) / 2); 5194cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(hoffset, yoffset, 5204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal hoffset + (int) (mAppIconSize * iconScale), 5214cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal yoffset + (int) (mAppIconSize * iconScale)); 5224cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 5234cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 5244cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } catch (Resources.NotFoundException e) { } 52505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 52605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 527ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal return mManager.getBadgeBitmap(info, preview); 52805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 52905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 53005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 53105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { 5324cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 5334cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (preview == null) { 5344cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 5354cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 5364cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) { 5374cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal throw new RuntimeException("Improperly sized bitmap passed as argument"); 53805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 5394cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 5404cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 54105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 54205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 54305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5444cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo)); 5454cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setFilterBitmap(true); 54605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5474cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw a desaturated/scaled version of the icon in the background as a watermark 5484cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal ColorMatrix colorMatrix = new ColorMatrix(); 5494cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal colorMatrix.setSaturation(0); 5504cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 5514cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha((int) (255 * 0.06f)); 5524cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 5534cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Resources res = mContext.getResources(); 5544cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 5554cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 5564cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 55705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 5584cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(paddingLeft, paddingTop, 5594cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth); 5604cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 56105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the final icon at top left corner. 5634cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 5644cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha(255); 5654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(null); 5664cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(0, 0, mAppIconSize, mAppIconSize); 5674cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 56805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 56905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 57005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 57105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 57205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 57365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private Drawable mutateOnMainThread(final Drawable drawable) { 57465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos try { 57565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return mMainThreadExecutor.submit(new Callable<Drawable>() { 57665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos @Override 57765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos public Drawable call() throws Exception { 57865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return drawable.mutate(); 57965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 58065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos }).get(); 58165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (InterruptedException e) { 58265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Thread.currentThread().interrupt(); 58365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 58465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (ExecutionException e) { 58565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 58665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 58765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 5881f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos 5891f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos private static final int MAX_OPEN_FILES = 1024; 5901f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos private static final int SAMPLE_RATE = 23; 5911f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos /** 5921f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos * Dumps all files that are open in this process without allocating a file descriptor. 5931f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos */ 594091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static void dumpOpenFiles() { 5951f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 5961f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):"); 5971f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_APK = "apk"; 5981f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_JAR = "jar"; 5991f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_PIPE = "pipe"; 6001f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_SOCKET = "socket"; 6011f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_DB = "db"; 6021f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_ANON_INODE = "anon_inode"; 6031f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_DEV = "dev"; 6041f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_NON_FS = "non-fs"; 6051f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_OTHER = "other"; 6061f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos List<String> types = Arrays.asList(TYPE_APK, TYPE_JAR, TYPE_PIPE, TYPE_SOCKET, TYPE_DB, 6071f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos TYPE_ANON_INODE, TYPE_DEV, TYPE_NON_FS, TYPE_OTHER); 6081f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int[] count = new int[types.size()]; 6091f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int[] duplicates = new int[types.size()]; 6101f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos HashSet<String> files = new HashSet<String>(); 6111f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int total = 0; 6121f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos for (int i = 0; i < MAX_OPEN_FILES; i++) { 6131f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // This is a gigantic hack but unfortunately the only way to resolve an fd 6141f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // to a file name. Note that we have to loop over all possible fds because 6151f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // reading the directory would require allocating a new fd. The kernel is 6161f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // currently implemented such that no fd is larger then the current rlimit, 6171f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // which is why it's safe to loop over them in such a way. 6181f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos String fd = "/proc/self/fd/" + i; 6191f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 6201f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // getCanonicalPath() uses readlink behind the scene which doesn't require 6211f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // a file descriptor. 6221f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos String resolved = new File(fd).getCanonicalPath(); 6231f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int type = types.indexOf(TYPE_OTHER); 6241f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (resolved.startsWith("/dev/")) { 6251f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_DEV); 6261f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".apk")) { 6271f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_APK); 6281f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".jar")) { 6291f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_JAR); 6301f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/pipe:")) { 6311f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_PIPE); 6321f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/socket:")) { 6331f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_SOCKET); 6341f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/anon_inode:")) { 6351f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_ANON_INODE); 6361f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".db") || resolved.contains("/databases/")) { 6371f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_DB); 6381f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.startsWith("/proc/") && resolved.contains("/fd/")) { 6391f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Those are the files that don't point anywhere on the file system. 6401f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // getCanonicalPath() wrongly interprets these as relative symlinks and 6411f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // resolves them within /proc/<pid>/fd/. 6421f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_NON_FS); 6431f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6441f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos count[type]++; 6451f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos total++; 6461f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (files.contains(resolved)) { 6471f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos duplicates[type]++; 6481f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6491f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos files.add(resolved); 6501f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (total % SAMPLE_RATE == 0) { 6511f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, " fd " + i + ": " + resolved 6521f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos + " (" + types.get(type) + ")"); 6531f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6541f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (IOException e) { 6551f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Ignoring exceptions for non-existing file descriptors. 6561f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6571f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6581f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos for (int i = 0; i < types.size(); i++) { 6591f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, String.format("Open %10s files: %4d total, %4d duplicates", 6601f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos types.get(i), count[i], duplicates[i])); 6611f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6621f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (Throwable t) { 6631f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Catch everything. This is called from an exception handler that we shouldn't upset. 6641f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.e(TAG, "Unable to log open files.", t); 6651f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6661f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 66705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 668