13f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song/*
23f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * Copyright (C) 2015 The Android Open Source Project
33f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song *
43f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * Licensed under the Apache License, Version 2.0 (the "License");
53f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * you may not use this file except in compliance with the License.
63f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * You may obtain a copy of the License at
73f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song *
83f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song *      http://www.apache.org/licenses/LICENSE-2.0
93f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song *
103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * Unless required by applicable law or agreed to in writing, software
113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * distributed under the License is distributed on an "AS IS" BASIS,
123f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * See the License for the specific language governing permissions and
143f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * limitations under the License.
153f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song */
163f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
173f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songpackage com.android.launcher3.widget;
183f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
193f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.content.Context;
203f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.Bitmap;
213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.Rect;
223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.drawable.Drawable;
233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.support.v7.widget.LinearLayoutManager;
24e809332032c8f0c2f361eb8fc753f3b57d9cfaaaHyunyoung Songimport android.support.v7.widget.RecyclerView.State;
253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.util.AttributeSet;
263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.util.Log;
273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.view.View;
289600d20110861db08f0db21358161dc0ae6b2037Sunny Goyalimport android.view.ViewGroup;
29b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Songimport android.widget.Toast;
30f52abd7758b8f245522936e941336e574debabf5Sunny Goyal
319480415d9baf00ecfaac8ab3f608b16a1faa6518Winson Chungimport com.android.launcher3.BaseContainerView;
323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.CellLayout;
333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DeleteDropTarget;
343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DragSource;
353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DropTarget.DragObject;
3694b510cc683a6436ae82c6d323cbd8b429561b06Sunny Goyalimport com.android.launcher3.dragndrop.DragOptions;
37261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.folder.Folder;
383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.IconCache;
393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.ItemInfo;
403f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Launcher;
413f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.LauncherAppState;
423f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.PendingAddItemInfo;
433f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.R;
443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Utilities;
453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.WidgetPreviewLoader;
463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Workspace;
47fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.dragndrop.DragController;
4858376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyalimport com.android.launcher3.model.WidgetsModel;
4959a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Songimport com.android.launcher3.userevent.nano.LauncherLogProto;
5059a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Songimport com.android.launcher3.userevent.nano.LauncherLogProto.Target;
51316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyalimport com.android.launcher3.util.Thunk;
520ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Mirandaimport com.android.launcher3.util.TransformingTouchDelegate;
533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song/**
553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * The widgets list view container.
563f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song */
579480415d9baf00ecfaac8ab3f608b16a1faa6518Winson Chungpublic class WidgetsContainerView extends BaseContainerView
58a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        implements View.OnLongClickListener, View.OnClickListener, DragSource {
59b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    private static final String TAG = "WidgetsContainerView";
60a0628cc521614835933db74ba5a2536a936629c5Tony Wickham    private static final boolean LOGD = false;
613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Global instances that are used inside this container. */
63316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk Launcher mLauncher;
643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private DragController mDragController;
653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private IconCache mIconCache;
663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
671f06427266c0cb5de4561fc7c620ff542f625300Winson    private final Rect mTmpBgPaddingRect = new Rect();
681f06427266c0cb5de4561fc7c620ff542f625300Winson
693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Recycler view related member variables */
70a6194d3d9205488d6f5400193f8d4d6aaf140218Sunny Goyal    private WidgetsRecyclerView mRecyclerView;
713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetsListAdapter mAdapter;
720ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda    private TransformingTouchDelegate mRecyclerViewTouchDelegate;
733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
74b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    /* Touch handling related member variables. */
75b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    private Toast mWidgetInstructionToast;
763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Rendering related. */
783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetPreviewLoader mWidgetPreviewLoader;
79b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context) {
813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        this(context, null);
823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context, AttributeSet attrs) {
853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        this(context, attrs, 0);
863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        super(context, attrs, defStyleAttr);
90abef55a1c1f1fda4f42e4b4223534dd21f3dc19fAndrew Sapperstein        mLauncher = Launcher.getLauncher(context);
913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mDragController = mLauncher.getDragController();
92abef55a1c1f1fda4f42e4b4223534dd21f3dc19fAndrew Sapperstein        mAdapter = new WidgetsListAdapter(this, this, context);
933f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mIconCache = (LauncherAppState.getInstance()).getIconCache();
94a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        if (LOGD) {
953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, "WidgetsContainerView constructor");
963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
993f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
1000ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1010ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        super.onLayout(changed, left, top, right, bottom);
1020ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        getRevealView().getBackground().getPadding(mTmpBgPaddingRect);
1030ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        mRecyclerViewTouchDelegate.setBounds(
1040ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda                mRecyclerView.getLeft() - mTmpBgPaddingRect.left,
1050ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda                mRecyclerView.getTop() - mTmpBgPaddingRect.top,
1060ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda                mRecyclerView.getRight() + mTmpBgPaddingRect.right,
1070ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda                mRecyclerView.getBottom() + mTmpBgPaddingRect.bottom);
1080ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda    }
1090ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda
1100ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda    @Override
1113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    protected void onFinishInflate() {
112a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        super.onFinishInflate();
113a6194d3d9205488d6f5400193f8d4d6aaf140218Sunny Goyal        mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
114a6194d3d9205488d6f5400193f8d4d6aaf140218Sunny Goyal        mRecyclerView.setAdapter(mAdapter);
115b7271fd17ea78acbf8506b2c9a34f741680fc4a9Hyunyoung Song        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
1160ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        mRecyclerViewTouchDelegate = new TransformingTouchDelegate(mRecyclerView);
1171f06427266c0cb5de4561fc7c620ff542f625300Winson    }
11805c8c57fa72a81f34058036f6dc30c084ca6742bSunny Goyal
1191f06427266c0cb5de4561fc7c620ff542f625300Winson    @Override
1200ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda    protected void onAttachedToWindow() {
1210ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        super.onAttachedToWindow();
1220ef81fdc2265c764d6ebd57cf44d4a0bd15132b7Jon Miranda        ((View) mRecyclerView.getParent()).setTouchDelegate(mRecyclerViewTouchDelegate);
1233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Returns views used for launcher transitions.
1273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void scrollToTop() {
130a6194d3d9205488d6f5400193f8d4d6aaf140218Sunny Goyal        mRecyclerView.scrollToPosition(0);
1313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Touch related handling.
1353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1373f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
138b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    public void onClick(View v) {
139b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        // When we have exited widget tray or are in transition, disregard clicks
140b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        if (!mLauncher.isWidgetsViewVisible()
141b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                || mLauncher.getWorkspace().isSwitchingState()
142b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song                || !(v instanceof WidgetCell)) return;
143b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
144b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        // Let the user know that they have to long press to add a widget
145b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        if (mWidgetInstructionToast != null) {
146b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song            mWidgetInstructionToast.cancel();
147b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        }
148e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal
149e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal        CharSequence msg = Utilities.wrapForTts(
150e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal                getContext().getText(R.string.long_press_widget_to_add),
151e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal                getContext().getString(R.string.long_accessible_way_to_add));
152e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal        mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
153b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        mWidgetInstructionToast.show();
154b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    }
155b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song
156b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song    @Override
1573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean onLongClick(View v) {
158a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        if (LOGD) {
1593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, String.format("onLonglick [v=%s]", v));
1603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Return early if this is not initiated from a touch
1623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!v.isInTouchMode()) return false;
1633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // When we have exited all apps or are in transition, disregard long clicks
1643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!mLauncher.isWidgetsViewVisible() ||
1653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                mLauncher.getWorkspace().isSwitchingState()) return false;
1663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Return if global dragging is not enabled
1673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!mLauncher.isDraggingEnabled()) return false;
1683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
169b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        boolean status = beginDragging(v);
1705b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal        if (status && v.getTag() instanceof PendingAddWidgetInfo) {
1715b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            WidgetHostViewLoader hostLoader = new WidgetHostViewLoader(mLauncher, v);
1725b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            boolean preloadStatus = hostLoader.preloadWidget();
173a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            if (LOGD) {
1745b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal                Log.d(TAG, String.format("preloading widget [status=%s]", preloadStatus));
1755b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            }
1765b9ebcab3c6c55dcb7575fdbcb77020a5ad274d4Sunny Goyal            mLauncher.getDragController().addDragListener(hostLoader);
177b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        }
178b99ff3e83270e113f6182e337c4f7b0223bad92bHyunyoung Song        return status;
1793f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private boolean beginDragging(View v) {
1823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (v instanceof WidgetCell) {
1833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (!beginDraggingWidget((WidgetCell) v)) {
1843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                return false;
1853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
1863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        } else {
1873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.e(TAG, "Unexpected dragging view: " + v);
1883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
19058376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyal        // We don't enter spring-loaded mode if the drag has been cancelled
19158376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyal        if (mLauncher.getDragController().isDragging()) {
19258376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyal            // Go into spring loaded mode (must happen before we startDrag())
19358376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyal            mLauncher.enterSpringLoadedDragMode();
19458376925f9596c23f5c9ffa6c99630dfddcfce9cSunny Goyal        }
1953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
1973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1993f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private boolean beginDraggingWidget(WidgetCell v) {
2003f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Get the widget preview as the drag representation
201f52abd7758b8f245522936e941336e574debabf5Sunny Goyal        WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview);
2023f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
2033f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2043f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
2053f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // we abort the drag.
206f52abd7758b8f245522936e941336e574debabf5Sunny Goyal        if (image.getBitmap() == null) {
2073f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            return false;
2083f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
2093f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Compose the drag image
2113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Bitmap preview;
21206e21a25877db7207b5393ab163028bb4116df4fSunny Goyal        final float scale;
213f52abd7758b8f245522936e941336e574debabf5Sunny Goyal        final Rect bounds = image.getBitmapBounds();
2143f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2153f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (createItemInfo instanceof PendingAddWidgetInfo) {
2163f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // This can happen in some weird cases involving multi-touch. We can't start dragging
2173f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // the widget if this is null, so we break out.
2183f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2193f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
2203f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
2213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
222f52abd7758b8f245522936e941336e574debabf5Sunny Goyal            Bitmap icon = image.getBitmap();
2233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            float minScale = 1.25f;
224f52abd7758b8f245522936e941336e574debabf5Sunny Goyal            int maxWidth = Math.min((int) (icon.getWidth() * minScale), size[0]);
2253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            int[] previewSizeBeforeScale = new int[1];
2272e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen            preview = getWidgetPreviewLoader().generateWidgetPreview(mLauncher,
2282e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                    createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale);
229f52abd7758b8f245522936e941336e574debabf5Sunny Goyal
230f52abd7758b8f245522936e941336e574debabf5Sunny Goyal            if (previewSizeBeforeScale[0] < icon.getWidth()) {
231f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                // The icon has extra padding around it.
232f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                int padding = (icon.getWidth() - previewSizeBeforeScale[0]) / 2;
233f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                if (icon.getWidth() > image.getWidth()) {
234f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                    padding = padding * image.getWidth() / icon.getWidth();
235f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                }
236f52abd7758b8f245522936e941336e574debabf5Sunny Goyal
237f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                bounds.left += padding;
238f52abd7758b8f245522936e941336e574debabf5Sunny Goyal                bounds.right -= padding;
2393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
240f52abd7758b8f245522936e941336e574debabf5Sunny Goyal            scale = bounds.width() / (float) preview.getWidth();
2413f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        } else {
2423f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
2433f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
2443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            preview = Utilities.createIconBitmap(icon, mLauncher);
2453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            createItemInfo.spanX = createItemInfo.spanY = 1;
24653d7ee4285842732517edcccbdcaa92dccb1e107Sunny Goyal            scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
2473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
2483f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
24906e21a25877db7207b5393ab163028bb4116df4fSunny Goyal        // Since we are not going through the workspace for starting the drag, set drag related
25006e21a25877db7207b5393ab163028bb4116df4fSunny Goyal        // information on the workspace before starting the drag.
25106e21a25877db7207b5393ab163028bb4116df4fSunny Goyal        mLauncher.getWorkspace().prepareDragWithProvider(
25206e21a25877db7207b5393ab163028bb4116df4fSunny Goyal                new PendingItemPreviewProvider(v, createItemInfo, preview));
2533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Start the drag
2553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mDragController.startDrag(image, preview, this, createItemInfo,
25694b510cc683a6436ae82c6d323cbd8b429561b06Sunny Goyal                bounds, scale, new DragOptions());
2573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
2583f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
2613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Drag related handling methods that implement {@link DragSource} interface.
2623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
2633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsFlingToDelete() {
2669aae47f8a6e23f1805ee3d44512fc1f80286e6ddTony Wickham        return true;
2673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2703f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsAppInfoDropTarget() {
2713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
2723f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2743f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /*
2753f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
2763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * {@link DeleteDropTarget} to be invisible.)
2773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
2783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2793f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsDeleteDropTarget() {
2803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return false;
2813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public float getIntrinsicIconScaleFactor() {
2853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return 0;
2863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void onFlingToDeleteCompleted() {
2903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // We just dismiss the drag when we fling, so cleanup here
2913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.exitSpringLoadedDragModeDelayed(true,
2923f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
2933f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.unlockScreenOrientation(false);
2943f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
2983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            boolean success) {
299a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        if (LOGD) {
300a0628cc521614835933db74ba5a2536a936629c5Tony Wickham            Log.d(TAG, "onDropCompleted");
301a0628cc521614835933db74ba5a2536a936629c5Tony Wickham        }
3023f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
3033f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
3043f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // Exit spring loaded mode if we have not successfully dropped or have not handled the
3053f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // drop in Workspace
3063f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mLauncher.exitSpringLoadedDragModeDelayed(true,
3073f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
3083f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3093f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.unlockScreenOrientation(false);
3103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Display an error message if the drag failed due to there not being enough space on the
3123f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // target layout we were dropping on.
3133f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!success) {
3143f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            boolean showOutOfSpaceMessage = false;
3153f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (target instanceof Workspace) {
3163f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
3173f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                Workspace workspace = (Workspace) target;
3183f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
319aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal                ItemInfo itemInfo = d.dragInfo;
3203f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                if (layout != null) {
3213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    showOutOfSpaceMessage =
3223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
3233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                }
3243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
3253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (showOutOfSpaceMessage) {
3263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                mLauncher.showOutOfSpaceMessage(false);
3273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
3283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            d.deferDragViewCleanupPostAnimation = false;
3293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3303f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /**
3333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * Initialize the widget data model.
3343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
3352bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song    public void addWidgets(WidgetsModel model) {
336a6194d3d9205488d6f5400193f8d4d6aaf140218Sunny Goyal        mRecyclerView.setWidgets(model);
3372bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song        mAdapter.setWidgetsModel(model);
3382bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song        mAdapter.notifyDataSetChanged();
3399600d20110861db08f0db21358161dc0ae6b2037Sunny Goyal
3409600d20110861db08f0db21358161dc0ae6b2037Sunny Goyal        View loader = getContentView().findViewById(R.id.loader);
3419600d20110861db08f0db21358161dc0ae6b2037Sunny Goyal        if (loader != null) {
3429600d20110861db08f0db21358161dc0ae6b2037Sunny Goyal            ((ViewGroup) getContentView()).removeView(loader);
3439600d20110861db08f0db21358161dc0ae6b2037Sunny Goyal        }
3443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3462e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal    public boolean isEmpty() {
3472e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal        return mAdapter.getItemCount() == 0;
3482e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal    }
3492e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal
3503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetPreviewLoader getWidgetPreviewLoader() {
3513f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (mWidgetPreviewLoader == null) {
3523f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
3533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return mWidgetPreviewLoader;
3553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
35659a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Song
35759a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Song    @Override
35859a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Song    public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
35959a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Song        targetParent.containerType = LauncherLogProto.WIDGETS;
36059a238095e82fd02355f4cb53abe01655a50b051Hyunyoung Song    }
3613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song}