1 package com.android.launcher3.widget; 2 3 import android.appwidget.AppWidgetHostView; 4 import android.content.Context; 5 import android.os.Bundle; 6 import android.os.Handler; 7 import android.util.Log; 8 import android.view.View; 9 10 import com.android.launcher3.DropTarget; 11 import com.android.launcher3.Launcher; 12 import com.android.launcher3.dragndrop.DragController; 13 import com.android.launcher3.dragndrop.DragLayer; 14 import com.android.launcher3.dragndrop.DragOptions; 15 import com.android.launcher3.util.Thunk; 16 17 public class WidgetHostViewLoader implements DragController.DragListener { 18 private static final String TAG = "WidgetHostViewLoader"; 19 private static final boolean LOGD = false; 20 21 /* Runnables to handle inflation and binding. */ 22 @Thunk Runnable mInflateWidgetRunnable = null; 23 private Runnable mBindWidgetRunnable = null; 24 25 // TODO: technically, this class should not have to know the existence of the launcher. 26 @Thunk Launcher mLauncher; 27 @Thunk Handler mHandler; 28 @Thunk final View mView; 29 @Thunk final PendingAddWidgetInfo mInfo; 30 31 // Widget id generated for binding a widget host view or -1 for invalid id. The id is 32 // not is use as long as it is stored here and can be deleted safely. Once its used, this value 33 // to be set back to -1. 34 @Thunk int mWidgetLoadingId = -1; 35 WidgetHostViewLoader(Launcher launcher, View view)36 public WidgetHostViewLoader(Launcher launcher, View view) { 37 mLauncher = launcher; 38 mHandler = new Handler(); 39 mView = view; 40 mInfo = (PendingAddWidgetInfo) view.getTag(); 41 } 42 43 @Override onDragStart(DropTarget.DragObject dragObject, DragOptions options)44 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { 45 preloadWidget(); 46 } 47 48 @Override onDragEnd()49 public void onDragEnd() { 50 if (LOGD) { 51 Log.d(TAG, "Cleaning up in onDragEnd()..."); 52 } 53 54 // Cleanup up preloading state. 55 mLauncher.getDragController().removeDragListener(this); 56 57 mHandler.removeCallbacks(mBindWidgetRunnable); 58 mHandler.removeCallbacks(mInflateWidgetRunnable); 59 60 // Cleanup widget id 61 if (mWidgetLoadingId != -1) { 62 mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); 63 mWidgetLoadingId = -1; 64 } 65 66 // The widget was inflated and added to the DragLayer -- remove it. 67 if (mInfo.boundWidget != null) { 68 if (LOGD) { 69 Log.d(TAG, "...removing widget from drag layer"); 70 } 71 mLauncher.getDragLayer().removeView(mInfo.boundWidget); 72 mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); 73 mInfo.boundWidget = null; 74 } 75 } 76 77 /** 78 * Start preloading the widget. 79 */ preloadWidget()80 private boolean preloadWidget() { 81 final LauncherAppWidgetProviderInfo pInfo = mInfo.info; 82 83 if (pInfo.isCustomWidget()) { 84 return false; 85 } 86 final Bundle options = mInfo.getDefaultSizeOptions(mLauncher); 87 88 // If there is a configuration activity, do not follow thru bound and inflate. 89 if (mInfo.getHandler().needsConfigure()) { 90 mInfo.bindOptions = options; 91 return false; 92 } 93 94 mBindWidgetRunnable = new Runnable() { 95 @Override 96 public void run() { 97 mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); 98 if (LOGD) { 99 Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId); 100 } 101 if (new WidgetManagerHelper(mLauncher).bindAppWidgetIdIfAllowed( 102 mWidgetLoadingId, pInfo, options)) { 103 104 // Widget id bound. Inflate the widget. 105 mHandler.post(mInflateWidgetRunnable); 106 } 107 } 108 }; 109 110 mInflateWidgetRunnable = new Runnable() { 111 @Override 112 public void run() { 113 if (LOGD) { 114 Log.d(TAG, "Inflating widget, id: " + mWidgetLoadingId); 115 } 116 if (mWidgetLoadingId == -1) { 117 return; 118 } 119 AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( 120 (Context) mLauncher, mWidgetLoadingId, pInfo); 121 mInfo.boundWidget = hostView; 122 123 // We used up the widget Id in binding the above view. 124 mWidgetLoadingId = -1; 125 126 hostView.setVisibility(View.INVISIBLE); 127 int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo); 128 // We want the first widget layout to be the correct size. This will be important 129 // for width size reporting to the AppWidgetManager. 130 DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], 131 unScaledSize[1]); 132 lp.x = lp.y = 0; 133 lp.customPosition = true; 134 hostView.setLayoutParams(lp); 135 if (LOGD) { 136 Log.d(TAG, "Adding host view to drag layer"); 137 } 138 mLauncher.getDragLayer().addView(hostView); 139 mView.setTag(mInfo); 140 } 141 }; 142 143 if (LOGD) { 144 Log.d(TAG, "About to bind/inflate widget"); 145 } 146 mHandler.post(mBindWidgetRunnable); 147 return true; 148 } 149 150 } 151