WidgetsContainerView.java revision 3f471440a8b6b71d4c15501a96befd3b715c9e8f
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.content.pm.PackageManager;
213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.Bitmap;
223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.Point;
233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.Rect;
243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.graphics.drawable.Drawable;
253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.support.v7.widget.LinearLayoutManager;
263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.support.v7.widget.RecyclerView;
273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.util.AttributeSet;
283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.util.Log;
293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.view.MotionEvent;
303f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.view.View;
313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.widget.FrameLayout;
323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport android.widget.ImageView;
333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.CellLayout;
353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DeleteDropTarget;
363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DragController;
373f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DragSource;
383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.DropTarget.DragObject;
393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.FastBitmapDrawable;
403f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Folder;
413f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.IconCache;
423f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Insettable;
433f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.ItemInfo;
443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Launcher;
453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.LauncherAppState;
463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.PendingAddItemInfo;
473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.R;
483f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Utilities;
493f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.WidgetPreviewLoader;
503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.Workspace;
513f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
523f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport java.util.ArrayList;
533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song/**
553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song * The widgets list view container.
563f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song */
573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songpublic class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
583f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        View.OnLongClickListener, DragSource{
593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private static final String TAG = "WidgetContainerView";
613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private static final boolean DEBUG = false;
623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* {@link RecyclerView} will keep following # of views in cache, before recycling. */
643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private static final int WIDGET_CACHE_SIZE = 2;
653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Global instances that are used inside this container. */
673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private Launcher mLauncher;
683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private DragController mDragController;
693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private IconCache mIconCache;
703f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Data model for the widget */
723f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetsModel mWidgets;
733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
743f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Recycler view related member variables */
753f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private RecyclerView mView;
763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetsListAdapter mAdapter;
773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Dragging related. */
793f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private boolean mDraggingWidget = false;    // TODO(hyunyoungs): seems not needed? check!
803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private Point mLastTouchDownPos = new Point();
813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /* Rendering related. */
833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetPreviewLoader mWidgetPreviewLoader;
843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private Rect mPadding = new Rect();
853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context) {
873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        this(context, null);
883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context, AttributeSet attrs) {
913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        this(context, attrs, 0);
923f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
933f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
943f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        this(context, attrs, defStyleAttr, 0);
963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
993f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        super(context, attrs, defStyleAttr);
1003f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher = (Launcher) context;
1013f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mDragController = mLauncher.getDragController();
1023f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1033f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
1043f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mWidgets = new WidgetsModel(context, mAdapter);
1053f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mAdapter.setWidgetsModel(mWidgets);
1063f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mIconCache = (LauncherAppState.getInstance()).getIconCache();
1073f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1083f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (DEBUG) {
1093f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, "WidgetsContainerView constructor");
1103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1123f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1133f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
1143f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    protected void onFinishInflate() {
1153f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (DEBUG) {
1163f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, String.format("onFinishInflate [widgets size=%d]",
1173f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    mWidgets.getPackageSize()));
1183f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1193f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mView = (RecyclerView) findViewById(R.id.widgets_list_view);
1203f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mView.setAdapter(mAdapter);
1213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mView.setLayoutManager(new LinearLayoutManager(getContext()));
1223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mView.setItemViewCacheSize(WIDGET_CACHE_SIZE);
1233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
1253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                getPaddingBottom());
1263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Returns views used for launcher transitions.
1303f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public View getContentView() {
1333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return findViewById(R.id.widgets_list_view);
1343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public View getRevealView() {
1373f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // TODO(hyunyoungs): temporarily use apps view transition.
1383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return findViewById(R.id.widgets_reveal_view);
1393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1403f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1413f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void scrollToTop() {
1423f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mView.scrollToPosition(0);
1433f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (DEBUG) {
1443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, String.format("scrollToTop, [widgets size=%d]",
1453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    mWidgets.getPackageSize()));
1463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1483f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1493f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Touch related handling.
1513f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
1523f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
1543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean onLongClick(View v) {
1553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (DEBUG) {
1563f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.d(TAG, String.format("onLonglick [v=%s]", v));
1573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1583f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Return early if this is not initiated from a touch
1603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!v.isInTouchMode()) return false;
1613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // When we have exited all apps or are in transition, disregard long clicks
1623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!mLauncher.isWidgetsViewVisible() ||
1633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                mLauncher.getWorkspace().isSwitchingState()) return false;
1643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Return if global dragging is not enabled
1653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
1663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!mLauncher.isDraggingEnabled()) return false;
1673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return beginDragging(v);
1693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1703f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private boolean beginDragging(View v) {
1723f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (v instanceof WidgetCell) {
1733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (!beginDraggingWidget((WidgetCell) v)) {
1743f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                return false;
1753f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
1763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        } else {
1773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            Log.e(TAG, "Unexpected dragging view: " + v);
1783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
1793f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // We delay entering spring-loaded mode slightly to make sure the UI
1813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // thready is free of any work.
1823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        postDelayed(new Runnable() {
1833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            @Override
1843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            public void run() {
1853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                // We don't enter spring-loaded mode if the drag has been cancelled
1863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                if (mLauncher.getDragController().isDragging()) {
1873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    // Go into spring loaded mode (must happen before we startDrag())
1883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    mLauncher.enterSpringLoadedDragMode();
1893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                }
1903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
1913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }, 150);
1923f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1933f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
1943f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
1953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
1963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private boolean beginDraggingWidget(WidgetCell v) {
1973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mDraggingWidget = true;
1983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Get the widget preview as the drag representation
1993f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
2003f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
2013f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2023f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
2033f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // we abort the drag.
2043f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (image.getDrawable() == null) {
2053f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mDraggingWidget = false;
2063f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            return false;
2073f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
2083f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2093f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Compose the drag image
2103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Bitmap preview;
2113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Bitmap outline;
2123f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        float scale = 1f;
2133f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Point previewPadding = null;
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
2223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
2233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            float minScale = 1.25f;
2243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
2253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            int[] previewSizeBeforeScale = new int[1];
2273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
2283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    maxWidth, null, previewSizeBeforeScale);
2293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // Compare the size of the drag preview to the preview in the AppsCustomize tray
2303f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
2313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    v.getActualItemWidth());
2323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
2333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // The bitmap in the AppsCustomize tray is always the the same size, so there
2353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // might be extra pixels around the preview itself - this accounts for that
2363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
2373f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                int padding =
2383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
2393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                previewPadding = new Point(padding, 0);
2403f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
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;
2463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
2473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2483f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Don't clip alpha values for the drag outline if we're using the default widget preview
2493f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
2503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
2513f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2523f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Save the preview for the outline generation, then dim the preview
2533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
2543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                false);
2553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2563f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Start the drag
2573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.lockScreenOrientation();
2583f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
2593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mDragController.startDrag(image, preview, this, createItemInfo,
2603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                DragController.DRAG_ACTION_COPY, previewPadding, scale);
2613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        outline.recycle();
2623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        preview.recycle();
2633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
2643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /*
2673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
2683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
2693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2703f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean onTouch(View v, MotionEvent ev) {
2713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
2723f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (ev.getAction() == MotionEvent.ACTION_DOWN ||
2733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                ev.getAction() == MotionEvent.ACTION_MOVE) {
2743f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
2753f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
2763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return false;
2773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2793f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
2803f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Drag related handling methods that implement {@link DragSource} interface.
2813f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
2823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2843f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsFlingToDelete() {
2853f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return false;
2863f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2873f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsAppInfoDropTarget() {
2903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return true;
2913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
2923f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
2933f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /*
2943f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
2953f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * {@link DeleteDropTarget} to be invisible.)
2963f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
2973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
2983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean supportsDeleteDropTarget() {
2993f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return false;
3003f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3013f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3023f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
3033f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public float getIntrinsicIconScaleFactor() {
3043f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return 0;
3053f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3063f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3073f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
3083f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void onFlingToDeleteCompleted() {
3093f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // We just dismiss the drag when we fling, so cleanup here
3103f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.exitSpringLoadedDragModeDelayed(true,
3113f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
3123f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.unlockScreenOrientation(false);
3133f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3143f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3153f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
3163f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
3173f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            boolean success) {
3183f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
3193f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
3203f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // Exit spring loaded mode if we have not successfully dropped or have not handled the
3213f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            // drop in Workspace
3223f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mLauncher.exitSpringLoadedDragModeDelayed(true,
3233f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
3243f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3253f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mLauncher.unlockScreenOrientation(false);
3263f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3273f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // Display an error message if the drag failed due to there not being enough space on the
3283f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        // target layout we were dropping on.
3293f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (!success) {
3303f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            boolean showOutOfSpaceMessage = false;
3313f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (target instanceof Workspace) {
3323f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
3333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                Workspace workspace = (Workspace) target;
3343f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
3353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
3363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                if (layout != null) {
3373f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    layout.calculateSpans(itemInfo);
3383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                    showOutOfSpaceMessage =
3393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
3403f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                }
3413f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
3423f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            if (showOutOfSpaceMessage) {
3433f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                mLauncher.showOutOfSpaceMessage(false);
3443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            }
3453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            d.deferDragViewCleanupPostAnimation = false;
3463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3483f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3493f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
3503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    // Container rendering related.
3513f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    //
3523f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /*
3543f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * @see Insettable#setInsets(Rect)
3553f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
3563f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    @Override
3573f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void setInsets(Rect insets) {
3583f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
3593f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song                mPadding.right + insets.right, mPadding.bottom + insets.bottom);
3603f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3613f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3623f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    /**
3633f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     * Initialize the widget data model.
3643f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song     */
3653f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public void addWidgets(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
3663f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        mWidgets.addWidgetsAndShortcuts(widgetsShortcuts, pm);
3673f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3683f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3693f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    private WidgetPreviewLoader getWidgetPreviewLoader() {
3703f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        if (mWidgetPreviewLoader == null) {
3713f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
3723f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        }
3733f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song        return mWidgetPreviewLoader;
3743f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    }
3753f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song
3763f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song}