Generate a default preview for widgets that don't have a previewImage.

Change-Id: I3a3c24543c925a50ab34fd3cbf7947544a5ac5c0
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 62ede4d..7ca549e 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -63,6 +63,7 @@
     private int mHeightGap;
 
     private final Rect mRect = new Rect();
+    private final RectF mRectF = new RectF();
     private final CellInfo mCellInfo = new CellInfo();
 
     // This is a temporary variable to prevent having to allocate a new object just to
@@ -692,6 +693,19 @@
     }
 
     /**
+     * Estimate the size that a child with the given dimensions will take in the layout.
+     */
+    void estimateChildSize(int minWidth, int minHeight, int[] result) {
+        // Assuming it's placed at 0, 0, find where the bottom right cell will land
+        rectToCell(minWidth, minHeight, result);
+
+        // Then figure out the rect it will occupy
+        cellToRect(0, 0, result[0], result[1], mRectF);
+        result[0] = (int)mRectF.width();
+        result[1] = (int)mRectF.height();
+    }
+
+    /**
      * Estimate where the top left cell of the dragged item will land if it is dropped.
      *
      * @param originX The X value of the top left corner of the item
@@ -891,8 +905,9 @@
      *
      * @param width Width in pixels
      * @param height Height in pixels
+     * @param result An array of length 2 in which to store the result (may be null).
      */
-    public int[] rectToCell(int width, int height) {
+    public int[] rectToCell(int width, int height, int[] result) {
         // Always assume we're working with the smallest span to make sure we
         // reserve enough space in both orientations.
         final Resources resources = getResources();
@@ -904,7 +919,12 @@
         int spanX = (width + smallerSize) / smallerSize;
         int spanY = (height + smallerSize) / smallerSize;
 
-        return new int[] { spanX, spanY };
+        if (result == null) {
+            return new int[] { spanX, spanY };
+        }
+        result[0] = spanX;
+        result[1] = spanY;
+        return result;
     }
 
     /**
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 94556be..dd93cbb 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -953,7 +953,7 @@
 
         // Calculate the grid spans needed to fit this widget
         CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
-        int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
+        int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight, null);
 
         // Try finding open space on Launcher screen
         final int[] xy = mCellCoordinates;
diff --git a/src/com/android/launcher2/WidgetChooser.java b/src/com/android/launcher2/WidgetChooser.java
index 101b671..ea6888e 100644
--- a/src/com/android/launcher2/WidgetChooser.java
+++ b/src/com/android/launcher2/WidgetChooser.java
@@ -2,13 +2,13 @@
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.AdapterView;
+import android.widget.TextView;
 
 public class WidgetChooser extends HomeCustomizationItemGallery implements DragSource {
     private DragController mDragController;
@@ -22,29 +22,23 @@
     }
 
     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+        Drawable[] drawables = ((TextView)view).getCompoundDrawables();
+        Bitmap bmp = ((BitmapDrawable)drawables[1]).getBitmap();
+        final int w = bmp.getWidth();
+        final int h = bmp.getHeight();
+
+        // We don't really have an accurate location to use.  This will do.
+        int screenX = mMotionDownRawX - (w / 2);
+        int screenY = mMotionDownRawY - h;
+
         AppWidgetProviderInfo info = (AppWidgetProviderInfo)getAdapter().getItem(position);
-        try {
-            Resources r = mContext.getPackageManager().getResourcesForApplication(info.provider.getPackageName());
-
-            Bitmap bmp = BitmapFactory.decodeResource(r, info.icon);
-            final int w = bmp.getWidth();
-            final int h = bmp.getHeight();
-
-            // We don't really have an accurate location to use.  This will do.
-            int screenX = mMotionDownRawX - (w / 2);
-            int screenY = mMotionDownRawY - h;
-
-            AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo)view.getTag();
-            LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(info.provider);
-            // TODO: Is this really the best place to do this?
-            dragInfo.minWidth = appWidgetInfo.minWidth;
-            dragInfo.minHeight = appWidgetInfo.minHeight;
-            mDragController.startDrag(bmp, screenX, screenY,
-                    0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY);
-            return true;
-        } catch (NameNotFoundException e) {
-            return false;
-        }
+        LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(info.provider);
+        // TODO: Is this really the best place to do this?
+        dragInfo.minWidth = info.minWidth;
+        dragInfo.minHeight = info.minHeight;
+        mDragController.startDrag(bmp, screenX, screenY,
+                0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY);
+        return true;
     }
 
     public void onDropCompleted(View target, boolean success) {
diff --git a/src/com/android/launcher2/WidgetListAdapter.java b/src/com/android/launcher2/WidgetListAdapter.java
index 5d5d86a..597ecf9 100644
--- a/src/com/android/launcher2/WidgetListAdapter.java
+++ b/src/com/android/launcher2/WidgetListAdapter.java
@@ -22,29 +22,36 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import java.util.List;
 
 public class WidgetListAdapter extends BaseAdapter {
-    private LayoutInflater mLayoutInflater;
-    private PackageManager mPackageManager;
+    private final Launcher mLauncher;
     private List<AppWidgetProviderInfo> mWidgets;
+    private final Canvas mCanvas = new Canvas();
+
+    private final int[] mTempSize = new int[2];
+    private final Rect mTempRect = new Rect();
+
     private static final String TAG = "Launcher.WidgetGalleryAdapter";
 
-    WidgetListAdapter(Context context) {
-        mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
-        mWidgets = widgetManager.getInstalledProviders();
-        mPackageManager = context.getPackageManager();
+    WidgetListAdapter(Launcher launcher) {
+        mLauncher = launcher;
+        mWidgets = AppWidgetManager.getInstance(launcher).getInstalledProviders();
     }
 
     public int getCount() {
@@ -63,27 +70,58 @@
         TextView textView;
 
         if (convertView == null) {
-            textView = (TextView) mLayoutInflater.inflate(
+            LayoutInflater inflater =
+                (LayoutInflater)mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            textView = (TextView) inflater.inflate(
                     R.layout.home_customization_drawer_item, parent, false);
         } else {
             textView = (TextView) convertView;
         }
 
         AppWidgetProviderInfo info = mWidgets.get(position);
-        Drawable image = null;
+        PackageManager packageManager = mLauncher.getPackageManager();
+        String packageName = info.provider.getPackageName();
+        Drawable drawable = null;
         if (info.previewImage != 0) {
-            image = mPackageManager.getDrawable(
-                    info.provider.getPackageName(), info.previewImage, null);
-            if (image == null) {
+            drawable = packageManager.getDrawable(packageName, info.previewImage, null);
+            if (drawable == null) {
                 Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
                         + " for provider: " + info.provider);
             }
         }
-        if (image == null) {
-            image = mPackageManager.getDrawable(info.provider.getPackageName(), info.icon, null);
+        // If we don't have a preview image, create a default one
+        if (drawable == null) {
+            Resources resources = mLauncher.getResources();
+
+            // Determine the size the widget will take in the layout
+            mLauncher.getWorkspace().estimateChildSize(info.minWidth, info.minHeight, mTempSize);
+
+            // Create a new bitmap to hold the widget preview
+            final int width = mTempSize[0];
+            final int height = mTempSize[1];
+            Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+            mCanvas.setBitmap(bitmap);
+            // For some reason, we must re-set the clip rect here, otherwise it will be wrong
+            mCanvas.clipRect(0, 0, width, height, Op.REPLACE);
+
+            Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
+            background.setBounds(0, 0, width, height);
+            background.draw(mCanvas);
+
+            // Draw the icon vertically centered, flush left
+            Drawable icon = packageManager.getDrawable(packageName, info.icon, null);
+            background.getPadding(mTempRect);
+
+            final int left = mTempRect.left;
+            final int top = (height - icon.getIntrinsicHeight()) / 2;
+            icon.setBounds(
+                    left, top, left + icon.getIntrinsicWidth(), top + icon.getIntrinsicHeight());
+            icon.draw(mCanvas);
+
+            drawable = new BitmapDrawable(resources, bitmap);
         }
-        image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
-        textView.setCompoundDrawables(null, image, null, null);
+        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+        textView.setCompoundDrawables(null, drawable, null, null);
         textView.setText(info.label);
         // Store the widget info on the associated view so we can easily fetch it later
         textView.setTag(info);
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index b4986ad..79fb4a9 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1265,7 +1265,7 @@
 
             if (widgetInfo.spanX == -1) {
                 // Calculate the grid spans needed to fit this widget
-                int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight);
+                int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, null);
                 item.spanX = spans[0];
                 item.spanY = spans[1];
             }
@@ -1430,6 +1430,13 @@
         return layout.findNearestVacantArea(mTempEstimate[0], mTempEstimate[1], spanX, spanY, mVacantCache, recycle);
     }
 
+    /**
+     * Estimate the size that a child with the given dimensions will take in the current screen.
+     */
+    void estimateChildSize(int minWidth, int minHeight, int[] result) {
+        ((CellLayout)getChildAt(mCurrentScreen)).estimateChildSize(minWidth, minHeight, result);
+    }
+
     void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }