1b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songpackage com.android.launcher3.widget;
2b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
3b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.appwidget.AppWidgetHostView;
4b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.appwidget.AppWidgetManager;
5b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.content.Context;
6b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.graphics.Rect;
7b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.os.Bundle;
8b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.os.Handler;
9a0628cc521614835933db74ba5a2536a936629c5Tony Wickhamimport android.util.Log;
10b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.view.View;
11b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
12b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport com.android.launcher3.AppWidgetResizeFrame;
1394b510cc683a6436ae82c6d323cbd8b429561b06Sunny Goyalimport com.android.launcher3.DropTarget;
14b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport com.android.launcher3.Launcher;
15b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport com.android.launcher3.LauncherAppWidgetProviderInfo;
16b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport com.android.launcher3.compat.AppWidgetManagerCompat;
179ccb94b6e4613ee717550416db2b456d9f17702eTony Wickhamimport com.android.launcher3.dragndrop.DragController;
18fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.dragndrop.DragLayer;
1994b510cc683a6436ae82c6d323cbd8b429561b06Sunny Goyalimport com.android.launcher3.dragndrop.DragOptions;
20316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyalimport com.android.launcher3.util.Thunk;
21b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
22a0628cc521614835933db74ba5a2536a936629c5Tony Wickhampublic class WidgetHostViewLoader implements DragController.DragListener {
23a0628cc521614835933db74ba5a2536a936629c5Tony Wickham    private static final String TAG = "WidgetHostViewLoader";
24a0628cc521614835933db74ba5a2536a936629c5Tony Wickham    private static final boolean LOGD = false;
25b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
26b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    /* Runnables to handle inflation and binding. */
275b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Thunk Runnable mInflateWidgetRunnable = null;
28b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    private Runnable mBindWidgetRunnable = null;
29b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
30b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    // TODO: technically, this class should not have to know the existence of the launcher.
31316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk Launcher mLauncher;
325b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Thunk Handler mHandler;
335b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Thunk final View mView;
345b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Thunk final PendingAddWidgetInfo mInfo;
355b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal
365b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    // Widget id generated for binding a widget host view or -1 for invalid id. The id is
375b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    // not is use as long as it is stored here and can be deleted safely. Once its used, this value
385b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    // to be set back to -1.
395b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Thunk int mWidgetLoadingId = -1;
40b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
415b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    public WidgetHostViewLoader(Launcher launcher, View view) {
42b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        mLauncher = launcher;
43b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        mHandler = new Handler();
445b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mView = view;
455b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mInfo = (PendingAddWidgetInfo) view.getTag();
46b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    }
47b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
485b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Override
498a0dc38aebdc7624db3de2cdfecb9d11e2baee04Sunny Goyal    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
508a0dc38aebdc7624db3de2cdfecb9d11e2baee04Sunny Goyal        preloadWidget();
518a0dc38aebdc7624db3de2cdfecb9d11e2baee04Sunny Goyal    }
52b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
535b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    @Override
545b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    public void onDragEnd() {
55a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        if (LOGD) {
56a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            Log.d(TAG, "Cleaning up in onDragEnd()...");
57a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        }
58a0628cc521614835933db74ba5a2536a936629c5Tony Wickham
595b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        // Cleanup up preloading state.
605b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mLauncher.getDragController().removeDragListener(this);
61b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
625b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mHandler.removeCallbacks(mBindWidgetRunnable);
635b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mHandler.removeCallbacks(mInflateWidgetRunnable);
64b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
655b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        // Cleanup widget id
665b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        if (mWidgetLoadingId != -1) {
675b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
685b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mWidgetLoadingId = -1;
695b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        }
70b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
715b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        // The widget was inflated and added to the DragLayer -- remove it.
725b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        if (mInfo.boundWidget != null) {
73a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            if (LOGD) {
74a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                Log.d(TAG, "...removing widget from drag layer");
75a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            }
765b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mLauncher.getDragLayer().removeView(mInfo.boundWidget);
775b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId());
785b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mInfo.boundWidget = null;
79b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        }
80b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    }
81b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
825b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal    /**
835b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal     * Start preloading the widget.
845b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal     */
858a0dc38aebdc7624db3de2cdfecb9d11e2baee04Sunny Goyal    private boolean preloadWidget() {
865b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
87b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
885b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        if (pInfo.isCustomWidget) {
895b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            return false;
905b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        }
915b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo);
92b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
93b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        // If there is a configuration activity, do not follow thru bound and inflate.
948a0dc38aebdc7624db3de2cdfecb9d11e2baee04Sunny Goyal        if (mInfo.getHandler().needsConfigure()) {
955b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mInfo.bindOptions = options;
96b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            return false;
97b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        }
985b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal
99b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        mBindWidgetRunnable = new Runnable() {
100b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            @Override
101b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            public void run() {
102b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
103a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                if (LOGD) {
104a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                    Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId);
105a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                }
106b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
107b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                        mWidgetLoadingId, pInfo, options)) {
1085b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal
1095b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                    // Widget id bound. Inflate the widget.
1105b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                    mHandler.post(mInflateWidgetRunnable);
111b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                }
112b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            }
113b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        };
114b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
115b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        mInflateWidgetRunnable = new Runnable() {
116b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            @Override
117b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            public void run() {
118a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                if (LOGD) {
119a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                    Log.d(TAG, "Inflating widget, id: " + mWidgetLoadingId);
120a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                }
1215b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                if (mWidgetLoadingId == -1) {
122b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                    return;
123b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                }
124b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
125b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                        (Context) mLauncher, mWidgetLoadingId, pInfo);
1265b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                mInfo.boundWidget = hostView;
1275b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal
1285b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                // We used up the widget Id in binding the above view.
1295b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                mWidgetLoadingId = -1;
130b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
1315b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                hostView.setVisibility(View.INVISIBLE);
132e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false, true);
133b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                // We want the first widget layout to be the correct size. This will be important
134b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                // for width size reporting to the AppWidgetManager.
135b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
136b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                        unScaledSize[1]);
137b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                lp.x = lp.y = 0;
138b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                lp.customPosition = true;
139b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                hostView.setLayoutParams(lp);
140a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                if (LOGD) {
141a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                    Log.d(TAG, "Adding host view to drag layer");
142a0628cc521614835933db74ba5a2536a936629c5Tony Wickham                }
143b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                mLauncher.getDragLayer().addView(hostView);
1445b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                mView.setTag(mInfo);
145b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            }
146b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        };
1475b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal
148a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        if (LOGD) {
149a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            Log.d(TAG, "About to bind/inflate widget");
150a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        }
1515b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        mHandler.post(mBindWidgetRunnable);
152b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        return true;
153b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    }
154b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
15516466f1bbb935d56c01b10551ead416feb7fc943Sunny Goyal    public static Bundle getDefaultOptionsForWidget(Context context, PendingAddWidgetInfo info) {
156a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        Rect rect = new Rect();
157a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        AppWidgetResizeFrame.getWidgetSizeRanges(context, info.spanX, info.spanY, rect);
158a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context,
159a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal                info.componentName, null);
160a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal
161a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        float density = context.getResources().getDisplayMetrics().density;
162a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        int xPaddingDips = (int) ((padding.left + padding.right) / density);
163a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
164a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal
165a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        Bundle options = new Bundle();
166a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
167a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal                rect.left - xPaddingDips);
168a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
169a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal                rect.top - yPaddingDips);
170a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
171a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal                rect.right - xPaddingDips);
172a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
173a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal                rect.bottom - yPaddingDips);
174b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        return options;
175b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    }
176b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song}
177