diff options
Diffstat (limited to 'src/com/android/launcher3/widget/WidgetHostViewLoader.java')
-rw-r--r-- | src/com/android/launcher3/widget/WidgetHostViewLoader.java | 156 |
1 files changed, 156 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..461aebb6b --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -0,0 +1,156 @@ +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.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.Utilities; +import com.android.launcher3.compat.AppWidgetManagerCompat; +import com.android.launcher3.util.Thunk; + +public class WidgetHostViewLoader implements DragListener { + + /* Runnables to handle inflation and binding. */ + @Thunk Runnable mInflateWidgetRunnable = null; + private Runnable mBindWidgetRunnable = null; + + // TODO: technically, this class should not have to know the existence of the launcher. + @Thunk Launcher mLauncher; + @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, View view) { + mLauncher = launcher; + 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 preloading the widget. + */ + public boolean preloadWidget() { + final LauncherAppWidgetProviderInfo pInfo = mInfo.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) { + mInfo.bindOptions = options; + return false; + } + + mBindWidgetRunnable = new Runnable() { + @Override + public void run() { + mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); + if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( + mWidgetLoadingId, pInfo, options)) { + + // Widget id bound. Inflate the widget. + mHandler.post(mInflateWidgetRunnable); + } + } + }; + + mInflateWidgetRunnable = new Runnable() { + @Override + public void run() { + if (mWidgetLoadingId == -1) { + return; + } + AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( + (Context) mLauncher, mWidgetLoadingId, pInfo); + 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], + unScaledSize[1]); + lp.x = lp.y = 0; + lp.customPosition = true; + hostView.setLayoutParams(lp); + mLauncher.getDragLayer().addView(hostView); + mView.setTag(mInfo); + } + }; + + mHandler.post(mBindWidgetRunnable); + return true; + } + + public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { + Bundle options = null; + Rect rect = new Rect(); + if (Utilities.ATLEAST_JB_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; + } +} |