diff options
Diffstat (limited to 'src/com/android/launcher3')
7 files changed, 182 insertions, 53 deletions
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 6dc65d9a5..5e859c72a 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -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; } /** @@ -511,42 +515,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; @@ -662,6 +632,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 { diff --git a/src/com/android/launcher3/compat/PinItemRequestCompat.java b/src/com/android/launcher3/compat/PinItemRequestCompat.java index f76b77655..550bcc327 100644 --- a/src/com/android/launcher3/compat/PinItemRequestCompat.java +++ b/src/com/android/launcher3/compat/PinItemRequestCompat.java @@ -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); diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index b80baf32f..c2a4820c8 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -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 index 000000000..36a0292da --- /dev/null +++ b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java @@ -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; + } +} diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index 6e5318f2a..fd252a26a 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -16,9 +16,11 @@ 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) { diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java index 6f4c2864b..b4118790c 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -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. diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index 455ec4ef8..3bf622e8f 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -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; } } |