OSDN Git Service

Adding support for showing the widget preview based on the provided RemoteViews
authorSunny Goyal <sunnygoyal@google.com>
Wed, 8 Mar 2017 22:49:55 +0000 (14:49 -0800)
committerSunny Goyal <sunnygoyal@google.com>
Fri, 17 Mar 2017 18:25:29 +0000 (11:25 -0700)
Bug: 35811129
Change-Id: I336e48cd00cfec2e617ac73bd8a81419b0944aa7

13 files changed:
res/layout/add_item_confirmation_activity.xml
res/layout/widget_cell.xml
res/layout/widget_cell_content.xml [new file with mode: 0644]
src/com/android/launcher3/WidgetPreviewLoader.java
src/com/android/launcher3/compat/PinItemRequestCompat.java
src/com/android/launcher3/dragndrop/AddItemActivity.java
src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java [new file with mode: 0644]
src/com/android/launcher3/dragndrop/PinItemDragListener.java
src/com/android/launcher3/widget/PendingItemDragHelper.java
src/com/android/launcher3/widget/WidgetCell.java
tests/res/layout/test_layout_appwidget_view.xml [new file with mode: 0644]
tests/src/com/android/launcher3/testcomponent/RequestPinItemActivity.java
tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java

index 2aae5bc..35bcac3 100644 (file)
         android:background="?android:attr/colorPrimaryDark"
         android:layout_height="wrap_content">
 
-        <include
-            layout="@layout/widget_cell"
-            android:layout_gravity="center_horizontal"
+        <com.android.launcher3.dragndrop.LivePreviewWidgetCell
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:id="@+id/widget_cell" />
+            android:layout_weight="1"
+            android:orientation="vertical"
+            android:focusable="true"
+            android:background="?android:attr/colorPrimaryDark"
+            android:gravity="center_horizontal"
+            android:id="@+id/widget_cell"
+            android:layout_gravity="center_horizontal" >
+
+            <include layout="@layout/widget_cell_content"  />
+
+        </com.android.launcher3.dragndrop.LivePreviewWidgetCell>
     </FrameLayout>
 
     <LinearLayout
index b9b098c..148a99b 100644 (file)
     android:background="?android:attr/colorPrimaryDark"
     android:gravity="center_horizontal">
 
-    <LinearLayout
-        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"
-        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
-        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
-        android:orientation="horizontal">
+    <include layout="@layout/widget_cell_content"  />
 
-        <!-- The name of the widget. -->
-        <TextView
-            android:id="@+id/widget_name"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:ellipsize="end"
-            android:fadingEdge="horizontal"
-            android:fontFamily="sans-serif-condensed"
-            android:gravity="start"
-            android:singleLine="true"
-            android:maxLines="1"
-            android:textColor="?android:attr/textColorSecondary"
-            android:textSize="14sp" />
-
-        <!-- The original dimensions of the widget (can't be the same text as above due to different
-             style. -->
-        <TextView
-            android:id="@+id/widget_dims"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="5dp"
-            android:layout_marginLeft="5dp"
-            android:textColor="?android:attr/textColorSecondary"
-            android:textSize="14sp"
-            android:fontFamily="sans-serif-condensed"
-            android:alpha="0.8" />
-    </LinearLayout>
-
-    <!-- The image of the widget. This view does not support padding. Any placement adjustment
-         should be done using margins. -->
-    <com.android.launcher3.widget.WidgetImageView
-        android:id="@+id/widget_preview"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
 </com.android.launcher3.widget.WidgetCell>
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
new file mode 100644 (file)
index 0000000..c77b0b9
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        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"
+        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+        android:orientation="horizontal">
+
+        <!-- The name of the widget. -->
+        <TextView
+            android:id="@+id/widget_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="start"
+            android:singleLine="true"
+            android:maxLines="1"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp" />
+
+        <!-- The original dimensions of the widget (can't be the same text as above due to different
+             style. -->
+        <TextView
+            android:id="@+id/widget_dims"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="5dp"
+            android:layout_marginLeft="5dp"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif-condensed"
+            android:alpha="0.8" />
+    </LinearLayout>
+
+    <!-- The image of the widget. This view does not support padding. Any placement adjustment
+         should be done using margins. -->
+    <com.android.launcher3.widget.WidgetImageView
+        android:id="@+id/widget_preview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</merge>
\ No newline at end of file
index 689cc9b..0e91062 100644 (file)
@@ -22,6 +22,7 @@ import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.support.v4.graphics.ColorUtils;
@@ -89,14 +90,17 @@ public class WidgetPreviewLoader {
      *
      * @return a request id which can be used to cancel the request.
      */
-    public PreviewLoadRequest getPreview(WidgetItem item, int previewWidth,
+    public CancellationSignal getPreview(WidgetItem item, int previewWidth,
             int previewHeight, WidgetCell caller) {
         String size = previewWidth + "x" + previewHeight;
         WidgetCacheKey key = new WidgetCacheKey(item.componentName, item.user, size);
 
         PreviewLoadTask task = new PreviewLoadTask(key, item, previewWidth, previewHeight, caller);
         task.executeOnExecutor(Utilities.THREAD_POOL_EXECUTOR);
-        return new PreviewLoadRequest(task);
+
+        CancellationSignal signal = new CancellationSignal();
+        signal.setOnCancelListener(task);
+        return signal;
     }
 
     /**
@@ -510,42 +514,8 @@ public class WidgetPreviewLoader {
         }
     }
 
-    /**
-     * A request Id which can be used by the client to cancel any request.
-     */
-    public class PreviewLoadRequest {
-
-        @Thunk final PreviewLoadTask mTask;
-
-        public PreviewLoadRequest(PreviewLoadTask task) {
-            mTask = task;
-        }
-
-        public void cleanup() {
-            if (mTask != null) {
-                mTask.cancel(true);
-            }
-
-            // This only handles the case where the PreviewLoadTask is cancelled after the task has
-            // successfully completed (including having written to disk when necessary).  In the
-            // other cases where it is cancelled while the task is running, it will be cleaned up
-            // in the tasks's onCancelled() call, and if cancelled while the task is writing to
-            // disk, it will be cancelled in the task's onPostExecute() call.
-            if (mTask.mBitmapToRecycle != null) {
-                mWorkerHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (mUnusedBitmaps) {
-                            mUnusedBitmaps.add(mTask.mBitmapToRecycle);
-                        }
-                        mTask.mBitmapToRecycle = null;
-                    }
-                });
-            }
-        }
-    }
-
-    public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> {
+    public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap>
+            implements CancellationSignal.OnCancelListener {
         @Thunk final WidgetCacheKey mKey;
         private final WidgetItem mInfo;
         private final int mPreviewHeight;
@@ -661,6 +631,28 @@ public class WidgetPreviewLoader {
                 });
             }
         }
+
+        @Override
+        public void onCancel() {
+            cancel(true);
+
+            // This only handles the case where the PreviewLoadTask is cancelled after the task has
+            // successfully completed (including having written to disk when necessary).  In the
+            // other cases where it is cancelled while the task is running, it will be cleaned up
+            // in the tasks's onCancelled() call, and if cancelled while the task is writing to
+            // disk, it will be cancelled in the task's onPostExecute() call.
+            if (mBitmapToRecycle != null) {
+                mWorkerHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        synchronized (mUnusedBitmaps) {
+                            mUnusedBitmaps.add(mBitmapToRecycle);
+                        }
+                        mBitmapToRecycle = null;
+                    }
+                });
+            }
+        }
     }
 
     private static final class WidgetCacheKey extends ComponentKey {
index f76b776..550bcc3 100644 (file)
@@ -76,6 +76,14 @@ public class PinItemRequestCompat implements Parcelable {
         }
     }
 
+    public Bundle getExtras() {
+        try {
+            return (Bundle) mObject.getClass().getDeclaredMethod("getExtras").invoke(mObject);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     private Object invokeMethod(String methodName) {
         try {
             return mObject.getClass().getDeclaredMethod(methodName).invoke(mObject);
index b80baf3..c2a4820 100644 (file)
@@ -27,10 +27,8 @@ import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.*;
@@ -47,7 +45,6 @@ import com.android.launcher3.compat.PinItemRequestCompat;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
-import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetImageView;
 
@@ -65,7 +62,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
     private LauncherAppState mApp;
     private InvariantDeviceProfile mIdp;
 
-    private WidgetCell mWidgetCell;
+    private LivePreviewWidgetCell mWidgetCell;
 
     // Widget request specific options.
     private AppWidgetHost mAppWidgetHost;
@@ -92,7 +89,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
         mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
 
         setContentView(R.layout.add_item_confirmation_activity);
-        mWidgetCell = (WidgetCell) findViewById(R.id.widget_cell);
+        mWidgetCell = (LivePreviewWidgetCell) findViewById(R.id.widget_cell);
 
         if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
             setupShortcut();
@@ -169,6 +166,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
             // Cannot add widget
             return false;
         }
+        mWidgetCell.setPreview(PinItemDragListener.getPreview(mRequest));
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
         mAppWidgetHost = new AppWidgetHost(this, Launcher.APPWIDGET_HOST_ID);
diff --git a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
new file mode 100644 (file)
index 0000000..36a0292
--- /dev/null
@@ -0,0 +1,99 @@
+package com.android.launcher3.dragndrop;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetCell;
+
+/**
+ * Extension of {@link WidgetCell} which supports generating previews from {@link RemoteViews}
+ */
+public class LivePreviewWidgetCell extends WidgetCell {
+
+    private RemoteViews mPreview;
+
+    public LivePreviewWidgetCell(Context context) {
+        this(context, null);
+    }
+
+    public LivePreviewWidgetCell(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public LivePreviewWidgetCell(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setPreview(RemoteViews view) {
+        mPreview = view;
+    }
+
+    @Override
+    public void ensurePreview() {
+        if (mPreview != null && mActiveRequest == null) {
+            Bitmap preview = generateFromRemoteViews(
+                    mActivity, mPreview, mItem.widgetInfo, mPresetPreviewSize, new int[1]);
+            if (preview != null) {
+                applyPreview(preview);
+                return;
+            }
+        }
+        super.ensurePreview();
+    }
+
+    /**
+     * Generates a bitmap by inflating {@param views}.
+     * @see com.android.launcher3.WidgetPreviewLoader#generateWidgetPreview
+     *
+     * TODO: Consider moving this to the background thread.
+     */
+    public static Bitmap generateFromRemoteViews(BaseActivity activity, RemoteViews views,
+            LauncherAppWidgetProviderInfo info, int previewSize, int[] preScaledWidthOut) {
+
+        DeviceProfile dp = activity.getDeviceProfile();
+        int viewWidth = dp.cellWidthPx * info.spanX;
+        int viewHeight = dp.cellHeightPx * info.spanY;
+
+        final View v;
+        try {
+            v = views.apply(activity, new FrameLayout(activity));
+            v.measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));
+
+            viewWidth = v.getMeasuredWidth();
+            viewHeight = v.getMeasuredHeight();
+            v.layout(0, 0, viewWidth, viewHeight);
+        } catch (Exception e) {
+            return null;
+        }
+
+        preScaledWidthOut[0] = viewWidth;
+        final int bitmapWidth, bitmapHeight;
+        final float scale;
+        if (viewWidth > previewSize) {
+            scale = ((float) previewSize) / viewWidth;
+            bitmapWidth = previewSize;
+            bitmapHeight = (int) (viewHeight * scale);
+        } else {
+            scale = 1;
+            bitmapWidth = viewWidth;
+            bitmapHeight = viewHeight;
+        }
+
+        Bitmap preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(preview);
+        c.scale(scale, scale);
+        v.draw(c);
+        c.setBitmap(null);
+        return preview;
+    }
+}
index 6e5318f..fd252a2 100644 (file)
 
 package com.android.launcher3.dragndrop;
 
+import android.appwidget.AppWidgetManager;
 import android.content.ClipDescription;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcel;
@@ -27,6 +29,7 @@ import android.os.SystemClock;
 import android.util.Log;
 import android.view.DragEvent;
 import android.view.View;
+import android.widget.RemoteViews;
 
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
@@ -171,7 +174,12 @@ public class PinItemDragListener
         // and the absolute position (position relative to the screen) of drag event is same
         // across windows, using drag position here give a good estimate for relative position
         // to source window.
-        new PendingItemDragHelper(view).startDrag(new Rect(mPreviewRect),
+        PendingItemDragHelper dragHelper = new PendingItemDragHelper(view);
+        if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET) {
+            dragHelper.setPreview(getPreview(mRequest));
+        }
+
+        dragHelper.startDrag(new Rect(mPreviewRect),
                 mPreviewBitmapWidth, mPreviewViewWidth, downPos,  this, options);
         mDragStartTime = SystemClock.uptimeMillis();
         return true;
@@ -250,6 +258,15 @@ public class PinItemDragListener
         }
     }
 
+    public static RemoteViews getPreview(PinItemRequestCompat request) {
+        Bundle extras = request.getExtras();
+        if (extras != null &&
+                extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW) instanceof RemoteViews) {
+            return (RemoteViews) extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW);
+        }
+        return null;
+    }
+
     public static final Parcelable.Creator<PinItemDragListener> CREATOR =
             new Parcelable.Creator<PinItemDragListener>() {
                 public PinItemDragListener createFromParcel(Parcel source) {
index 6f4c286..b411879 100644 (file)
@@ -23,6 +23,7 @@ import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.view.View;
+import android.widget.RemoteViews;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
@@ -32,6 +33,7 @@ import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.graphics.HolographicOutlineHelper;
 import com.android.launcher3.graphics.LauncherIcons;
@@ -47,12 +49,17 @@ public class PendingItemDragHelper extends DragPreviewProvider {
     private final PendingAddItemInfo mAddInfo;
 
     private Bitmap mPreviewBitmap;
+    private RemoteViews mPreview;
 
     public PendingItemDragHelper(View view) {
         super(view);
         mAddInfo = (PendingAddItemInfo) view.getTag();
     }
 
+    public void setPreview(RemoteViews preview) {
+        mPreview = preview;
+    }
+
     /**
      * Starts the drag for the pending item associated with the view.
      *
@@ -67,7 +74,7 @@ public class PendingItemDragHelper extends DragPreviewProvider {
         final Launcher launcher = Launcher.getLauncher(mView.getContext());
         LauncherAppState app = LauncherAppState.getInstance(launcher);
 
-        final Bitmap preview;
+        Bitmap preview = null;
         final float scale;
         final Point dragOffset;
         final Rect dragRegion;
@@ -80,8 +87,15 @@ public class PendingItemDragHelper extends DragPreviewProvider {
             int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), size[0]);
 
             int[] previewSizeBeforeScale = new int[1];
-            preview = app.getWidgetCache() .generateWidgetPreview(
-                    launcher, createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale);
+
+            if (mPreview != null) {
+                preview = LivePreviewWidgetCell.generateFromRemoteViews(launcher, mPreview,
+                        createWidgetInfo.info, maxWidth, previewSizeBeforeScale);
+            }
+            if (preview == null) {
+                preview = app.getWidgetCache().generateWidgetPreview(
+                        launcher, createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale);
+            }
 
             if (previewSizeBeforeScale[0] < previewBitmapWidth) {
                 // The icon has extra padding around it.
index 455ec4e..3bf622e 100644 (file)
@@ -18,6 +18,7 @@ package com.android.launcher3.widget;
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.os.CancellationSignal;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -34,7 +35,6 @@ import com.android.launcher3.R;
 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;
 
@@ -60,20 +60,21 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
     /** Widget preview width is calculated by multiplying this factor to the widget cell width. */
     private static final float PREVIEW_SCALE = 0.8f;
 
-    private int mPresetPreviewSize;
+    protected int mPresetPreviewSize;
     private int mCellSize;
 
     private WidgetImageView mWidgetImage;
     private TextView mWidgetName;
     private TextView mWidgetDims;
 
-    private WidgetItem mItem;
+    protected WidgetItem mItem;
 
     private WidgetPreviewLoader mWidgetPreviewLoader;
-    private PreviewLoadRequest mActiveRequest;
     private StylusEventHelper mStylusEventHelper;
 
-    private final BaseActivity mActivity;
+    protected CancellationSignal mActiveRequest;
+
+    protected final BaseActivity mActivity;
 
     public WidgetCell(Context context) {
         this(context, null);
@@ -123,7 +124,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
         mWidgetDims.setText(null);
 
         if (mActiveRequest != null) {
-            mActiveRequest.cleanup();
+            mActiveRequest.cancel();
             mActiveRequest = null;
         }
     }
diff --git a/tests/res/layout/test_layout_appwidget_view.xml b/tests/res/layout/test_layout_appwidget_view.xml
new file mode 100644 (file)
index 0000000..7c87e60
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#FFFF00">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="20dp"
+        android:background="#FF0000"
+        android:id="@android:id/icon" />
+</FrameLayout>
\ No newline at end of file
index 2a031af..8580992 100644 (file)
@@ -28,6 +28,7 @@ import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
+import android.widget.RemoteViews;
 
 /**
  * Sample activity to request pinning an item.
@@ -36,7 +37,8 @@ import android.os.Bundle;
 public class RequestPinItemActivity extends BaseTestingActivity {
 
     private PendingIntent mCallback = null;
-    private String mShortcutId;
+    private String mShortcutId = "test-id";
+    private int mRemoteViewColor = Color.TRANSPARENT;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -51,6 +53,10 @@ public class RequestPinItemActivity extends BaseTestingActivity {
         mCallback = callback;
     }
 
+    public void setRemoteViewColor(int color) {
+        mRemoteViewColor = color;
+    }
+
     public void setShortcutId(String id) {
         mShortcutId = id;
     }
@@ -84,6 +90,16 @@ public class RequestPinItemActivity extends BaseTestingActivity {
     }
 
     private void requestWidget(ComponentName cn) {
-        AppWidgetManager.getInstance(this).requestPinAppWidget(cn, null, mCallback);
+        Bundle extras = null;
+        if (mRemoteViewColor != Color.TRANSPARENT) {
+            int layoutId = getResources().getIdentifier(
+                    "test_layout_appwidget_view", "layout", getPackageName());
+            RemoteViews views = new RemoteViews(getPackageName(), layoutId);
+            views.setInt(android.R.id.icon, "setBackgroundColor", mRemoteViewColor);
+            extras = new Bundle();
+            extras.putParcelable(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW, views);
+        }
+
+        AppWidgetManager.getInstance(this).requestPinAppWidget(cn, extras, mCallback);
     }
 }
index 5ef5ec1..b798dfa 100644 (file)
@@ -20,6 +20,7 @@ import android.app.Application;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
 import android.content.Intent;
+import android.graphics.Color;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
@@ -95,6 +96,23 @@ public class RequestPinItemTest  extends LauncherInstrumentationTestCase {
         });
     }
 
+    public void testPinWidgetNoConfig_customPreview() throws Throwable {
+        // Command to set custom preview
+        Intent command =  RequestPinItemActivity.getCommandIntent(
+                RequestPinItemActivity.class, "setRemoteViewColor").putExtra(
+                RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED);
+
+        runTest("pinWidgetNoConfig", true, new ItemOperator() {
+            @Override
+            public boolean evaluate(ItemInfo info, View view) {
+                return info instanceof LauncherAppWidgetInfo &&
+                        ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
+                        ((LauncherAppWidgetInfo) info).providerName.getClassName()
+                                .equals(AppWidgetNoConfig.class.getName());
+            }
+        }, command);
+    }
+
     public void testPinWidgetWithConfig() throws Throwable {
         runTest("pinWidgetWithConfig", true, new ItemOperator() {
             @Override
@@ -107,8 +125,12 @@ public class RequestPinItemTest  extends LauncherInstrumentationTestCase {
         });
     }
 
+    public void testPinShortcut() throws Throwable {
+        // Command to set the shortcut id
+        Intent command = RequestPinItemActivity.getCommandIntent(
+                RequestPinItemActivity.class, "setShortcutId").putExtra(
+                RequestPinItemActivity.EXTRA_PARAM + "0", mShortcutId);
 
-    public void testPinWidgetShortcut() throws Throwable {
         runTest("pinShortcut", false, new ItemOperator() {
             @Override
             public boolean evaluate(ItemInfo info, View view) {
@@ -116,11 +138,11 @@ public class RequestPinItemTest  extends LauncherInstrumentationTestCase {
                         info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
                         ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId);
             }
-        });
+        }, command);
     }
 
-    private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher)
-            throws Throwable {
+    private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher,
+            Intent... commandIntents) throws Throwable {
         if (!Utilities.isAtLeastO()) {
             return;
         }
@@ -146,11 +168,8 @@ public class RequestPinItemTest  extends LauncherInstrumentationTestCase {
                 RequestPinItemActivity.class, "setCallback").putExtra(
                 RequestPinItemActivity.EXTRA_PARAM + "0", callback));
 
-        if (!isWidget) {
-            // Set shortcut id
-            mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
-                    RequestPinItemActivity.class, "setShortcutId").putExtra(
-                    RequestPinItemActivity.EXTRA_PARAM + "0", mShortcutId));
+        for (Intent command : commandIntents) {
+            mTargetContext.sendBroadcast(command);
         }
 
         // call the requested method to start the flow