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.DragController;
     14 import com.android.launcher3.DragLayer;
     15 import com.android.launcher3.DragSource;
     16 import com.android.launcher3.Launcher;
     17 import com.android.launcher3.LauncherAppWidgetProviderInfo;
     18 import com.android.launcher3.Utilities;
     19 import com.android.launcher3.compat.AppWidgetManagerCompat;
     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(DragSource source, Object info, int dragAction) { }
     50 
     51     @Override
     52     public void onDragEnd() {
     53         if (LOGD) {
     54             Log.d(TAG, "Cleaning up in onDragEnd()...");
     55         }
     56 
     57         // Cleanup up preloading state.
     58         mLauncher.getDragController().removeDragListener(this);
     59 
     60         mHandler.removeCallbacks(mBindWidgetRunnable);
     61         mHandler.removeCallbacks(mInflateWidgetRunnable);
     62 
     63         // Cleanup widget id
     64         if (mWidgetLoadingId != -1) {
     65             mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
     66             mWidgetLoadingId = -1;
     67         }
     68 
     69         // The widget was inflated and added to the DragLayer -- remove it.
     70         if (mInfo.boundWidget != null) {
     71             if (LOGD) {
     72                 Log.d(TAG, "...removing widget from drag layer");
     73             }
     74             mLauncher.getDragLayer().removeView(mInfo.boundWidget);
     75             mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId());
     76             mInfo.boundWidget = null;
     77         }
     78     }
     79 
     80     /**
     81      * Start preloading the widget.
     82      */
     83     public boolean preloadWidget() {
     84         final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
     85 
     86         if (pInfo.isCustomWidget) {
     87             return false;
     88         }
     89         final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo);
     90 
     91         // If there is a configuration activity, do not follow thru bound and inflate.
     92         if (pInfo.configure != null) {
     93             mInfo.bindOptions = options;
     94             return false;
     95         }
     96 
     97         mBindWidgetRunnable = new Runnable() {
     98             @Override
     99             public void run() {
    100                 mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
    101                 if (LOGD) {
    102                     Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId);
    103                 }
    104                 if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
    105                         mWidgetLoadingId, pInfo, options)) {
    106 
    107                     // Widget id bound. Inflate the widget.
    108                     mHandler.post(mInflateWidgetRunnable);
    109                 }
    110             }
    111         };
    112 
    113         mInflateWidgetRunnable = new Runnable() {
    114             @Override
    115             public void run() {
    116                 if (LOGD) {
    117                     Log.d(TAG, "Inflating widget, id: " + mWidgetLoadingId);
    118                 }
    119                 if (mWidgetLoadingId == -1) {
    120                     return;
    121                 }
    122                 AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
    123                         (Context) mLauncher, mWidgetLoadingId, pInfo);
    124                 mInfo.boundWidget = hostView;
    125 
    126                 // We used up the widget Id in binding the above view.
    127                 mWidgetLoadingId = -1;
    128 
    129                 hostView.setVisibility(View.INVISIBLE);
    130                 int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false);
    131                 // We want the first widget layout to be the correct size. This will be important
    132                 // for width size reporting to the AppWidgetManager.
    133                 DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
    134                         unScaledSize[1]);
    135                 lp.x = lp.y = 0;
    136                 lp.customPosition = true;
    137                 hostView.setLayoutParams(lp);
    138                 if (LOGD) {
    139                     Log.d(TAG, "Adding host view to drag layer");
    140                 }
    141                 mLauncher.getDragLayer().addView(hostView);
    142                 mView.setTag(mInfo);
    143             }
    144         };
    145 
    146         if (LOGD) {
    147             Log.d(TAG, "About to bind/inflate widget");
    148         }
    149         mHandler.post(mBindWidgetRunnable);
    150         return true;
    151     }
    152 
    153     public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
    154         Bundle options = null;
    155         Rect rect = new Rect();
    156         if (Utilities.ATLEAST_JB_MR1) {
    157             AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
    158             Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
    159                     info.componentName, null);
    160 
    161             float density = launcher.getResources().getDisplayMetrics().density;
    162             int xPaddingDips = (int) ((padding.left + padding.right) / density);
    163             int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
    164 
    165             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         }
    175         return options;
    176     }
    177 }
    178