Merge "Adding support for new APIs in O related to configurable shortcuts" into ub-launcher3-master
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 15f369f..c5a6753 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -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"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c7bc286..3a2eea6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -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>
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 33d6362..f814bb7 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -70,7 +70,6 @@
     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 @@
         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 @@
      * 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 @@
             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 @@
             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 @@
             }
             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(BaseActivity launcher, ShortcutConfigActivityInfo info,
@@ -538,6 +539,7 @@
         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 @@
             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 @@
                 // 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;
         }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index af43c02..7911bb2 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -71,9 +71,6 @@
     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);
 
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 56a7f46..61dd1a5 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -23,17 +23,9 @@
 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;
@@ -82,47 +74,6 @@
     }
 
     @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
                 .getInstalledProvidersForProfile(user)) {
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 693df7a..4d4d508 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -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.Utilities;
 import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
 
+import java.util.HashMap;
+
 /**
  * Factory for creating new drawables.
  */
@@ -43,6 +54,9 @@
         }
     }
 
+    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 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;
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 9e2091b..d07139d 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -34,6 +34,7 @@
 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 @@
             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 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);
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index b0fbe1e..1211c08 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -22,9 +22,13 @@
 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 @@
 
     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 @@
         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 @@
                     (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);
+        }
     }
 
     /**