private Bitmap generateShortcutPreview( ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get(); final Canvas c = mCachedShortcutPreviewCanvas.get(); if (tempBitmap == null || tempBitmap.getWidth() != maxWidth || tempBitmap.getHeight() != maxHeight) { tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); mCachedShortcutPreviewBitmap.set(tempBitmap); } else { c.setBitmap(tempBitmap); c.drawColor(0, PorterDuff.Mode.CLEAR); c.setBitmap(null); } // Render the icon Drawable icon = mIconCache.getFullResIcon(info); int paddingTop = mContext.getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); int paddingLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); int paddingRight = mContext.getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); renderDrawableToBitmap( icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth); if (preview != null && (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight)) { throw new RuntimeException("Improperly sized bitmap passed as argument"); } else if (preview == null) { preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); } c.setBitmap(preview); // Draw a desaturated/scaled version of the icon in the background as a watermark Paint p = mCachedShortcutPreviewPaint.get(); if (p == null) { p = new Paint(); ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setSaturation(0); p.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); p.setAlpha((int) (255 * 0.06f)); mCachedShortcutPreviewPaint.set(p); } c.drawBitmap(tempBitmap, 0, 0, p); c.setBitmap(null); renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize); return preview; }
public Bitmap generateWidgetPreview( ComponentName provider, int previewImage, int iconId, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) { // Load the preview image if possible String packageName = provider.getPackageName(); if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE; Drawable drawable = null; if (previewImage != 0) { drawable = mPackageManager.getDrawable(packageName, previewImage, null); if (drawable == null) { Log.w( TAG, "Can't load widget preview drawable 0x" + Integer.toHexString(previewImage) + " for provider: " + provider); } } int previewWidth; int previewHeight; Bitmap defaultPreview = null; boolean widgetPreviewExists = (drawable != null); if (widgetPreviewExists) { previewWidth = drawable.getIntrinsicWidth(); previewHeight = drawable.getIntrinsicHeight(); } else { // Generate a preview image if we couldn't load one if (cellHSpan < 1) cellHSpan = 1; if (cellVSpan < 1) cellVSpan = 1; BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.widget_tile); final int previewDrawableWidth = previewDrawable.getIntrinsicWidth(); final int previewDrawableHeight = previewDrawable.getIntrinsicHeight(); previewWidth = previewDrawableWidth * cellHSpan; previewHeight = previewDrawableHeight * cellVSpan; defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); final Canvas c = mCachedAppWidgetPreviewCanvas.get(); c.setBitmap(defaultPreview); previewDrawable.setBounds(0, 0, previewWidth, previewHeight); previewDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); previewDrawable.draw(c); c.setBitmap(null); // Draw the icon in the top left corner int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage); int smallestSide = Math.min(previewWidth, previewHeight); float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), 1f); try { Drawable icon = null; int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2); int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); if (iconId > 0) icon = mIconCache.getFullResIcon(packageName, iconId); if (icon != null) { renderDrawableToBitmap( icon, defaultPreview, hoffset, yoffset, (int) (mAppIconSize * iconScale), (int) (mAppIconSize * iconScale)); } } catch (Resources.NotFoundException e) { } } // Scale to fit width only - let the widget preview be clipped in the // vertical dimension float scale = 1f; if (preScaledWidthOut != null) { preScaledWidthOut[0] = previewWidth; } if (previewWidth > maxPreviewWidth) { scale = maxPreviewWidth / (float) previewWidth; } if (scale != 1f) { previewWidth = (int) (scale * previewWidth); previewHeight = (int) (scale * previewHeight); } // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size if (preview == null) { preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); } // Draw the scaled preview into the final bitmap int x = (preview.getWidth() - previewWidth) / 2; if (widgetPreviewExists) { renderDrawableToBitmap(drawable, preview, x, 0, previewWidth, previewHeight); } else { final Canvas c = mCachedAppWidgetPreviewCanvas.get(); final Rect src = mCachedAppWidgetPreviewSrcRect.get(); final Rect dest = mCachedAppWidgetPreviewDestRect.get(); c.setBitmap(preview); src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight()); dest.set(x, 0, x + previewWidth, previewHeight); Paint p = mCachedAppWidgetPreviewPaint.get(); if (p == null) { p = new Paint(); p.setFilterBitmap(true); mCachedAppWidgetPreviewPaint.set(p); } c.drawBitmap(defaultPreview, src, dest, p); c.setBitmap(null); } return preview; }
public Bitmap getPreview(final Object o) { final String name = getObjectName(o); final String packageName = getObjectPackage(o); // check if the package is valid boolean packageValid = true; synchronized (sInvalidPackages) { packageValid = !sInvalidPackages.contains(packageName); } if (!packageValid) { return null; } if (packageValid) { synchronized (mLoadedPreviews) { // check if it exists in our existing cache if (mLoadedPreviews.containsKey(name) && mLoadedPreviews.get(name).get() != null) { return mLoadedPreviews.get(name).get(); } } } Bitmap unusedBitmap = null; synchronized (mUnusedBitmaps) { // not in cache; we need to load it from the db 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(); c.setBitmap(unusedBitmap); c.drawColor(0, PorterDuff.Mode.CLEAR); c.setBitmap(null); } } if (unusedBitmap == null) { unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight, Bitmap.Config.ARGB_8888); } Bitmap preview = null; if (packageValid) { preview = readFromDb(name, unusedBitmap); } if (preview != null) { synchronized (mLoadedPreviews) { mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); } return preview; } else { // it's not in the db... we need to generate it final Bitmap generatedPreview = generatePreview(o, unusedBitmap); preview = generatedPreview; if (preview != unusedBitmap) { throw new RuntimeException("generatePreview is not recycling the bitmap " + o); } 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 // of the first time widget previews are loaded new AsyncTask<Void, Void, Void>() { public Void doInBackground(Void... args) { writeToDb(o, generatedPreview); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); return preview; } }