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