Merge "Fixing preloaded widget not getting used for animation" into ub-launcher3-burnaby

This commit is contained in:
Sunny Goyal
2015-06-08 22:32:48 +00:00
committed by Android (Google) Code Review
4 changed files with 72 additions and 132 deletions
+3
View File
@@ -2380,6 +2380,9 @@ public class Launcher extends Activity
if (hostView != null) { if (hostView != null) {
appWidgetId = hostView.getAppWidgetId(); appWidgetId = hostView.getAppWidgetId();
addAppWidgetImpl(appWidgetId, info, hostView, info.info); addAppWidgetImpl(appWidgetId, info, hostView, info.info);
// Clear the boundWidget so that it doesn't get destroyed.
info.boundWidget = null;
} else { } else {
// In this case, we either need to start an activity to get permission to bind // 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. // the widget, or we need to start an activity to configure the widget, or both.
@@ -65,25 +65,6 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo {
return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; 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 @Override
public String toString() { public String toString() {
return String.format("PendingAddWidgetInfo package=%s, name=%s", return String.format("PendingAddWidgetInfo package=%s, name=%s",
@@ -7,148 +7,111 @@ import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.util.Log;
import android.view.View; import android.view.View;
import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.AppWidgetResizeFrame;
import com.android.launcher3.DragController.DragListener;
import com.android.launcher3.DragLayer; import com.android.launcher3.DragLayer;
import com.android.launcher3.DragSource;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.util.Thunk; import com.android.launcher3.util.Thunk;
public class WidgetHostViewLoader { public class WidgetHostViewLoader implements DragListener {
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;
/* Runnables to handle inflation and binding. */ /* Runnables to handle inflation and binding. */
private Runnable mInflateWidgetRunnable = null; @Thunk Runnable mInflateWidgetRunnable = null;
private Runnable mBindWidgetRunnable = 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. // TODO: technically, this class should not have to know the existence of the launcher.
@Thunk Launcher mLauncher; @Thunk Launcher mLauncher;
private Handler mHandler; @Thunk Handler mHandler;
@Thunk final View mView;
@Thunk final PendingAddWidgetInfo mInfo;
public WidgetHostViewLoader(Launcher launcher) { // 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, View view) {
mLauncher = launcher; mLauncher = launcher;
mHandler = new Handler(); mHandler = new Handler();
mView = view;
mInfo = (PendingAddWidgetInfo) view.getTag();
}
@Override
public void onDragStart(DragSource source, Object info, int dragAction) { }
@Override
public void onDragEnd() {
// Cleanup up preloading state.
mLauncher.getDragController().removeDragListener(this);
mHandler.removeCallbacks(mBindWidgetRunnable);
mHandler.removeCallbacks(mInflateWidgetRunnable);
// Cleanup widget id
if (mWidgetLoadingId != -1) {
mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
mWidgetLoadingId = -1;
}
// 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;
}
} }
/** /**
* Start loading the widget. * Start preloading the widget.
*/ */
public void load(View v) { public boolean preloadWidget() {
if (mCreateWidgetInfo != null) { final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
// Just in case the cleanup process wasn't properly executed.
finish(false); if (pInfo.isCustomWidget) {
return false;
} }
boolean status = false; final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo);
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));
}
}
/**
* 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));
}
// 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);
}
// 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);
}
// The widget was inflated and added to the DragLayer -- remove it.
AppWidgetHostView widget = info.boundWidget;
mLauncher.getDragLayer().removeView(widget);
}
setState(WIDGET_NO_CLEANUP_REQUIRED);
mWidgetLoadingId = -1;
}
private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) {
final LauncherAppWidgetProviderInfo pInfo = info.info;
final Bundle options = pInfo.isCustomWidget ? null :
getDefaultOptionsForWidget(mLauncher, info);
// If there is a configuration activity, do not follow thru bound and inflate. // If there is a configuration activity, do not follow thru bound and inflate.
if (pInfo.configure != null) { if (pInfo.configure != null) {
info.bindOptions = options; mInfo.bindOptions = options;
return false; return false;
} }
setState(WIDGET_PRELOAD_PENDING);
mBindWidgetRunnable = new Runnable() { mBindWidgetRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
if (pInfo.isCustomWidget) {
setState(WIDGET_BOUND);
return;
}
mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
mWidgetLoadingId, pInfo, options)) { mWidgetLoadingId, pInfo, options)) {
setState(WIDGET_BOUND);
// Widget id bound. Inflate the widget.
mHandler.post(mInflateWidgetRunnable);
} }
} }
}; };
mHandler.post(mBindWidgetRunnable);
mInflateWidgetRunnable = new Runnable() { mInflateWidgetRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
if (mState != WIDGET_BOUND) { if (mWidgetLoadingId == -1) {
return; return;
} }
AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
(Context) mLauncher, mWidgetLoadingId, pInfo); (Context) mLauncher, mWidgetLoadingId, pInfo);
info.boundWidget = hostView; mInfo.boundWidget = hostView;
setState(WIDGET_INFLATED);
hostView.setVisibility(View.INVISIBLE);
int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
// 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 // We want the first widget layout to be the correct size. This will be important
// for width size reporting to the AppWidgetManager. // for width size reporting to the AppWidgetManager.
DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
@@ -157,10 +120,11 @@ public class WidgetHostViewLoader {
lp.customPosition = true; lp.customPosition = true;
hostView.setLayoutParams(lp); hostView.setLayoutParams(lp);
mLauncher.getDragLayer().addView(hostView); mLauncher.getDragLayer().addView(hostView);
v.setTag(info); mView.setTag(mInfo);
} }
}; };
mHandler.post(mInflateWidgetRunnable);
mHandler.post(mBindWidgetRunnable);
return true; return true;
} }
@@ -188,11 +152,4 @@ public class WidgetHostViewLoader {
} }
return options; return options;
} }
@Thunk void setState(int state) {
if (DEBUG) {
Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
}
mState = state;
}
} }
@@ -74,7 +74,6 @@ public class WidgetsContainerView extends BaseContainerView
/* Rendering related. */ /* Rendering related. */
private WidgetPreviewLoader mWidgetPreviewLoader; private WidgetPreviewLoader mWidgetPreviewLoader;
private WidgetHostViewLoader mWidgetHostViewLoader;
private Rect mPadding = new Rect(); private Rect mPadding = new Rect();
@@ -90,7 +89,6 @@ public class WidgetsContainerView extends BaseContainerView
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
mLauncher = (Launcher) context; mLauncher = (Launcher) context;
mDragController = mLauncher.getDragController(); mDragController = mLauncher.getDragController();
mWidgetHostViewLoader = new WidgetHostViewLoader(mLauncher);
mAdapter = new WidgetsListAdapter(context, this, this, mLauncher); mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
mIconCache = (LauncherAppState.getInstance()).getIconCache(); mIconCache = (LauncherAppState.getInstance()).getIconCache();
if (DEBUG) { if (DEBUG) {
@@ -169,8 +167,13 @@ public class WidgetsContainerView extends BaseContainerView
if (!mLauncher.isDraggingEnabled()) return false; if (!mLauncher.isDraggingEnabled()) return false;
boolean status = beginDragging(v); boolean status = beginDragging(v);
if (status) { if (status && v.getTag() instanceof PendingAddWidgetInfo) {
mWidgetHostViewLoader.load(v); 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; return status;
} }
@@ -325,10 +328,6 @@ public class WidgetsContainerView extends BaseContainerView
} }
d.deferDragViewCleanupPostAnimation = false; 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);
} }
// //