summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/widget/WidgetHostViewLoader.java
diff options
context:
space:
mode:
authorHyunyoung Song <hyunyoungs@google.com>2015-04-23 15:17:50 -0700
committerHyunyoung Song <hyunyoungs@google.com>2015-04-23 15:17:50 -0700
commitb99ff3e83270e113f6182e337c4f7b0223bad92b (patch)
tree357fb2fee1efa1ea7248a420f59c0436860545c0 /src/com/android/launcher3/widget/WidgetHostViewLoader.java
parent685f98b2e23465c7f12839590663b53a40e36527 (diff)
downloadandroid_packages_apps_Trebuchet-b99ff3e83270e113f6182e337c4f7b0223bad92b.tar.gz
android_packages_apps_Trebuchet-b99ff3e83270e113f6182e337c4f7b0223bad92b.tar.bz2
android_packages_apps_Trebuchet-b99ff3e83270e113f6182e337c4f7b0223bad92b.zip
Add drop animation / Toast to widgettray
- show instruction toast on clicking the widget - Add animation when widget drops on the workspace. Added WidgetHostViewLoader to handle short press and assign widget host view to enable animation b/19897708 Change-Id: Iec36d72cb21bf09343d0beeb31a09bf8b0cb5e0d
Diffstat (limited to 'src/com/android/launcher3/widget/WidgetHostViewLoader.java')
-rw-r--r--src/com/android/launcher3/widget/WidgetHostViewLoader.java197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
new file mode 100644
index 000000000..d65455053
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -0,0 +1,197 @@
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+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.DragLayer;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+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;
+
+ /* Runnables to handle inflation and binding. */
+ private 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.
+ private Launcher mLauncher;
+ private Handler mHandler;
+
+ public WidgetHostViewLoader(Launcher launcher) {
+ mLauncher = launcher;
+ mHandler = new Handler();
+ }
+
+ /**
+ * 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));
+ }
+ }
+
+
+ /**
+ * 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 (pInfo.configure != null) {
+ info.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);
+ }
+ }
+ };
+ mHandler.post(mBindWidgetRunnable);
+
+ mInflateWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mState != WIDGET_BOUND) {
+ 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);
+
+ // 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],
+ unScaledSize[1]);
+ lp.x = lp.y = 0;
+ lp.customPosition = true;
+ hostView.setLayoutParams(lp);
+ mLauncher.getDragLayer().addView(hostView);
+ v.setTag(info);
+ }
+ };
+ mHandler.post(mInflateWidgetRunnable);
+ return true;
+ }
+
+ public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
+ Bundle options = null;
+ Rect rect = new Rect();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
+ Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
+ info.componentName, null);
+
+ float density = launcher.getResources().getDisplayMetrics().density;
+ int xPaddingDips = (int) ((padding.left + padding.right) / density);
+ int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+
+ options = new Bundle();
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+ rect.left - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+ rect.top - yPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+ rect.right - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+ rect.bottom - yPaddingDips);
+ }
+ return options;
+ }
+
+ private void setState(int state) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
+ }
+ mState = state;
+ }
+}