From 5b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 1 Jun 2015 18:37:32 -0700 Subject: Fixing preloaded widget not getting used for animation > The preloaded widget was being set in a different instance of PendingAddWidgetInfo and was never getting used for animation. bug: 20699153 Change-Id: Iaec13640e49c66993b4695e4a52dc3a3a2133fb2 --- src/com/android/launcher3/Launcher.java | 3 + .../launcher3/widget/PendingAddWidgetInfo.java | 19 --- .../launcher3/widget/WidgetHostViewLoader.java | 157 ++++++++------------- .../launcher3/widget/WidgetsContainerView.java | 16 +-- 4 files changed, 67 insertions(+), 128 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 2ff6adc99..975672764 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2370,6 +2370,9 @@ public class Launcher extends Activity if (hostView != null) { appWidgetId = hostView.getAppWidgetId(); addAppWidgetImpl(appWidgetId, info, hostView, info.info); + + // Clear the boundWidget so that it doesn't get destroyed. + info.boundWidget = null; } else { // In this case, we either need to start an activity to get permission to bind // the widget, or we need to start an activity to configure the widget, or both. diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java index 36cc2b111..88a6ca420 100644 --- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java +++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java @@ -65,25 +65,6 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo { return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; } - // Copy constructor - public PendingAddWidgetInfo(PendingAddWidgetInfo copy) { - minWidth = copy.minWidth; - minHeight = copy.minHeight; - minResizeWidth = copy.minResizeWidth; - minResizeHeight = copy.minResizeHeight; - previewImage = copy.previewImage; - icon = copy.icon; - info = copy.info; - boundWidget = copy.boundWidget; - componentName = copy.componentName; - itemType = copy.itemType; - spanX = copy.spanX; - spanY = copy.spanY; - minSpanX = copy.minSpanX; - minSpanY = copy.minSpanY; - bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone(); - } - @Override public String toString() { return String.format("PendingAddWidgetInfo package=%s, name=%s", diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 887587905..30b3d581a 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -7,148 +7,111 @@ import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.util.Log; import android.view.View; import com.android.launcher3.AppWidgetResizeFrame; +import com.android.launcher3.DragController.DragListener; import com.android.launcher3.DragLayer; +import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.util.Thunk; -public class WidgetHostViewLoader { - - private static final boolean DEBUG = false; - private static final String TAG = "WidgetHostViewLoader"; - - /* constants used for widget loading state. */ - private static final int WIDGET_NO_CLEANUP_REQUIRED = -1; - private static final int WIDGET_PRELOAD_PENDING = 0; - private static final int WIDGET_BOUND = 1; - private static final int WIDGET_INFLATED = 2; - - int mState = WIDGET_NO_CLEANUP_REQUIRED; +public class WidgetHostViewLoader implements DragListener { /* Runnables to handle inflation and binding. */ - private Runnable mInflateWidgetRunnable = null; + @Thunk Runnable mInflateWidgetRunnable = null; private Runnable mBindWidgetRunnable = null; - /* Id of the widget being handled. */ - int mWidgetLoadingId = -1; - PendingAddWidgetInfo mCreateWidgetInfo = null; - // TODO: technically, this class should not have to know the existence of the launcher. @Thunk Launcher mLauncher; - private Handler mHandler; + @Thunk Handler mHandler; + @Thunk final View mView; + @Thunk final PendingAddWidgetInfo mInfo; + + // Widget id generated for binding a widget host view or -1 for invalid id. The id is + // not is use as long as it is stored here and can be deleted safely. Once its used, this value + // to be set back to -1. + @Thunk int mWidgetLoadingId = -1; - public WidgetHostViewLoader(Launcher launcher) { + public WidgetHostViewLoader(Launcher launcher, View view) { mLauncher = launcher; mHandler = new Handler(); + mView = view; + mInfo = (PendingAddWidgetInfo) view.getTag(); } - /** - * Start loading the widget. - */ - public void load(View v) { - if (mCreateWidgetInfo != null) { - // Just in case the cleanup process wasn't properly executed. - finish(false); - } - boolean status = false; - if (v.getTag() instanceof PendingAddWidgetInfo) { - mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag()); - status = preloadWidget(v, mCreateWidgetInfo); - } - if (DEBUG) { - Log.d(TAG, String.format("load started on [state=%d, status=%s]", mState, status)); - } - } - + @Override + public void onDragStart(DragSource source, Object info, int dragAction) { } - /** - * Clean up according to what the last known state was. - * @param widgetIdUsed {@code true} if the widgetId was consumed which can happen only - * when view is fully inflated - */ - public void finish(boolean widgetIdUsed) { - if (DEBUG) { - Log.d(TAG, String.format("cancel on state [%d] widgetId=[%d]", - mState, mWidgetLoadingId)); - } + @Override + public void onDragEnd() { + // Cleanup up preloading state. + mLauncher.getDragController().removeDragListener(this); - // If the widget was not added, we may need to do further cleanup. - PendingAddWidgetInfo info = mCreateWidgetInfo; - mCreateWidgetInfo = null; - - if (mState == WIDGET_PRELOAD_PENDING) { - // We never did any preloading, so just remove pending callbacks to do so - mHandler.removeCallbacks(mBindWidgetRunnable); - mHandler.removeCallbacks(mInflateWidgetRunnable); - } else if (mState == WIDGET_BOUND) { - // Delete the widget id which was allocated - if (mWidgetLoadingId != -1 && !info.isCustomWidget()) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); - } + mHandler.removeCallbacks(mBindWidgetRunnable); + mHandler.removeCallbacks(mInflateWidgetRunnable); - // We never got around to inflating the widget, so remove the callback to do so. - mHandler.removeCallbacks(mInflateWidgetRunnable); - } else if (mState == WIDGET_INFLATED && !widgetIdUsed) { - // Delete the widget id which was allocated - if (mWidgetLoadingId != -1 && !info.isCustomWidget()) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); - } + // Cleanup widget id + if (mWidgetLoadingId != -1) { + mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); + mWidgetLoadingId = -1; + } - // The widget was inflated and added to the DragLayer -- remove it. - AppWidgetHostView widget = info.boundWidget; - mLauncher.getDragLayer().removeView(widget); + // The widget was inflated and added to the DragLayer -- remove it. + if (mInfo.boundWidget != null) { + mLauncher.getDragLayer().removeView(mInfo.boundWidget); + mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); + mInfo.boundWidget = null; } - setState(WIDGET_NO_CLEANUP_REQUIRED); - mWidgetLoadingId = -1; } - private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) { - final LauncherAppWidgetProviderInfo pInfo = info.info; + /** + * Start preloading the widget. + */ + public boolean preloadWidget() { + final LauncherAppWidgetProviderInfo pInfo = mInfo.info; - final Bundle options = pInfo.isCustomWidget ? null : - getDefaultOptionsForWidget(mLauncher, info); + if (pInfo.isCustomWidget) { + return false; + } + final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo); // If there is a configuration activity, do not follow thru bound and inflate. if (pInfo.configure != null) { - info.bindOptions = options; + mInfo.bindOptions = options; return false; } - setState(WIDGET_PRELOAD_PENDING); + mBindWidgetRunnable = new Runnable() { @Override public void run() { - if (pInfo.isCustomWidget) { - setState(WIDGET_BOUND); - return; - } - mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( mWidgetLoadingId, pInfo, options)) { - setState(WIDGET_BOUND); + + // Widget id bound. Inflate the widget. + mHandler.post(mInflateWidgetRunnable); } } }; - mHandler.post(mBindWidgetRunnable); mInflateWidgetRunnable = new Runnable() { @Override public void run() { - if (mState != WIDGET_BOUND) { + if (mWidgetLoadingId == -1) { return; } AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( (Context) mLauncher, mWidgetLoadingId, pInfo); - info.boundWidget = hostView; - setState(WIDGET_INFLATED); - hostView.setVisibility(View.INVISIBLE); - int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false); + mInfo.boundWidget = hostView; + + // We used up the widget Id in binding the above view. + mWidgetLoadingId = -1; + hostView.setVisibility(View.INVISIBLE); + int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false); // We want the first widget layout to be the correct size. This will be important // for width size reporting to the AppWidgetManager. DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], @@ -157,10 +120,11 @@ public class WidgetHostViewLoader { lp.customPosition = true; hostView.setLayoutParams(lp); mLauncher.getDragLayer().addView(hostView); - v.setTag(info); + mView.setTag(mInfo); } }; - mHandler.post(mInflateWidgetRunnable); + + mHandler.post(mBindWidgetRunnable); return true; } @@ -188,11 +152,4 @@ public class WidgetHostViewLoader { } return options; } - - @Thunk void setState(int state) { - if (DEBUG) { - Log.d(TAG, String.format(" state [%d -> %d]", mState, state)); - } - mState = state; - } } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 8d04be5e3..aa139cb48 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -21,7 +21,6 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.State; import android.util.AttributeSet; import android.util.Log; @@ -74,7 +73,6 @@ public class WidgetsContainerView extends BaseContainerView /* Rendering related. */ private WidgetPreviewLoader mWidgetPreviewLoader; - private WidgetHostViewLoader mWidgetHostViewLoader; private Rect mPadding = new Rect(); @@ -90,7 +88,6 @@ public class WidgetsContainerView extends BaseContainerView super(context, attrs, defStyleAttr); mLauncher = (Launcher) context; mDragController = mLauncher.getDragController(); - mWidgetHostViewLoader = new WidgetHostViewLoader(mLauncher); mAdapter = new WidgetsListAdapter(context, this, this, mLauncher); mIconCache = (LauncherAppState.getInstance()).getIconCache(); @@ -170,8 +167,13 @@ public class WidgetsContainerView extends BaseContainerView if (!mLauncher.isDraggingEnabled()) return false; boolean status = beginDragging(v); - if (status) { - mWidgetHostViewLoader.load(v); + if (status && v.getTag() instanceof PendingAddWidgetInfo) { + WidgetHostViewLoader hostLoader = new WidgetHostViewLoader(mLauncher, v); + boolean preloadStatus = hostLoader.preloadWidget(); + if (DEBUG) { + Log.d(TAG, String.format("preloading widget [status=%s]", preloadStatus)); + } + mLauncher.getDragController().addDragListener(hostLoader); } return status; } @@ -325,10 +327,6 @@ public class WidgetsContainerView extends BaseContainerView } d.deferDragViewCleanupPostAnimation = false; } - //TODO(hyunyoungs): if drop fails, this call cleans up correctly. - // However, in rare corner case where drop succeeds but doesn't end up using the widget - // id created by the loader, this finish will leave dangling widget id. - mWidgetHostViewLoader.finish(success); } // -- cgit v1.2.3