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