Updating widget preview generation to not embed any badge.

Instead drawing badge in the view directly.

This will allow us to reuse the same preview when we do not want to draw
badges. This also simplified badging of shortcut config activities.

Change-Id: I9c07c33bf9c2b8ef81a00026b1d42587868c906f
This commit is contained in:
Sunny Goyal 2017-01-14 13:40:15 -08:00
parent 278359539c
commit a2441e88ff
8 changed files with 105 additions and 72 deletions

View File

@ -15,7 +15,6 @@
-->
<com.android.launcher3.widget.WidgetCell
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
@ -25,7 +24,7 @@
android:gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/widget_preview_label_vertical_padding"
android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
@ -36,7 +35,7 @@
<!-- The name of the widget. -->
<TextView
android:id="@+id/widget_name"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"

View File

@ -83,7 +83,7 @@
<!-- Widget tray -->
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">16dp</dimen>
<dimen name="widget_section_height">56dp</dimen>
<dimen name="widget_section_icon_size">40dp</dimen>

View File

@ -70,7 +70,6 @@ public class WidgetPreviewLoader {
private final UserManagerCompat mUserManager;
private final AppWidgetManagerCompat mWidgetManager;
private final CacheDb mDb;
private final int mProfileBadgeMargin;
private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
@Thunk final Handler mWorkerHandler;
@ -82,8 +81,6 @@ public class WidgetPreviewLoader {
mUserManager = UserManagerCompat.getInstance(context);
mDb = new CacheDb(context);
mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
mProfileBadgeMargin = context.getResources()
.getDimensionPixelSize(R.dimen.profile_badge_margin);
}
/**
@ -107,7 +104,7 @@ public class WidgetPreviewLoader {
* sizes (landscape vs portrait).
*/
private static class CacheDb extends SQLiteCacheHelper {
private static final int DB_VERSION = 4;
private static final int DB_VERSION = 5;
private static final String TABLE_NAME = "shortcut_and_widget_previews";
private static final String COLUMN_COMPONENT = "componentName";
@ -344,7 +341,7 @@ public class WidgetPreviewLoader {
preScaledWidthOut[0] = previewWidth;
}
if (previewWidth > maxPreviewWidth) {
scale = (maxPreviewWidth - 2 * mProfileBadgeMargin) / (float) (previewWidth);
scale = maxPreviewWidth / (float) (previewWidth);
}
if (scale != 1f) {
previewWidth = (int) (scale * previewWidth);
@ -357,6 +354,12 @@ public class WidgetPreviewLoader {
preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
c.setBitmap(preview);
} else {
// We use the preview bitmap height to determine where the badge will be drawn in the
// UI. If its larger than what we need, resize the preview bitmap so that there are
// no transparent pixels between the preview and the badge.
if (preview.getHeight() > previewHeight) {
preview.reconfigure(preview.getWidth(), previewHeight, preview.getConfig());
}
// Reusing bitmap. Clear it.
c.setBitmap(preview);
c.drawColor(0, PorterDuff.Mode.CLEAR);
@ -409,9 +412,7 @@ public class WidgetPreviewLoader {
}
c.setBitmap(null);
}
int imageWidth = Math.min(preview.getWidth(), previewWidth + mProfileBadgeMargin);
int imageHeight = Math.min(preview.getHeight(), previewHeight + mProfileBadgeMargin);
return mWidgetManager.getBadgeBitmap(info, preview, imageWidth, imageHeight);
return preview;
}
private Bitmap generateShortcutPreview(
@ -538,6 +539,7 @@ public class WidgetPreviewLoader {
private final int mPreviewHeight;
private final int mPreviewWidth;
private final WidgetCell mCaller;
private final BaseActivity mActivity;
@Thunk long[] mVersions;
@Thunk Bitmap mBitmapToRecycle;
@ -548,6 +550,7 @@ public class WidgetPreviewLoader {
mPreviewHeight = previewHeight;
mPreviewWidth = previewWidth;
mCaller = caller;
mActivity = BaseActivity.fromContext(mCaller.getContext());
if (DEBUG) {
Log.d(TAG, String.format("%s, %s, %d, %d",
mKey, mInfo, mPreviewHeight, mPreviewWidth));
@ -591,10 +594,8 @@ public class WidgetPreviewLoader {
// which would gets re-written next time.
mVersions = getPackageVersion(mKey.componentName.getPackageName());
BaseActivity launcher = BaseActivity.fromContext(mCaller.getContext());
// it's not in the db... we need to generate it
preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight);
preview = generatePreview(mActivity, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight);
}
return preview;
}

View File

@ -71,9 +71,6 @@ public abstract class AppWidgetManagerCompat {
public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
Activity activity, AppWidgetHost host, int requestCode);
public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
int imageWidth, int imageHeight);
public abstract LauncherAppWidgetProviderInfo findProvider(
ComponentName provider, UserHandle user);

View File

@ -23,17 +23,9 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.view.View;
import android.widget.Toast;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@ -81,47 +73,6 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
}
}
@Override
public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
int imageWidth, int imageHeight) {
if (info.isCustomWidget || info.getProfile().equals(android.os.Process.myUserHandle())) {
return bitmap;
}
// Add a user badge in the bottom right of the image.
final Resources res = mContext.getResources();
final int badgeMinTop = res.getDimensionPixelSize(R.dimen.profile_badge_minimum_top);
// choose min between badge size defined for widget tray versus width, height of the image.
// Width, height of the image can be smaller than widget tray badge size when being dropped
// to the workspace.
final int badgeSize = Math.min(res.getDimensionPixelSize(R.dimen.profile_badge_size),
Math.min(imageWidth, imageHeight - badgeMinTop));
final Rect badgeLocation = new Rect(0, 0, badgeSize, badgeSize);
final int top = Math.max(imageHeight - badgeSize, badgeMinTop);
if (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
badgeLocation.offset(0, top);
} else {
badgeLocation.offset(bitmap.getWidth() - badgeSize, top);
}
Drawable drawable = mPm.getUserBadgedDrawableForDensity(
new BitmapDrawable(res, bitmap), info.getProfile(), badgeLocation, 0);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
bitmap.eraseColor(Color.TRANSPARENT);
Canvas c = new Canvas(bitmap);
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
drawable.draw(c);
c.setBitmap(null);
return bitmap;
}
@Override
public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandle user) {
for (AppWidgetProviderInfo info : mAppWidgetManager

View File

@ -17,7 +17,16 @@
package com.android.launcher3.graphics;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
import android.support.annotation.UiThread;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
@ -25,6 +34,8 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
import java.util.HashMap;
/**
* Factory for creating new drawables.
*/
@ -43,6 +54,9 @@ public class DrawableFactory {
}
}
protected final UserHandle mMyUser = Process.myUserHandle();
protected final HashMap<UserHandle, Bitmap> mUserBadges = new HashMap<>();
/**
* Returns a FastBitmapDrawable with the icon.
*/
@ -55,4 +69,47 @@ public class DrawableFactory {
public AllAppsBackgroundDrawable getAllAppsBackground(Context context) {
return new AllAppsBackgroundDrawable(context);
}
/**
* Returns a drawable that can be used as a badge for the user or null.
*/
@UiThread
public Drawable getBadgeForUser(UserHandle user, Context context) {
if (mMyUser.equals(user)) {
return null;
}
Bitmap badgeBitmap = getUserBadge(user, context);
FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
d.setFilterBitmap(true);
d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
return d;
}
protected synchronized Bitmap getUserBadge(UserHandle user, Context context) {
Bitmap badgeBitmap = mUserBadges.get(user);
if (badgeBitmap != null) {
return badgeBitmap;
}
final Resources res = context.getApplicationContext().getResources();
int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size);
badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
Drawable drawable = context.getPackageManager().getUserBadgedDrawableForDensity(
new BitmapDrawable(res, badgeBitmap), user, new Rect(0, 0, badgeSize, badgeSize),
0);
if (drawable instanceof BitmapDrawable) {
badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
} else {
badgeBitmap.eraseColor(Color.TRANSPARENT);
Canvas c = new Canvas(badgeBitmap);
drawable.setBounds(0, 0, badgeSize, badgeSize);
drawable.draw(c);
c.setBitmap(null);
}
mUserBadges.put(user, badgeBitmap);
return badgeBitmap;
}
}

View File

@ -34,6 +34,7 @@ import com.android.launcher3.SimpleOnStylusPressListener;
import com.android.launcher3.StylusEventHelper;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.model.WidgetItem;
/**
@ -116,7 +117,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
Log.d(TAG, "reset called on:" + mWidgetName.getText());
}
mWidgetImage.animate().cancel();
mWidgetImage.setBitmap(null);
mWidgetImage.setBitmap(null, null);
mWidgetName.setText(null);
mWidgetDims.setText(null);
@ -152,7 +153,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
public void applyPreview(Bitmap bitmap) {
if (bitmap != null) {
mWidgetImage.setBitmap(bitmap);
mWidgetImage.setBitmap(bitmap,
DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
mWidgetImage.setAlpha(0f);
ViewPropertyAnimator anim = mWidgetImage.animate();
anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);

View File

@ -22,9 +22,13 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
/**
* View that draws a bitmap horizontally centered. If the image width is greater than the view
* width, the image is scaled down appropriately.
@ -33,22 +37,29 @@ public class WidgetImageView extends View {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final RectF mDstRectF = new RectF();
private final int mBadgeMargin;
private Bitmap mBitmap;
private Drawable mBadge;
public WidgetImageView(Context context) {
super(context);
this(context, null);
}
public WidgetImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this(context, attrs, 0);
}
public WidgetImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mBadgeMargin = context.getResources()
.getDimensionPixelSize(R.dimen.profile_badge_margin);
}
public void setBitmap(Bitmap bitmap) {
public void setBitmap(Bitmap bitmap, Drawable badge) {
mBitmap = bitmap;
mBadge = badge;
invalidate();
}
@ -61,6 +72,11 @@ public class WidgetImageView extends View {
if (mBitmap != null) {
updateDstRectF();
canvas.drawBitmap(mBitmap, null, mDstRectF, mPaint);
// Only draw the badge if a preview was drawn.
if (mBadge != null) {
mBadge.draw(canvas);
}
}
}
@ -83,6 +99,16 @@ public class WidgetImageView extends View {
(getWidth() + mBitmap.getWidth()) * 0.5f,
mBitmap.getHeight());
}
if (mBadge != null) {
Rect bounds = mBadge.getBounds();
int left = Utilities.boundToRange(
(int) (mDstRectF.right + mBadgeMargin - bounds.width()),
mBadgeMargin, getWidth() - bounds.width());
int top = Utilities.boundToRange(
(int) (mDstRectF.bottom + mBadgeMargin - bounds.height()),
mBadgeMargin, getHeight() - bounds.height());
mBadge.setBounds(left, top, bounds.width() + left, bounds.height() + top);
}
}
/**