Folder.java revision f3007589e346df224d357b389069adfeb266545e
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.animation.Animator;
20df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.animation.AnimatorListenerAdapter;
21df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.animation.ObjectAnimator;
22df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.animation.PropertyValuesHolder;
2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.content.res.Resources;
25043f2af567178b82b0b41f12d379e7dd12da2936Winson Chungimport android.graphics.PointF;
26fb5411e98278d461b78aea0663d3e85f7a9e8a15Romain Guyimport android.graphics.Rect;
27badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohenimport android.graphics.drawable.Drawable;
287a14d0bddea652ddca855af0c413e47a6c1360b2Adam Cohenimport android.text.InputType;
29e601a43345224e3e386abc68bbea8b08b2df9570Adam Cohenimport android.text.Selection;
30e601a43345224e3e386abc68bbea8b08b2df9570Adam Cohenimport android.text.Spannable;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
323bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohenimport android.util.Log;
3376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.ActionMode;
3476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.KeyEvent;
35df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.view.LayoutInflater;
3676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.Menu;
3776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.MenuItem;
380c872ba544ecfd9b106bb66137da8680927590deAdam Cohenimport android.view.MotionEvent;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityEvent;
413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityManager;
422e7471cf96bb8d9d02a9f2010ec198d585363dd7Mindy DelliCarpiniimport android.view.animation.AccelerateInterpolator;
432e7471cf96bb8d9d02a9f2010ec198d585363dd7Mindy DelliCarpiniimport android.view.animation.Interpolator;
4476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.inputmethod.EditorInfo;
4576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.inputmethod.InputMethodManager;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.LinearLayout;
47f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohenimport android.widget.ScrollView;
48df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.widget.TextView;
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
50325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.FolderInfo.FolderListener;
51edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy
52c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
533bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohenimport java.util.Collections;
543bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohenimport java.util.Comparator;
55c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
5731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Represents a set of icons chosen by the user or generated by the system.
5831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
598dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohenpublic class Folder extends LinearLayout implements DragSource, View.OnClickListener,
60ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
61ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        View.OnFocusChangeListener {
624eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen    private static final String TAG = "Launcher.Folder";
63df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
644eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen    protected DragController mDragController;
6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected Launcher mLauncher;
6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected FolderInfo mInfo;
6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
68df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_NONE = -1;
69df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_SMALL = 0;
70df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_ANIMATING = 1;
71df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_OPEN = 2;
72df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
73df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private int mExpandDuration;
74df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    protected CellLayout mContent;
75f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private ScrollView mScrollView;
76df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private final LayoutInflater mInflater;
77df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private final IconCache mIconCache;
78df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private int mState = STATE_NONE;
79bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 230;
80f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private static final int REORDER_DELAY = 250;
81bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private static final int ON_EXIT_CLOSE_DELAY = 800;
822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private boolean mRearrangeOnClose = false;
832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private FolderIcon mFolderIcon;
842801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private int mMaxCountX;
852801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private int mMaxCountY;
86f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mMaxVisibleX;
87f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mMaxVisibleY;
88f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mMaxContentAreaHeight = 0;
8978dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen    private int mMaxNumItems;
907c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
91badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    private Drawable mIconDrawable;
927c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    boolean mItemsInvalidated = false;
93bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private ShortcutInfo mCurrentDragInfo;
94bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private View mCurrentDragView;
95bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    boolean mSuppressOnAdd = false;
96bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mTargetCell = new int[2];
97bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mPreviousTargetCell = new int[2];
98bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mEmptyCell = new int[2];
99bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private Alarm mReorderAlarm = new Alarm();
100bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private Alarm mOnExitAlarm = new Alarm();
10176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private int mFolderNameHeight;
1028e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen    private Rect mTempRect = new Rect();
10367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mDragInProgress = false;
10467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mDeleteFolderOnDropCompleted = false;
10567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mSuppressFolderDeletion = false;
10605e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen    private boolean mItemAddedBackToSelfViaIcon = false;
107ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    FolderEditText mFolderName;
108268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    private float mFolderIconPivotX;
109268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    private float mFolderIconPivotY;
110228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohen
111f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private static final int SCROLL_CUT_OFF_AMOUNT = 60;
1122e7471cf96bb8d9d02a9f2010ec198d585363dd7Mindy DelliCarpini
11353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini    private static final float MAX_SCROLL_VELOCITY = 1500f;
114f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
11576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean mIsEditingName = false;
11676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private InputMethodManager mInputMethodManager;
117df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
118a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen    private static String sDefaultFolderName;
119a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen    private static String sHintText;
120a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
121f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int DRAG_MODE_NONE = 0;
122f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int DRAG_MODE_REORDER = 1;
123f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mDragMode = DRAG_MODE_NONE;
124f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
125fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private boolean mDestroyed;
126fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
12753b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini    private AutoScroller mAutoScroller;
12853b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini
1291e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    private Runnable mDeferredAction;
1301e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    private boolean mDeferDropAfterUninstall;
1311e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    private boolean mUninstallSuccessful;
1321e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka
13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to inflate the Workspace from XML.
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
13631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param attrs The attribtues set containing the Workspace's customization values.
13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
13931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public Folder(Context context, AttributeSet attrs) {
14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
1415f8afe6280eae34620067696173e71943e1a30a3Winson Chung
1425f8afe6280eae34620067696173e71943e1a30a3Winson Chung        LauncherAppState app = LauncherAppState.getInstance();
1435f8afe6280eae34620067696173e71943e1a30a3Winson Chung        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
145df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mInflater = LayoutInflater.from(context);
1465f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mIconCache = app.getIconCache();
14778dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen
14878dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        Resources res = getResources();
1495f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mMaxCountX = mMaxVisibleX = mMaxVisibleY = (int) (grid.numColumns);
1505f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mMaxCountY = mMaxNumItems = Integer.MAX_VALUE;
15176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
15276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mInputMethodManager = (InputMethodManager)
1538b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
15476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
15576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration);
1564ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen
1574ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        if (sDefaultFolderName == null) {
1584ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            sDefaultFolderName = res.getString(R.string.folder_name);
1594ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        }
160a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        if (sHintText == null) {
161a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen            sHintText = res.getString(R.string.folder_hint_text);
162a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        }
1634eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen        mLauncher = (Launcher) context;
164ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // We need this view to be focusable in touch mode so that when text editing of the folder
165ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // name is complete, we have something to focus on, thus hiding the cursor and giving
166ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // reliable behvior when clicking the text field (since it will always gain focus on click).
167ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        setFocusableInTouchMode(true);
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onFinishInflate() {
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onFinishInflate();
173f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mScrollView = (ScrollView) findViewById(R.id.scroll_view);
174df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mContent = (CellLayout) findViewById(R.id.folder_content);
175f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
1765f8afe6280eae34620067696173e71943e1a30a3Winson Chung        LauncherAppState app = LauncherAppState.getInstance();
1775f8afe6280eae34620067696173e71943e1a30a3Winson Chung        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
1785f8afe6280eae34620067696173e71943e1a30a3Winson Chung
179f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        // Beyond this height, the area scrolls
1805f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mContent.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
181f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mContent.setGridSize(mMaxVisibleX, mMaxVisibleY);
182f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mMaxContentAreaHeight = mContent.getDesiredHeight() - SCROLL_CUT_OFF_AMOUNT;
1832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mContent.setGridSize(0, 0);
184a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
1852374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        mContent.setInvertIfRtl(true);
186ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderName = (FolderEditText) findViewById(R.id.folder_name);
187ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderName.setFolder(this);
188ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        mFolderName.setOnFocusChangeListener(this);
18976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
19076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // We find out how tall the text view wants to be (it is set to wrap_content), so that
19176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // we can allocate the appropriate amount of space for it.
19276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        int measureSpec = MeasureSpec.UNSPECIFIED;
19376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.measure(measureSpec, measureSpec);
19476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderNameHeight = mFolderName.getMeasuredHeight();
19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
19676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // We disable action mode for now since it messes up the view on phones
19776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback);
19876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.setOnEditorActionListener(this);
1994ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        mFolderName.setSelectAllOnFocus(true);
2007a14d0bddea652ddca855af0c413e47a6c1360b2Adam Cohen        mFolderName.setInputType(mFolderName.getInputType() |
2017a14d0bddea652ddca855af0c413e47a6c1360b2Adam Cohen                InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
20253b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        mAutoScroller = new AutoScroller(mScrollView);
20353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        mAutoScroller.setMaximumVelocityAbsolute(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY);
20453b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        mAutoScroller.setExtendsBeyondEdges(false);
20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
20776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
20876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
20976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
21076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
21176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
21276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
21376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
21476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
21576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
21676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public void onDestroyActionMode(ActionMode mode) {
21776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
21876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
21976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
22076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
22176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
22276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    };
22376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
22431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public void onClick(View v) {
225df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        Object tag = v.getTag();
226df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (tag instanceof ShortcutInfo) {
227b5fe60c8a502fb7e265e3183550478b2b2a49264Adam Cohen            mLauncher.onClick(v);
228df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
23031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
23131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onLongClick(View v) {
23236a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung        // Return if global dragging is not enabled
23336a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung        if (!mLauncher.isDraggingEnabled()) return true;
23436a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung
235df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        Object tag = v.getTag();
236df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (tag instanceof ShortcutInfo) {
237df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            ShortcutInfo item = (ShortcutInfo) tag;
238df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            if (!v.isInTouchMode()) {
239df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                return false;
240df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
241df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
2427d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung            mLauncher.dismissFolderCling(null);
2437d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
244df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            mLauncher.getWorkspace().onDragStartedWithItem(v);
245ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            mLauncher.getWorkspace().beginDragShared(v, this);
246badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen            mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
24776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
24876078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen            mCurrentDragInfo = item;
249bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mEmptyCell[0] = item.cellX;
250bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mEmptyCell[1] = item.cellY;
251bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mCurrentDragView = v;
252fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
253fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            mContent.removeView(mCurrentDragView);
254fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            mInfo.remove(mCurrentDragInfo);
25567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            mDragInProgress = true;
25605e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            mItemAddedBackToSelfViaIcon = false;
257df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
25831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return true;
25931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
26031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean isEditingName() {
26276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return mIsEditingName;
26376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
26476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
26576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void startEditingFolderName() {
266a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mFolderName.setHint("");
26776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mIsEditingName = true;
26876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
26976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
27076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void dismissEditingName() {
27176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
27276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        doneEditingFolderName(true);
27376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
27476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
27576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void doneEditingFolderName(boolean commit) {
276a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mFolderName.setHint(sHintText);
2771df26a368a135395b7bd61e9b109044b33b1b0beAdam Cohen        // Convert to a string here to ensure that no other state associated with the text field
2781df26a368a135395b7bd61e9b109044b33b1b0beAdam Cohen        // gets saved.
2793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        String newTitle = mFolderName.getText().toString();
2803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        mInfo.setTitle(newTitle);
28176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        LauncherModel.updateItemInDatabase(mLauncher, mInfo);
282ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
2833371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (commit) {
2843371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
2858b805b17158886035b38261eb611d8641701ae43Michael Jurka                    String.format(getContext().getString(R.string.folder_renamed), newTitle));
2863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
287ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // In order to clear the focus from the text field, we set the focus on ourself. This
288ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // ensures that every time the field is clicked, focus is gained, giving reliable behavior.
289ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        requestFocus();
290ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
291e601a43345224e3e386abc68bbea8b08b2df9570Adam Cohen        Selection.setSelection((Spannable) mFolderName.getText(), 0, 0);
29276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mIsEditingName = false;
29376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
29476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
29576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
29676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        if (actionId == EditorInfo.IME_ACTION_DONE) {
29776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            dismissEditingName();
29876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return true;
29976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
30076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return false;
30176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
30276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
30376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public View getEditTextRegion() {
30476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return mFolderName;
30576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
30676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
307badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    public Drawable getDragDrawable() {
308badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen        return mIconDrawable;
309badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    }
310badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
3110c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    /**
3120c872ba544ecfd9b106bb66137da8680927590deAdam Cohen     * We need to handle touch events to prevent them from falling through to the workspace below.
3130c872ba544ecfd9b106bb66137da8680927590deAdam Cohen     */
3140c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    @Override
3150c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    public boolean onTouchEvent(MotionEvent ev) {
3160c872ba544ecfd9b106bb66137da8680927590deAdam Cohen        return true;
3170c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    }
3180c872ba544ecfd9b106bb66137da8680927590deAdam Cohen
31900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void setDragController(DragController dragController) {
32000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = dragController;
32131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
32231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    void setFolderIcon(FolderIcon icon) {
3242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mFolderIcon = icon;
3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
3283371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
3293371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // When the folder gets focus, we don't want to announce the list of items.
3303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return true;
3313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
33331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
33431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return the FolderInfo object associated with this folder
33531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
33631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    FolderInfo getInfo() {
33731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return mInfo;
33831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
33931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3403bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    private class GridComparator implements Comparator<ShortcutInfo> {
3413bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int mNumCols;
3423bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        public GridComparator(int numCols) {
3433bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            mNumCols = numCols;
3443bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3453bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
3463bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        @Override
3473bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
3483bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int lhIndex = lhs.cellY * mNumCols + lhs.cellX;
3493bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int rhIndex = rhs.cellY * mNumCols + rhs.cellX;
3503bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            return (lhIndex - rhIndex);
3513bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3523bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    }
3533bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
3543bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    private void placeInReadingOrder(ArrayList<ShortcutInfo> items) {
3553bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int maxX = 0;
3563bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int count = items.size();
3573bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        for (int i = 0; i < count; i++) {
3583bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            ShortcutInfo item = items.get(i);
3593bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            if (item.cellX > maxX) {
3603bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen                maxX = item.cellX;
3613bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            }
3623bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
363691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen
364691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen        GridComparator gridComparator = new GridComparator(maxX + 1);
3653bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        Collections.sort(items, gridComparator);
3663bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        final int countX = mContent.getCountX();
3673bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        for (int i = 0; i < count; i++) {
3683bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int x = i % countX;
3693bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int y = i / countX;
3703bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            ShortcutInfo item = items.get(i);
3713bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            item.cellX = x;
3723bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            item.cellY = y;
3733bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3743bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    }
3753bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
37631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void bind(FolderInfo info) {
37731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mInfo = info;
378df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        ArrayList<ShortcutInfo> children = info.contents;
379c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        ArrayList<ShortcutInfo> overflow = new ArrayList<ShortcutInfo>();
3807c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        setupContentForNumItems(children.size());
3813bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        placeInReadingOrder(children);
3820057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        int count = 0;
383df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        for (int i = 0; i < children.size(); i++) {
384df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            ShortcutInfo child = (ShortcutInfo) children.get(i);
385c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            if (!createAndAddShortcut(child)) {
386c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen                overflow.add(child);
3870057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen            } else {
3880057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen                count++;
389c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            }
390df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
391c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
3920057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        // We rearrange the items in case there are any empty gaps
3930057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        setupContentForNumItems(count);
3940057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen
395c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // If our folder has too many items we prune them from the list. This is an issue
396c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // when upgrading from the old Folders implementation which could contain an unlimited
397c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // number of items.
398c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        for (ShortcutInfo item: overflow) {
399c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            mInfo.remove(item);
400c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            LauncherModel.deleteItemFromDatabase(mLauncher, item);
401c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        }
402c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
4034dbe6d993485a702505ee4895db94aaa89655f2cAdam Cohen        mItemsInvalidated = true;
404ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        updateTextViewFocus();
405a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        mInfo.addListener(this);
4064ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen
407afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (!sDefaultFolderName.contentEquals(mInfo.title)) {
4084ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            mFolderName.setText(mInfo.title);
4094ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        } else {
4104ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            mFolderName.setText("");
4114ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        }
412691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen        updateItemLocationsInDatabase();
413df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
414df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
415df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    /**
416df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * Creates a new UserFolder, inflated from R.layout.user_folder.
417df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     *
418df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * @param context The application's context.
419df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     *
420df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * @return A new UserFolder.
421df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     */
422df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static Folder fromXml(Context context) {
423df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
424df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
425df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
426df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    /**
427df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * This method is intended to make the UserFolder to be visually identical in size and position
428df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
429df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     */
430df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private void positionAndSizeAsIcon() {
4313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (!(getParent() instanceof DragLayer)) return;
432662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setScaleX(0.8f);
433662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setScaleY(0.8f);
434662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setAlpha(0f);
435df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mState = STATE_SMALL;
436df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
437df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
438df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public void animateOpen() {
4393e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        positionAndSizeAsIcon();
4403e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
4418e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        if (!(getParent() instanceof DragLayer)) return;
4422801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        centerAboutIcon();
443662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
444662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
445662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
446032e6bad1ba588ed8a884fb8f28fb8596efac480Michael Jurka        final ObjectAnimator oa =
4472ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
4486441de0ec2a71862798dd51180d0811b42edd514Adam Cohen
4492801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.addListener(new AnimatorListenerAdapter() {
450df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
451df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationStart(Animator animation) {
4523371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
4538b805b17158886035b38261eb611d8641701ae43Michael Jurka                        String.format(getContext().getString(R.string.folder_opened),
4543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        mContent.getCountX(), mContent.getCountY()));
455df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                mState = STATE_ANIMATING;
456df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
457df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
458df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationEnd(Animator animation) {
4592801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                mState = STATE_OPEN;
4600121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka                setLayerType(LAYER_TYPE_NONE, null);
4617a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                Cling cling = mLauncher.showFirstRunFoldersCling();
4627a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                if (cling != null) {
4637a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                    cling.bringToFront();
4647a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                }
465ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                setFocusOnFirstChild();
466df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
467df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        });
4682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.setDuration(mExpandDuration);
4690121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        setLayerType(LAYER_TYPE_HARDWARE, null);
470f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        oa.start();
471df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
472df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
4733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendCustomAccessibilityEvent(int type, String text) {
4748b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
4758b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
4768b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
4773371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(type);
4783371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
4793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            event.getText().add(text);
4808b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
4813371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
4823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
4833371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
484ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private void setFocusOnFirstChild() {
485ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View firstChild = mContent.getChildAt(0, 0);
486ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        if (firstChild != null) {
487ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            firstChild.requestFocus();
488ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
489ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
490ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
491df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public void animateClosed() {
4928e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        if (!(getParent() instanceof DragLayer)) return;
493662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
494662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
495662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
496032e6bad1ba588ed8a884fb8f28fb8596efac480Michael Jurka        final ObjectAnimator oa =
4972ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
498df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
4992801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.addListener(new AnimatorListenerAdapter() {
500df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
501df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationEnd(Animator animation) {
5022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                onCloseComplete();
5030121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka                setLayerType(LAYER_TYPE_NONE, null);
5042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                mState = STATE_SMALL;
505df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
506df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
507df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationStart(Animator animation) {
5083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
5098b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getString(R.string.folder_closed));
510df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                mState = STATE_ANIMATING;
511df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
512df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        });
5132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.setDuration(mExpandDuration);
5140121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        setLayerType(LAYER_TYPE_HARDWARE, null);
515f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        oa.start();
516df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
517df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
518cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public boolean acceptDrop(DragObject d) {
519cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        final ItemInfo item = (ItemInfo) d.dragInfo;
520df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        final int itemType = item.itemType;
5212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
5222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                    itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
5232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                    !isFull());
524df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
525df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
526df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    protected boolean findAndSetEmptyCells(ShortcutInfo item) {
527df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        int[] emptyCell = new int[2];
528df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
529df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            item.cellX = emptyCell[0];
530df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            item.cellY = emptyCell[1];
531df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            return true;
532df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        } else {
533df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            return false;
534df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
535df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
536df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
537c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen    protected boolean createAndAddShortcut(ShortcutInfo item) {
538df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        final TextView textView =
539e87b924efaaf1cfb555a4327dc653929a4c182f1Adam Cohen            (TextView) mInflater.inflate(R.layout.application, this, false);
540df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setCompoundDrawablesWithIntrinsicBounds(null,
541df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
542df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setText(item.title);
543df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setTag(item);
544df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
545df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setOnClickListener(this);
546df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setOnLongClickListener(this);
547df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
548c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // We need to check here to verify that the given item's location isn't already occupied
5493bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        // by another item.
5500057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        if (mContent.getChildAt(item.cellX, item.cellY) != null || item.cellX < 0 || item.cellY < 0
5510057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen                || item.cellX >= mContent.getCountX() || item.cellY >= mContent.getCountY()) {
5523bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            // This shouldn't happen, log it.
5533bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            Log.e(TAG, "Folder order not properly persisted during bind");
554c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            if (!findAndSetEmptyCells(item)) {
555c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen                return false;
556c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            }
557c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        }
558c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
559df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        CellLayout.LayoutParams lp =
560df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
561df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        boolean insert = false;
562ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        textView.setOnKeyListener(new FolderKeyEventListener());
563df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
564c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        return true;
565df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
566df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
567cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public void onDragEnter(DragObject d) {
568bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mPreviousTargetCell[0] = -1;
569bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mPreviousTargetCell[1] = -1;
570bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mOnExitAlarm.cancelAlarm();
571df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
572df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
573bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
574bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        public void onAlarm(Alarm alarm) {
575bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            realTimeReorder(mEmptyCell, mTargetCell);
576bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
577bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    };
578bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
579bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    boolean readingOrderGreaterThan(int[] v1, int[] v2) {
580bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) {
581bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
582bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
583bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return false;
584bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
585df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
586df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
587bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private void realTimeReorder(int[] empty, int[] target) {
588bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        boolean wrap;
589bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int startX;
590bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int endX;
591bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int startY;
59276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        int delay = 0;
59376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        float delayAmount = 30;
594bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (readingOrderGreaterThan(target, empty)) {
595bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            wrap = empty[0] >= mContent.getCountX() - 1;
596bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            startY = wrap ? empty[1] + 1 : empty[1];
597bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            for (int y = startY; y <= target[1]; y++) {
598bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                startX = y == empty[1] ? empty[0] + 1 : 0;
599bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                endX = y < target[1] ? mContent.getCountX() - 1 : target[0];
600bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                for (int x = startX; x <= endX; x++) {
601bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    View v = mContent.getChildAt(x,y);
602bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            REORDER_ANIMATION_DURATION, delay, true, true)) {
604bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[0] = x;
605bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[1] = y;
60676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delay += delayAmount;
60776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delayAmount *= 0.9;
608bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
609bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
610bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
611bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
612bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            wrap = empty[0] == 0;
613bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            startY = wrap ? empty[1] - 1 : empty[1];
614bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            for (int y = startY; y >= target[1]; y--) {
615bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                startX = y == empty[1] ? empty[0] - 1 : mContent.getCountX() - 1;
616bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                endX = y > target[1] ? 0 : target[0];
617bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                for (int x = startX; x >= endX; x--) {
618bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    View v = mContent.getChildAt(x,y);
619bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
620482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            REORDER_ANIMATION_DURATION, delay, true, true)) {
621bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[0] = x;
622bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[1] = y;
62376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delay += delayAmount;
62476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delayAmount *= 0.9;
625bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
626bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
627bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
628bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
629bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
630bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
6312374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    public boolean isLayoutRtl() {
6322374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
6332374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    }
6342374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
63553b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini    private Rect getDragObjectDrawingRect(View dragView, float[] r) {
63653b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        final Rect drawingRect = mTempRect;
63753b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        drawingRect.left = (int) r[0];
63853b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        drawingRect.top = (int) r[1];
63953b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        drawingRect.right = drawingRect.left + dragView.getMeasuredWidth();
64053b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        drawingRect.bottom = drawingRect.top + dragView.getMeasuredHeight();
64153b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        return drawingRect;
64253b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini    }
64353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini
644bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDragOver(DragObject d) {
645f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int scrollOffset = mScrollView.getScrollY();
646bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, null);
647f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        r[0] -= getPaddingLeft();
648f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        r[1] -= getPaddingTop();
64953b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        if (!mAutoScroller.onTouch(this, getDragObjectDrawingRect(d.dragView, r))) {
65053b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini            mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1] + scrollOffset, 1, 1,
65153b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                    mTargetCell);
652f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
65353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini            if (isLayoutRtl()) {
65453b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
655f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            }
65653b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini            if (mTargetCell[0] != mPreviousTargetCell[0]
65753b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                    || mTargetCell[1] != mPreviousTargetCell[1]) {
65853b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mReorderAlarm.cancelAlarm();
65953b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
66053b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mReorderAlarm.setAlarm(REORDER_DELAY);
66153b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mPreviousTargetCell[0] = mTargetCell[0];
66253b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mPreviousTargetCell[1] = mTargetCell[1];
66353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mDragMode = DRAG_MODE_REORDER;
66453b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini            } else {
66553b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini                mDragMode = DRAG_MODE_NONE;
666f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            }
66761a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen        } else {
66861a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            mReorderAlarm.cancelAlarm();
669bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
670df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
671df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
672bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // This is used to compute the visual center of the dragView. The idea is that
673bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // the visual center represents the user's interpretation of where the item is, and hence
674bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // is the appropriate point to use when determining drop location.
675bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
676bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            DragView dragView, float[] recycle) {
677bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        float res[];
678bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (recycle == null) {
679bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            res = new float[2];
680bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
681bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            res = recycle;
682df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
6832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
684bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // These represent the visual top and left of drag view if a dragRect was provided.
685bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // If a dragRect was not provided, then they correspond to the actual view left and
686bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // top, as the dragRect is in that case taken to be the entire dragView.
687bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // R.dimen.dragViewOffsetY.
688bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int left = x - xOffset;
689bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int top = y - yOffset;
690bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
691bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // In order to find the visual center, we shift by half the dragRect
692bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        res[0] = left + dragView.getDragRegion().width() / 2;
693bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        res[1] = top + dragView.getDragRegion().height() / 2;
694bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
695bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return res;
696bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
697bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
698bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
699bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        public void onAlarm(Alarm alarm) {
7003e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            completeDragExit();
701bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
702bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    };
7032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
70495bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen    public void completeDragExit() {
7053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mLauncher.closeFolder();
7063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mCurrentDragInfo = null;
7073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mCurrentDragView = null;
7083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mSuppressOnAdd = false;
7093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mRearrangeOnClose = true;
7103e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
7113e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
712bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDragExit(DragObject d) {
71353b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        // Exiting folder; stop the auto scroller.
71453b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        mAutoScroller.stop();
71553b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        // We only close the folder if this is a true drag exit, ie. not because
71653b8d071ce63b2b55fa8bdc71488c44308bfcf2fMindy DelliCarpini        // a drop has occurred above the folder.
717bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (!d.dragComplete) {
718bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mOnExitAlarm.setOnAlarmListener(mOnExitAlarmListener);
719bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
720bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
721bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mReorderAlarm.cancelAlarm();
722f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mDragMode = DRAG_MODE_NONE;
7232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
7242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
7251e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    public void onDropCompleted(final View target, final DragObject d,
7261e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka            final boolean isFlingToDelete, final boolean success) {
7271e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        if (mDeferDropAfterUninstall) {
728f3007589e346df224d357b389069adfeb266545eMichael Jurka            Log.d(TAG, "Deferred handling drop because waiting for uninstall.");
7291e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka            mDeferredAction = new Runnable() {
7301e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                    public void run() {
7311e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                        onDropCompleted(target, d, isFlingToDelete, success);
7321e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                        mDeferredAction = null;
7331e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                    }
7341e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                };
7351e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka            return;
7361e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        }
7371e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka
7381e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        boolean beingCalledAfterUninstall = mDeferredAction != null;
7391e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        boolean successfulDrop =
7401e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka                success && (!beingCalledAfterUninstall || mUninstallSuccessful);
7415f8afe6280eae34620067696173e71943e1a30a3Winson Chung
7421e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        if (successfulDrop) {
74305e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
74467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                replaceFolderWithFinalItem();
74567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
74667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        } else {
7477a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen            setupContentForNumItems(getItemCount());
74867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            // The drag failed, we need to return the item to the folder
74967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            mFolderIcon.onDrop(d);
75067bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        }
75167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen
75267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        if (target != this) {
75367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            if (mOnExitAlarm.alarmPending()) {
75467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                mOnExitAlarm.cancelAlarm();
7555455425c1b0355f5dd652cc8e7a2369c33dc9883Michael Jurka                if (!successfulDrop) {
7567a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                    mSuppressFolderDeletion = true;
7577a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                }
75867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                completeDragExit();
75967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
76067bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        }
7615f8afe6280eae34620067696173e71943e1a30a3Winson Chung
76267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mDeleteFolderOnDropCompleted = false;
76367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mDragInProgress = false;
76405e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        mItemAddedBackToSelfViaIcon = false;
765bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mCurrentDragInfo = null;
766bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mCurrentDragView = null;
767bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mSuppressOnAdd = false;
7684045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen
7694045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        // Reordering may have occured, and we need to save the new item locations. We do this once
7704045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        // at the end to prevent unnecessary database operations.
771f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        updateItemLocationsInDatabaseBatch();
7724045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    }
7734045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen
7741e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    public void deferCompleteDropAfterUninstallActivity() {
7751e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        mDeferDropAfterUninstall = true;
7761e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    }
7771e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka
7781e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    public void onUninstallActivityReturned(boolean success) {
7791e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        mDeferDropAfterUninstall = false;
7801e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        mUninstallSuccessful = success;
7811e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        if (mDeferredAction != null) {
7821e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka            mDeferredAction.run();
7831e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka        }
7841e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka    }
7851e2f465f46ded990ea30516cdb7f0fcf3280411fMichael Jurka
786a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
787043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public boolean supportsFlingToDelete() {
788043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        return true;
789043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
790043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
791a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
792a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // Do nothing
793a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
794a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
795a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
796a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onFlingToDeleteCompleted() {
797a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // Do nothing
798a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
799a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
8004045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    private void updateItemLocationsInDatabase() {
8014045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        ArrayList<View> list = getItemsInReadingOrder();
8024045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        for (int i = 0; i < list.size(); i++) {
8034045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            View v = list.get(i);
8044045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            ItemInfo info = (ItemInfo) v.getTag();
8054045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0,
8064045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen                        info.cellX, info.cellY);
8074045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        }
80867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    }
809228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohen
810f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private void updateItemLocationsInDatabaseBatch() {
811f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        ArrayList<View> list = getItemsInReadingOrder();
812f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
813f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        for (int i = 0; i < list.size(); i++) {
814f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            View v = list.get(i);
815f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            ItemInfo info = (ItemInfo) v.getTag();
816f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            items.add(info);
817f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        }
818f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
819f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        LauncherModel.moveItemsInDatabase(mLauncher, items, mInfo.id, 0);
820f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    }
821f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
822e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen    public void addItemLocationsInDatabase() {
823e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen        ArrayList<View> list = getItemsInReadingOrder();
824e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen        for (int i = 0; i < list.size(); i++) {
825e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen            View v = list.get(i);
826e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen            ItemInfo info = (ItemInfo) v.getTag();
827e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen            LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
828e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen                        info.cellX, info.cellY, false);
829e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen        }
830e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen    }
831e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen
83267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    public void notifyDrop() {
83367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        if (mDragInProgress) {
83405e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            mItemAddedBackToSelfViaIcon = true;
83576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        }
836df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
837df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
838df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public boolean isDropEnabled() {
839df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        return true;
840df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
841df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
8424045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    private void setupContentDimensions(int count) {
8432801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        ArrayList<View> list = getItemsInReadingOrder();
8442801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8452801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int countX = mContent.getCountX();
8462801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int countY = mContent.getCountY();
8477c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        boolean done = false;
8487c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen
8497c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        while (!done) {
8507c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            int oldCountX = countX;
8517c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            int oldCountY = countY;
8527c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            if (countX * countY < count) {
8537c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                // Current grid is too small, expand it
85478dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen                if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
8557c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    countX++;
8567c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                } else if (countY < mMaxCountY) {
8577c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    countY++;
8587c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                }
8597c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                if (countY == 0) countY++;
8607c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            } else if ((countY - 1) * countX >= count && countY >= countX) {
8617c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                countY = Math.max(0, countY - 1);
8627c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            } else if ((countX - 1) * countY >= count) {
8637c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                countX = Math.max(0, countX - 1);
8642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
8657c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            done = countX == oldCountX && countY == oldCountY;
8662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
8677c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mContent.setGridSize(countX, countY);
8682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        arrangeChildren(list);
8692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
8702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public boolean isFull() {
87278dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        return getItemCount() >= mMaxNumItems;
8732801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
8742801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void centerAboutIcon() {
8768e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
8772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8782801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
879f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int height = getFolderHeight();
8808e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
8818e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen
882307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect);
8832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
884307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int centerX = (int) (mTempRect.left + mTempRect.width() * scale / 2);
885307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int centerY = (int) (mTempRect.top + mTempRect.height() * scale / 2);
8862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int centeredLeft = centerX - width / 2;
8872801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int centeredTop = centerY - height / 2;
8882801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8897cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        int currentPage = mLauncher.getWorkspace().getCurrentPage();
8907cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // In case the workspace is scrolling, we need to use the final scroll to compute
8917cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // the folders bounds.
8927cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        mLauncher.getWorkspace().setFinalScrollForPageChange(currentPage);
89335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // We first fetch the currently visible CellLayoutChildren
8947cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        CellLayout currentLayout = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPage);
895a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer boundingLayout = currentLayout.getShortcutsAndWidgets();
89635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        Rect bounds = new Rect();
89735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
8987cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // We reset the workspaces scroll
8997cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        mLauncher.getWorkspace().resetFinalScrollForPageChange(currentPage);
90035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
90135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // We need to bound the folder to the currently visible CellLayoutChildren
90235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        int left = Math.min(Math.max(bounds.left, centeredLeft),
90335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen                bounds.left + bounds.width() - width);
90435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        int top = Math.min(Math.max(bounds.top, centeredTop),
90535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen                bounds.top + bounds.height() - height);
90635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // If the folder doesn't fit within the bounds, center it about the desired bounds
90735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        if (width >= bounds.width()) {
90835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen            left = bounds.left + (bounds.width() - width) / 2;
90935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        }
91035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        if (height >= bounds.height()) {
91135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen            top = bounds.top + (bounds.height() - height) / 2;
9120e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen        }
9132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
9142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int folderPivotX = width / 2 + (centeredLeft - left);
9152801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int folderPivotY = height / 2 + (centeredTop - top);
9162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        setPivotX(folderPivotX);
9172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        setPivotY(folderPivotY);
918268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        mFolderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
9192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (1.0f * folderPivotX / width));
920268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        mFolderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
9212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (1.0f * folderPivotY / height));
9223bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
923662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.width = width;
924662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.height = height;
925662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.x = left;
926662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.y = top;
9272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
9282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
929268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    float getPivotXForIconAnimation() {
930268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        return mFolderIconPivotX;
931268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    }
932268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    float getPivotYForIconAnimation() {
933268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        return mFolderIconPivotY;
934268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    }
935268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen
9362801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void setupContentForNumItems(int count) {
9374045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        setupContentDimensions(count);
9382801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
9398e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
9402801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (lp == null) {
9418e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen            lp = new DragLayer.LayoutParams(0, 0);
9428e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen            lp.customPosition = true;
9432801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setLayoutParams(lp);
9442801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
9452801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        centerAboutIcon();
9462801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
9472801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
948f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int getFolderHeight() {
949f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int contentAreaHeight = mContent.getDesiredHeight();
950f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        if (contentAreaHeight >= mMaxContentAreaHeight) {
951f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            // Subtract a bit so the user can see that it's scrollable.
952f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            contentAreaHeight = mMaxContentAreaHeight;
953f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        }
954f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int height = getPaddingTop() + getPaddingBottom() + contentAreaHeight
955f4bb1cdecd3cf866a1d87b7b8560234fa7dd4cc5Adam Cohen                + mFolderNameHeight;
956f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        return height;
957f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    }
958f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
959f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
960f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int contentAreaHeight = mContent.getDesiredHeight();
961f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        if (contentAreaHeight >= mMaxContentAreaHeight) {
962f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            // Subtract a bit so the user can see that it's scrollable.
963f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            contentAreaHeight = mMaxContentAreaHeight;
964f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        }
965f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
966f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
967f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int height = getFolderHeight();
968f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
969234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.EXACTLY);
970f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(contentAreaHeight,
971234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.EXACTLY);
972234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen
973f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mContent.setFixedSize(mContent.getDesiredWidth(), mContent.getDesiredHeight());
974f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
975f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mFolderName.measure(contentAreaWidthSpec,
976234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
977234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        setMeasuredDimension(width, height);
978234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    }
979234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen
9802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void arrangeChildren(ArrayList<View> list) {
9812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int[] vacant = new int[2];
9822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (list == null) {
9832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            list = getItemsInReadingOrder();
9842801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
9852801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mContent.removeAllViews();
9862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
9872801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int i = 0; i < list.size(); i++) {
9882801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            View v = list.get(i);
9892801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mContent.getVacantCell(vacant, 1, 1);
9902801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
9912801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            lp.cellX = vacant[0];
9922801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            lp.cellY = vacant[1];
9932801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            ItemInfo info = (ItemInfo) v.getTag();
9942792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen            if (info.cellX != vacant[0] || info.cellY != vacant[1]) {
9952792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                info.cellX = vacant[0];
9962792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                info.cellY = vacant[1];
9972792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
9982792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                        info.cellX, info.cellY);
9992792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen            }
10002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            boolean insert = false;
10012801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
10022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
10037c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mItemsInvalidated = true;
10042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
10052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1006a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public int getItemCount() {
1007a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mContent.getShortcutsAndWidgets().getChildCount();
1008a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
1009a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
1010a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public View getItemAt(int index) {
1011a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mContent.getShortcutsAndWidgets().getChildAt(index);
1012a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
1013a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
10142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void onCloseComplete() {
101505e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        DragLayer parent = (DragLayer) getParent();
10165649c287039ea7908112b41604c3fc2893c4697eMichael Jurka        if (parent != null) {
10175649c287039ea7908112b41604c3fc2893c4697eMichael Jurka            parent.removeView(this);
10185649c287039ea7908112b41604c3fc2893c4697eMichael Jurka        }
10194554ee16f122a3dbd9a8d3b828f1c8c7e7b7fe99Adam Cohen        mDragController.removeDropTarget((DropTarget) this);
102005e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        clearFocus();
1021ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderIcon.requestFocus();
102205e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen
10232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (mRearrangeOnClose) {
10242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setupContentForNumItems(getItemCount());
10252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mRearrangeOnClose = false;
10262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1027afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (getItemCount() <= 1) {
102867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            if (!mDragInProgress && !mSuppressFolderDeletion) {
102967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                replaceFolderWithFinalItem();
103067bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            } else if (mDragInProgress) {
103167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                mDeleteFolderOnDropCompleted = true;
103267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
1033afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
103467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mSuppressFolderDeletion = false;
1035afb01ee74243cede19088e694ca82cea5983c603Adam Cohen    }
1036afb01ee74243cede19088e694ca82cea5983c603Adam Cohen
1037afb01ee74243cede19088e694ca82cea5983c603Adam Cohen    private void replaceFolderWithFinalItem() {
1038fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // Add the last remaining child to the workspace in place of the folder
1039fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
1040fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            @Override
1041fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            public void run() {
1042dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen                CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screenId);
1043fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
1044c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen               View child = null;
1045fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                // Move the item from the folder to the workspace, in the position of the folder
1046fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                if (getItemCount() == 1) {
1047fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    ShortcutInfo finalItem = mInfo.contents.get(0);
1048c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                    child = mLauncher.createShortcut(R.layout.application, cellLayout,
1049fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                            finalItem);
1050fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
1051dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen                            mInfo.screenId, mInfo.cellX, mInfo.cellY);
1052fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
1053487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                if (getItemCount() <= 1) {
1054487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    // Remove the folder
1055487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
1056487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    cellLayout.removeView(mFolderIcon);
1057487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    if (mFolderIcon instanceof DropTarget) {
1058487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
1059487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    }
1060487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    mLauncher.removeFolder(mInfo);
1061487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                }
1062c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                // We add the child after removing the folder to prevent both from existing at
1063c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                // the same time in the CellLayout.
1064c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                if (child != null) {
1065dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen                    mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screenId,
1066c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                            mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
1067c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                }
1068fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            }
1069fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        };
1070fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        View finalChild = getItemAt(0);
1071fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        if (finalChild != null) {
1072fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
1073afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
1074fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        mDestroyed = true;
1075fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
1076afb01ee74243cede19088e694ca82cea5983c603Adam Cohen
1077fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    boolean isDestroyed() {
1078fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mDestroyed;
10792801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
10802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1081ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    // This method keeps track of the last item in the folder for the purposes
1082ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    // of keyboard focus
1083ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private void updateTextViewFocus() {
1084ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View lastChild = getItemAt(getItemCount() - 1);
1085ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        getItemAt(getItemCount() - 1);
1086ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        if (lastChild != null) {
1087ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusDownId(lastChild.getId());
1088ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusRightId(lastChild.getId());
1089ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusLeftId(lastChild.getId());
1090ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusUpId(lastChild.getId());
1091ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
1092ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
1093ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDrop(DragObject d) {
1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        ShortcutInfo item;
1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (d.dragInfo instanceof ApplicationInfo) {
1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // Came from all apps -- make a copy
1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item = ((ApplicationInfo) d.dragInfo).makeShortcut();
1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item.spanX = 1;
1100bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item.spanY = 1;
1101bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
1102bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item = (ShortcutInfo) d.dragInfo;
1103bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
110405e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // Dragged from self onto self, currently this is the only path possible, however
110505e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // we keep this as a distinct code path.
1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (item == mCurrentDragInfo) {
1107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
1109bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            si.cellX = lp.cellX = mEmptyCell[0];
1110bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            si.cellX = lp.cellY = mEmptyCell[1];
1111bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
1112fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            if (d.dragView.hasDrawn()) {
1113fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView);
1114fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            } else {
11152c4cf411f6c30fb2bfb47d2b13b680bda7a266dcWinson Chung                d.deferDragViewCleanupPostAnimation = false;
1116fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                mCurrentDragView.setVisibility(VISIBLE);
1117fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            }
1118e9166b247addcf67542ababb9d453f5bfb33c7b2Adam Cohen            mItemsInvalidated = true;
11194045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            setupContentDimensions(getItemCount());
1120716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            mSuppressOnAdd = true;
1121bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1122bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mInfo.add(item);
1123bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1124bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11257a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    // This is used so the item doesn't immediately appear in the folder when added. In one case
11267a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    // we need to create the illusion that the item isn't added back to the folder yet, to
11277a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    // to correspond to the animation of the icon back into the folder. This is
11287a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    public void hideItem(ShortcutInfo info) {
11297a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen        View v = getViewForInfo(info);
11307a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen        v.setVisibility(INVISIBLE);
11317a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    }
11327a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    public void showItem(ShortcutInfo info) {
11337a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen        View v = getViewForInfo(info);
11347a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen        v.setVisibility(VISIBLE);
11357a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen    }
11367a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen
1137bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onAdd(ShortcutInfo item) {
1138bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mItemsInvalidated = true;
113905e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // If the item was dropped onto this open folder, we have done the work associated
114005e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // with adding the item to the folder, as indicated by mSuppressOnAdd being set
1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (mSuppressOnAdd) return;
1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (!findAndSetEmptyCells(item)) {
1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // The current layout is full, can we expand it?
1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            setupContentForNumItems(getItemCount() + 1);
1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            findAndSetEmptyCells(item);
1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        createAndAddShortcut(item);
1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        LauncherModel.addOrMoveItemInDatabase(
1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1152a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
11537c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mItemsInvalidated = true;
115405e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // If this item is being dragged from this open folder, we have already handled
115505e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // the work associated with removing the item, so we don't have to do anything here.
1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (item == mCurrentDragInfo) return;
1157df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        View v = getViewForInfo(item);
1158a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        mContent.removeView(v);
11592801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (mState == STATE_ANIMATING) {
11602801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mRearrangeOnClose = true;
11612801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        } else {
11622801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setupContentForNumItems(getItemCount());
11632801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1164afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (getItemCount() <= 1) {
1165afb01ee74243cede19088e694ca82cea5983c603Adam Cohen            replaceFolderWithFinalItem();
1166afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
1167a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
11687c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen
1169df1e4e868a1970b756486dadd652651d40276d36Adam Cohen    private View getViewForInfo(ShortcutInfo item) {
1170df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        for (int j = 0; j < mContent.getCountY(); j++) {
1171df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            for (int i = 0; i < mContent.getCountX(); i++) {
1172df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                View v = mContent.getChildAt(i, j);
1173df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                if (v.getTag() == item) {
1174df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                    return v;
1175df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                }
1176df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            }
1177df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        }
1178df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        return null;
1179df1e4e868a1970b756486dadd652651d40276d36Adam Cohen    }
1180df1e4e868a1970b756486dadd652651d40276d36Adam Cohen
118176078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public void onItemsChanged() {
1182ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        updateTextViewFocus();
118376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
1184ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
118576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
118676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
118776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
11887c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    public ArrayList<View> getItemsInReadingOrder() {
11897c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        if (mItemsInvalidated) {
11907c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            mItemsInReadingOrder.clear();
11917c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            for (int j = 0; j < mContent.getCountY(); j++) {
11927c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                for (int i = 0; i < mContent.getCountX(); i++) {
11937c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    View v = mContent.getChildAt(i, j);
11947c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    if (v != null) {
11957a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                        mItemsInReadingOrder.add(v);
11967c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    }
11977c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                }
11987c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            }
11997c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            mItemsInvalidated = false;
12007c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        }
12017c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        return mItemsInReadingOrder;
12027c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    }
12038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
12048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public void getLocationInDragLayer(int[] loc) {
12058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
12068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
1207ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen
1208ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen    public void onFocusChange(View v, boolean hasFocus) {
1209ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        if (v == mFolderName && hasFocus) {
1210ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen            startEditingFolderName();
1211ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        }
1212ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen    }
12137d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
12147d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    @Override
12157d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public void getHitRectRelativeToDragLayer(Rect outRect) {
12167d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        getHitRect(outRect);
12177d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
121831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
1219