Folder.java revision 2374abfda3e53f84e005df8923170308e4df8c03
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
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
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;
4276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.inputmethod.EditorInfo;
4376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.inputmethod.InputMethodManager;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.LinearLayout;
45df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohenimport android.widget.TextView;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
47edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guyimport com.android.launcher.R;
48a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport com.android.launcher2.FolderInfo.FolderListener;
49edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy
50c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
513bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohenimport java.util.Collections;
523bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohenimport java.util.Comparator;
53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
5431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
5531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Represents a set of icons chosen by the user or generated by the system.
5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
578dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohenpublic class Folder extends LinearLayout implements DragSource, View.OnClickListener,
58ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
59ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        View.OnFocusChangeListener {
604eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen    private static final String TAG = "Launcher.Folder";
61df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
624eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen    protected DragController mDragController;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected Launcher mLauncher;
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected FolderInfo mInfo;
6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
66df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_NONE = -1;
67df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_SMALL = 0;
68df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_ANIMATING = 1;
69df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static final int STATE_OPEN = 2;
70df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
71df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private int mExpandDuration;
72df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    protected CellLayout mContent;
73df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private final LayoutInflater mInflater;
74df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private final IconCache mIconCache;
75df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private int mState = STATE_NONE;
76bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 230;
77bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private static final int ON_EXIT_CLOSE_DELAY = 800;
782801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private boolean mRearrangeOnClose = false;
792801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private FolderIcon mFolderIcon;
802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private int mMaxCountX;
812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private int mMaxCountY;
8278dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen    private int mMaxNumItems;
837c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
84badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    private Drawable mIconDrawable;
857c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    boolean mItemsInvalidated = false;
86bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private ShortcutInfo mCurrentDragInfo;
87bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private View mCurrentDragView;
88bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    boolean mSuppressOnAdd = false;
89bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mTargetCell = new int[2];
90bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mPreviousTargetCell = new int[2];
91bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private int[] mEmptyCell = new int[2];
92bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private Alarm mReorderAlarm = new Alarm();
93bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private Alarm mOnExitAlarm = new Alarm();
9476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private int mFolderNameHeight;
958e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen    private Rect mTempRect = new Rect();
9667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mDragInProgress = false;
9767bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mDeleteFolderOnDropCompleted = false;
9867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    private boolean mSuppressFolderDeletion = false;
9905e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen    private boolean mItemAddedBackToSelfViaIcon = false;
100ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    FolderEditText mFolderName;
101268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    private float mFolderIconPivotX;
102268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    private float mFolderIconPivotY;
103228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohen
10476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean mIsEditingName = false;
10576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private InputMethodManager mInputMethodManager;
106df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
107a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen    private static String sDefaultFolderName;
108a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen    private static String sHintText;
1090121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka    private ObjectAnimator mOpenCloseAnimator;
110a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
111fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private boolean mDestroyed;
112fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to inflate the Workspace from XML.
11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param attrs The attribtues set containing the Workspace's customization values.
11831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public Folder(Context context, AttributeSet attrs) {
12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
122df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mInflater = LayoutInflater.from(context);
123df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
12478dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen
12578dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        Resources res = getResources();
12678dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        mMaxCountX = res.getInteger(R.integer.folder_max_count_x);
12778dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        mMaxCountY = res.getInteger(R.integer.folder_max_count_y);
12878dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        mMaxNumItems = res.getInteger(R.integer.folder_max_num_items);
12978dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        if (mMaxCountX < 0 || mMaxCountY < 0 || mMaxNumItems < 0) {
13078dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen            mMaxCountX = LauncherModel.getCellCountX();
13178dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen            mMaxCountY = LauncherModel.getCellCountY();
13278dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen            mMaxNumItems = mMaxCountX * mMaxCountY;
13378dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        }
13476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
13576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mInputMethodManager = (InputMethodManager)
1368b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
13776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
13876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration);
1394ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen
1404ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        if (sDefaultFolderName == null) {
1414ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            sDefaultFolderName = res.getString(R.string.folder_name);
1424ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        }
143a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        if (sHintText == null) {
144a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen            sHintText = res.getString(R.string.folder_hint_text);
145a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        }
1464eac29a80b9a73465c8de54f1caec2a8098a73c6Adam Cohen        mLauncher = (Launcher) context;
147ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // We need this view to be focusable in touch mode so that when text editing of the folder
148ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // name is complete, we have something to focus on, thus hiding the cursor and giving
149ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // reliable behvior when clicking the text field (since it will always gain focus on click).
150ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        setFocusableInTouchMode(true);
15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
15231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
15331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
15431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onFinishInflate() {
15531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onFinishInflate();
156df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mContent = (CellLayout) findViewById(R.id.folder_content);
1572801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mContent.setGridSize(0, 0);
158a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
1592374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        mContent.setInvertIfRtl(true);
160ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderName = (FolderEditText) findViewById(R.id.folder_name);
161ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderName.setFolder(this);
162ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        mFolderName.setOnFocusChangeListener(this);
16376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
16476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // We find out how tall the text view wants to be (it is set to wrap_content), so that
16576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // we can allocate the appropriate amount of space for it.
16676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        int measureSpec = MeasureSpec.UNSPECIFIED;
16776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.measure(measureSpec, measureSpec);
16876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderNameHeight = mFolderName.getMeasuredHeight();
16976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
17076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        // We disable action mode for now since it messes up the view on phones
17176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback);
17276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mFolderName.setOnEditorActionListener(this);
1734ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        mFolderName.setSelectAllOnFocus(true);
1747a14d0bddea652ddca855af0c413e47a6c1360b2Adam Cohen        mFolderName.setInputType(mFolderName.getInputType() |
1757a14d0bddea652ddca855af0c413e47a6c1360b2Adam Cohen                InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
17876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
17976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
18076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
18176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
18276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
18376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
18476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
18576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
18676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
18776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public void onDestroyActionMode(ActionMode mode) {
18876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
18976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
19076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
19176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return false;
19276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
19376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    };
19476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public void onClick(View v) {
196df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        Object tag = v.getTag();
197df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (tag instanceof ShortcutInfo) {
198df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            // refactor this code from Folder
199df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            ShortcutInfo item = (ShortcutInfo) tag;
200df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            int[] pos = new int[2];
201df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            v.getLocationOnScreen(pos);
202df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            item.intent.setSourceBounds(new Rect(pos[0], pos[1],
203df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
204c7450e3ebd7672fcd7b9d51a8c1e68f63c5ce86bWinson Chung
205c7450e3ebd7672fcd7b9d51a8c1e68f63c5ce86bWinson Chung            mLauncher.startActivitySafely(v, item.intent, item);
206df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
20831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onLongClick(View v) {
21036a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung        // Return if global dragging is not enabled
21136a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung        if (!mLauncher.isDraggingEnabled()) return true;
21236a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung
213df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        Object tag = v.getTag();
214df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (tag instanceof ShortcutInfo) {
215df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            ShortcutInfo item = (ShortcutInfo) tag;
216df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            if (!v.isInTouchMode()) {
217df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                return false;
218df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
219df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
2207d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung            mLauncher.dismissFolderCling(null);
2217d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
222df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            mLauncher.getWorkspace().onDragStartedWithItem(v);
223ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            mLauncher.getWorkspace().beginDragShared(v, this);
224badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen            mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
22576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
22676078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen            mCurrentDragInfo = item;
227bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mEmptyCell[0] = item.cellX;
228bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mEmptyCell[1] = item.cellY;
229bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mCurrentDragView = v;
230fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
231fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            mContent.removeView(mCurrentDragView);
232fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            mInfo.remove(mCurrentDragInfo);
23367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            mDragInProgress = true;
23405e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            mItemAddedBackToSelfViaIcon = false;
235df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
23631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return true;
23731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
23831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
23976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean isEditingName() {
24076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return mIsEditingName;
24176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
24276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
24376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void startEditingFolderName() {
244a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mFolderName.setHint("");
24576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mIsEditingName = true;
24676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
24776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
24876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void dismissEditingName() {
24976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
25076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        doneEditingFolderName(true);
25176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
25276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
25376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void doneEditingFolderName(boolean commit) {
254a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mFolderName.setHint(sHintText);
2551df26a368a135395b7bd61e9b109044b33b1b0beAdam Cohen        // Convert to a string here to ensure that no other state associated with the text field
2561df26a368a135395b7bd61e9b109044b33b1b0beAdam Cohen        // gets saved.
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        String newTitle = mFolderName.getText().toString();
2583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        mInfo.setTitle(newTitle);
25976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        LauncherModel.updateItemInDatabase(mLauncher, mInfo);
260ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
2613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (commit) {
2623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
2638b805b17158886035b38261eb611d8641701ae43Michael Jurka                    String.format(getContext().getString(R.string.folder_renamed), newTitle));
2643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
265ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // In order to clear the focus from the text field, we set the focus on ourself. This
266ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        // ensures that every time the field is clicked, focus is gained, giving reliable behavior.
267ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        requestFocus();
268ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
269e601a43345224e3e386abc68bbea8b08b2df9570Adam Cohen        Selection.setSelection((Spannable) mFolderName.getText(), 0, 0);
27076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        mIsEditingName = false;
27176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
27276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
27376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
27476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        if (actionId == EditorInfo.IME_ACTION_DONE) {
27576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            dismissEditingName();
27676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return true;
27776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
27876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return false;
27976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
28076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
28176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public View getEditTextRegion() {
28276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        return mFolderName;
28376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
28476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
285badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    public Drawable getDragDrawable() {
286badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen        return mIconDrawable;
287badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    }
288badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
2890c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    /**
2900c872ba544ecfd9b106bb66137da8680927590deAdam Cohen     * We need to handle touch events to prevent them from falling through to the workspace below.
2910c872ba544ecfd9b106bb66137da8680927590deAdam Cohen     */
2920c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    @Override
2930c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    public boolean onTouchEvent(MotionEvent ev) {
2940c872ba544ecfd9b106bb66137da8680927590deAdam Cohen        return true;
2950c872ba544ecfd9b106bb66137da8680927590deAdam Cohen    }
2960c872ba544ecfd9b106bb66137da8680927590deAdam Cohen
29700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void setDragController(DragController dragController) {
29800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = dragController;
29931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
30031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3012801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    void setFolderIcon(FolderIcon icon) {
3022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mFolderIcon = icon;
3032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3053371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
3063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
3073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // When the folder gets focus, we don't want to announce the list of items.
3083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return true;
3093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
31131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
31231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return the FolderInfo object associated with this folder
31331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    FolderInfo getInfo() {
31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return mInfo;
31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
31731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3183bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    private class GridComparator implements Comparator<ShortcutInfo> {
3193bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int mNumCols;
3203bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        public GridComparator(int numCols) {
3213bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            mNumCols = numCols;
3223bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3233bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
3243bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        @Override
3253bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
3263bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int lhIndex = lhs.cellY * mNumCols + lhs.cellX;
3273bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int rhIndex = rhs.cellY * mNumCols + rhs.cellX;
3283bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            return (lhIndex - rhIndex);
3293bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3303bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    }
3313bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
3323bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    private void placeInReadingOrder(ArrayList<ShortcutInfo> items) {
3333bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int maxX = 0;
3343bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        int count = items.size();
3353bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        for (int i = 0; i < count; i++) {
3363bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            ShortcutInfo item = items.get(i);
3373bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            if (item.cellX > maxX) {
3383bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen                maxX = item.cellX;
3393bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            }
3403bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
341691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen
342691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen        GridComparator gridComparator = new GridComparator(maxX + 1);
3433bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        Collections.sort(items, gridComparator);
3443bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        final int countX = mContent.getCountX();
3453bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        for (int i = 0; i < count; i++) {
3463bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int x = i % countX;
3473bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            int y = i / countX;
3483bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            ShortcutInfo item = items.get(i);
3493bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            item.cellX = x;
3503bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            item.cellY = y;
3513bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        }
3523bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen    }
3533bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
35431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void bind(FolderInfo info) {
35531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mInfo = info;
356df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        ArrayList<ShortcutInfo> children = info.contents;
357c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        ArrayList<ShortcutInfo> overflow = new ArrayList<ShortcutInfo>();
3587c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        setupContentForNumItems(children.size());
3593bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        placeInReadingOrder(children);
3600057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        int count = 0;
361df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        for (int i = 0; i < children.size(); i++) {
362df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            ShortcutInfo child = (ShortcutInfo) children.get(i);
363c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            if (!createAndAddShortcut(child)) {
364c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen                overflow.add(child);
3650057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen            } else {
3660057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen                count++;
367c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            }
368df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
369c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
3700057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        // We rearrange the items in case there are any empty gaps
3710057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        setupContentForNumItems(count);
3720057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen
373c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // If our folder has too many items we prune them from the list. This is an issue
374c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // when upgrading from the old Folders implementation which could contain an unlimited
375c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // number of items.
376c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        for (ShortcutInfo item: overflow) {
377c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            mInfo.remove(item);
378c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            LauncherModel.deleteItemFromDatabase(mLauncher, item);
379c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        }
380c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
3814dbe6d993485a702505ee4895db94aaa89655f2cAdam Cohen        mItemsInvalidated = true;
382ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        updateTextViewFocus();
383a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        mInfo.addListener(this);
3844ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen
385afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (!sDefaultFolderName.contentEquals(mInfo.title)) {
3864ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            mFolderName.setText(mInfo.title);
3874ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        } else {
3884ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen            mFolderName.setText("");
3894ef610fc88e447ff6d6cdd382a7d064be9f739d6Adam Cohen        }
390691a5797f9bba4154d564d3a6c9b92559ee8cc4aAdam Cohen        updateItemLocationsInDatabase();
391df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
392df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
393df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    /**
394df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * Creates a new UserFolder, inflated from R.layout.user_folder.
395df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     *
396df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * @param context The application's context.
397df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     *
398df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * @return A new UserFolder.
399df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     */
400df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    static Folder fromXml(Context context) {
401df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
402df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
403df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
404df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    /**
405df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * This method is intended to make the UserFolder to be visually identical in size and position
406df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
407df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen     */
408df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    private void positionAndSizeAsIcon() {
4093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (!(getParent() instanceof DragLayer)) return;
410662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setScaleX(0.8f);
411662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setScaleY(0.8f);
412662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        setAlpha(0f);
413df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mState = STATE_SMALL;
414df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
415df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
416df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public void animateOpen() {
4173e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        positionAndSizeAsIcon();
4183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
4198e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        if (!(getParent() instanceof DragLayer)) return;
4202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        centerAboutIcon();
421662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
422662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
423662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
4240121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        final ObjectAnimator oa = mOpenCloseAnimator =
4252ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
4266441de0ec2a71862798dd51180d0811b42edd514Adam Cohen
4272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.addListener(new AnimatorListenerAdapter() {
428df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
429df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationStart(Animator animation) {
4303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
4318b805b17158886035b38261eb611d8641701ae43Michael Jurka                        String.format(getContext().getString(R.string.folder_opened),
4323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        mContent.getCountX(), mContent.getCountY()));
433df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                mState = STATE_ANIMATING;
434df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
435df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
436df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationEnd(Animator animation) {
4372801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                mState = STATE_OPEN;
4380121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka                setLayerType(LAYER_TYPE_NONE, null);
4397a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                Cling cling = mLauncher.showFirstRunFoldersCling();
4407a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                if (cling != null) {
4417a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                    cling.bringToFront();
4427a74ac9cd68db5e8bba87bbda43f73cea9c427c8Winson Chung                }
443ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                setFocusOnFirstChild();
444df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
445df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        });
4462801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.setDuration(mExpandDuration);
4470121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        setLayerType(LAYER_TYPE_HARDWARE, null);
448f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        oa.start();
449df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
450df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
4513371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendCustomAccessibilityEvent(int type, String text) {
4528b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
4538b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
4548b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
4553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(type);
4563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
4573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            event.getText().add(text);
4588b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
4593371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
4603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
4613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
462ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private void setFocusOnFirstChild() {
463ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View firstChild = mContent.getChildAt(0, 0);
464ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        if (firstChild != null) {
465ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            firstChild.requestFocus();
466ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
467ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
468ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
469df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public void animateClosed() {
4708e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        if (!(getParent() instanceof DragLayer)) return;
471662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
472662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
473662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
4740121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        final ObjectAnimator oa = mOpenCloseAnimator =
4752ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
476df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
4772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.addListener(new AnimatorListenerAdapter() {
478df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
479df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationEnd(Animator animation) {
4802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                onCloseComplete();
4810121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka                setLayerType(LAYER_TYPE_NONE, null);
4822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                mState = STATE_SMALL;
483df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
484df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            @Override
485df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            public void onAnimationStart(Animator animation) {
4863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
4878b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getString(R.string.folder_closed));
488df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                mState = STATE_ANIMATING;
489df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            }
490df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        });
4912801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        oa.setDuration(mExpandDuration);
4920121c3ea3d5bae176af193ea8ef23ae8a868dd31Michael Jurka        setLayerType(LAYER_TYPE_HARDWARE, null);
493f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        oa.start();
494df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
495df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
496df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    void notifyDataSetChanged() {
497df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        // recreate all the children if the data set changes under us. We may want to do this more
498df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        // intelligently (ie just removing the views that should no longer exist)
499df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mContent.removeAllViewsInLayout();
500df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        bind(mInfo);
501df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
502df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
503cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public boolean acceptDrop(DragObject d) {
504cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        final ItemInfo item = (ItemInfo) d.dragInfo;
505df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        final int itemType = item.itemType;
5062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
5072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                    itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
5082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                    !isFull());
509df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
510df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
511df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    protected boolean findAndSetEmptyCells(ShortcutInfo item) {
512df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        int[] emptyCell = new int[2];
513df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
514df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            item.cellX = emptyCell[0];
515df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            item.cellY = emptyCell[1];
516df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            return true;
517df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        } else {
518df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            return false;
519df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
520df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
521df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
522c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen    protected boolean createAndAddShortcut(ShortcutInfo item) {
523df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        final TextView textView =
524e87b924efaaf1cfb555a4327dc653929a4c182f1Adam Cohen            (TextView) mInflater.inflate(R.layout.application, this, false);
525df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setCompoundDrawablesWithIntrinsicBounds(null,
526df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
527df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setText(item.title);
528df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setTag(item);
529df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
530df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setOnClickListener(this);
531df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        textView.setOnLongClickListener(this);
532df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
533c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        // We need to check here to verify that the given item's location isn't already occupied
5343bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen        // by another item.
5350057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen        if (mContent.getChildAt(item.cellX, item.cellY) != null || item.cellX < 0 || item.cellY < 0
5360057bbcfa4a2ee12c5e87cba8c3fac8eadb078edAdam Cohen                || item.cellX >= mContent.getCountX() || item.cellY >= mContent.getCountY()) {
5373bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            // This shouldn't happen, log it.
5383bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen            Log.e(TAG, "Folder order not properly persisted during bind");
539c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            if (!findAndSetEmptyCells(item)) {
540c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen                return false;
541c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen            }
542c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        }
543c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen
544df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        CellLayout.LayoutParams lp =
545df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
546df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        boolean insert = false;
547ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        textView.setOnKeyListener(new FolderKeyEventListener());
548df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
549c508b2d701ef980875f7ebc71bf2d87781159478Adam Cohen        return true;
550df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
551df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
552cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public void onDragEnter(DragObject d) {
553bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mPreviousTargetCell[0] = -1;
554bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mPreviousTargetCell[1] = -1;
555bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mOnExitAlarm.cancelAlarm();
556df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
557df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
558bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
559bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        public void onAlarm(Alarm alarm) {
560bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            realTimeReorder(mEmptyCell, mTargetCell);
561bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
562bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    };
563bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
564bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    boolean readingOrderGreaterThan(int[] v1, int[] v2) {
565bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) {
566bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
567bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
568bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return false;
569bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
570df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
571df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
572bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private void realTimeReorder(int[] empty, int[] target) {
573bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        boolean wrap;
574bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int startX;
575bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int endX;
576bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int startY;
57776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        int delay = 0;
57876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        float delayAmount = 30;
579bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (readingOrderGreaterThan(target, empty)) {
580bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            wrap = empty[0] >= mContent.getCountX() - 1;
581bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            startY = wrap ? empty[1] + 1 : empty[1];
582bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            for (int y = startY; y <= target[1]; y++) {
583bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                startX = y == empty[1] ? empty[0] + 1 : 0;
584bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                endX = y < target[1] ? mContent.getCountX() - 1 : target[0];
585bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                for (int x = startX; x <= endX; x++) {
586bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    View v = mContent.getChildAt(x,y);
587bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
588482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            REORDER_ANIMATION_DURATION, delay, true, true)) {
589bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[0] = x;
590bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[1] = y;
59176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delay += delayAmount;
59276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delayAmount *= 0.9;
593bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
594bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
595bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
596bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
597bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            wrap = empty[0] == 0;
598bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            startY = wrap ? empty[1] - 1 : empty[1];
599bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            for (int y = startY; y >= target[1]; y--) {
600bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                startX = y == empty[1] ? empty[0] - 1 : mContent.getCountX() - 1;
601bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                endX = y > target[1] ? 0 : target[0];
602bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                for (int x = startX; x >= endX; x--) {
603bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    View v = mContent.getChildAt(x,y);
604bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            REORDER_ANIMATION_DURATION, delay, true, true)) {
606bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[0] = x;
607bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        empty[1] = y;
60876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delay += delayAmount;
60976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        delayAmount *= 0.9;
610bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
611bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
612bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
613bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
614bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
615bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
6162374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    public boolean isLayoutRtl() {
6172374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
6182374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    }
6192374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
620bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDragOver(DragObject d) {
621bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, null);
622bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1], 1, 1, mTargetCell);
623bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
6242374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        if (isLayoutRtl()) {
6252374abfda3e53f84e005df8923170308e4df8c03Adam Cohen            mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
6262374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        }
6272374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
628bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (mTargetCell[0] != mPreviousTargetCell[0] || mTargetCell[1] != mPreviousTargetCell[1]) {
629bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mReorderAlarm.cancelAlarm();
630bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
631bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mReorderAlarm.setAlarm(150);
632bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mPreviousTargetCell[0] = mTargetCell[0];
633bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mPreviousTargetCell[1] = mTargetCell[1];
634bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
635df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
636df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
637bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // This is used to compute the visual center of the dragView. The idea is that
638bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // the visual center represents the user's interpretation of where the item is, and hence
639bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    // is the appropriate point to use when determining drop location.
640bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
641bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            DragView dragView, float[] recycle) {
642bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        float res[];
643bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (recycle == null) {
644bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            res = new float[2];
645bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
646bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            res = recycle;
647df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        }
6482801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
649bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // These represent the visual top and left of drag view if a dragRect was provided.
650bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // If a dragRect was not provided, then they correspond to the actual view left and
651bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // top, as the dragRect is in that case taken to be the entire dragView.
652bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // R.dimen.dragViewOffsetY.
653bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int left = x - xOffset;
654bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        int top = y - yOffset;
655bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
656bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // In order to find the visual center, we shift by half the dragRect
657bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        res[0] = left + dragView.getDragRegion().width() / 2;
658bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        res[1] = top + dragView.getDragRegion().height() / 2;
659bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
660bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return res;
661bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
662bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
663bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
664bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        public void onAlarm(Alarm alarm) {
6653e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            completeDragExit();
666bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
667bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    };
6682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
66995bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen    public void completeDragExit() {
6703e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mLauncher.closeFolder();
6713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mCurrentDragInfo = null;
6723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mCurrentDragView = null;
6733e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mSuppressOnAdd = false;
6743e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mRearrangeOnClose = true;
6753e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
6763e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
677bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDragExit(DragObject d) {
678bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // We only close the folder if this is a true drag exit, ie. not because a drop
679bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        // has occurred above the folder.
680bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (!d.dragComplete) {
681bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mOnExitAlarm.setOnAlarmListener(mOnExitAlarmListener);
682bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
683bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
684bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mReorderAlarm.cancelAlarm();
6852801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
6862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
687a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
688a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung            boolean success) {
68967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        if (success) {
69005e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
69167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                replaceFolderWithFinalItem();
69267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
69367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        } else {
69467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            // The drag failed, we need to return the item to the folder
69567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            mFolderIcon.onDrop(d);
69667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen
69767bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            // We're going to trigger a "closeFolder" which may occur before this item has
69867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            // been added back to the folder -- this could cause the folder to be deleted
69967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            if (mOnExitAlarm.alarmPending()) {
70067bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                mSuppressFolderDeletion = true;
70167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
70267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        }
70367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen
70467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        if (target != this) {
70567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            if (mOnExitAlarm.alarmPending()) {
70667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                mOnExitAlarm.cancelAlarm();
70767bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                completeDragExit();
70867bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
70967bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        }
71067bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mDeleteFolderOnDropCompleted = false;
71167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mDragInProgress = false;
71205e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        mItemAddedBackToSelfViaIcon = false;
713bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mCurrentDragInfo = null;
714bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mCurrentDragView = null;
715bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mSuppressOnAdd = false;
7164045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen
7174045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        // Reordering may have occured, and we need to save the new item locations. We do this once
7184045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        // at the end to prevent unnecessary database operations.
7194045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        updateItemLocationsInDatabase();
7204045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    }
7214045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen
722a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
723043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public boolean supportsFlingToDelete() {
724043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        return true;
725043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
726043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
727a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
728a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // Do nothing
729a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
730a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
731a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
732a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onFlingToDeleteCompleted() {
733a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // Do nothing
734a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
735a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
7364045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    private void updateItemLocationsInDatabase() {
7374045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        ArrayList<View> list = getItemsInReadingOrder();
7384045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        for (int i = 0; i < list.size(); i++) {
7394045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            View v = list.get(i);
7404045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            ItemInfo info = (ItemInfo) v.getTag();
7414045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0,
7424045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen                        info.cellX, info.cellY);
7434045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        }
74467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    }
745228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohen
74667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen    public void notifyDrop() {
74767bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        if (mDragInProgress) {
74805e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen            mItemAddedBackToSelfViaIcon = true;
74976078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        }
750df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
751df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
752df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    public boolean isDropEnabled() {
753df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        return true;
754df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen    }
755df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen
756cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public DropTarget getDropTargetDelegate(DragObject d) {
757df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen        return null;
75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
759a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
7604045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen    private void setupContentDimensions(int count) {
7612801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        ArrayList<View> list = getItemsInReadingOrder();
7622801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
7632801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int countX = mContent.getCountX();
7642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int countY = mContent.getCountY();
7657c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        boolean done = false;
7667c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen
7677c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        while (!done) {
7687c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            int oldCountX = countX;
7697c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            int oldCountY = countY;
7707c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            if (countX * countY < count) {
7717c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                // Current grid is too small, expand it
77278dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen                if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
7737c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    countX++;
7747c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                } else if (countY < mMaxCountY) {
7757c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    countY++;
7767c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                }
7777c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                if (countY == 0) countY++;
7787c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            } else if ((countY - 1) * countX >= count && countY >= countX) {
7797c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                countY = Math.max(0, countY - 1);
7807c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            } else if ((countX - 1) * countY >= count) {
7817c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                countX = Math.max(0, countX - 1);
7822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
7837c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            done = countX == oldCountX && countY == oldCountY;
7842801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
7857c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mContent.setGridSize(countX, countY);
7862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        arrangeChildren(list);
7872801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
7882801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
7892801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public boolean isFull() {
79078dc83e875fdf541881cfb867ec38bee21d546e9Adam Cohen        return getItemCount() >= mMaxNumItems;
7912801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
7922801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
7932801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void centerAboutIcon() {
7948e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
7952801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
7962801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
797f4bb1cdecd3cf866a1d87b7b8560234fa7dd4cc5Adam Cohen        int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight()
798f4bb1cdecd3cf866a1d87b7b8560234fa7dd4cc5Adam Cohen                + mFolderNameHeight;
7998e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
8008e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen
801307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect);
8022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
803307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int centerX = (int) (mTempRect.left + mTempRect.width() * scale / 2);
804307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int centerY = (int) (mTempRect.top + mTempRect.height() * scale / 2);
8052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int centeredLeft = centerX - width / 2;
8062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int centeredTop = centerY - height / 2;
8072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8087cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        int currentPage = mLauncher.getWorkspace().getCurrentPage();
8097cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // In case the workspace is scrolling, we need to use the final scroll to compute
8107cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // the folders bounds.
8117cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        mLauncher.getWorkspace().setFinalScrollForPageChange(currentPage);
81235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // We first fetch the currently visible CellLayoutChildren
8137cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        CellLayout currentLayout = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPage);
814a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer boundingLayout = currentLayout.getShortcutsAndWidgets();
81535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        Rect bounds = new Rect();
81635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
8177cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        // We reset the workspaces scroll
8187cc1bc4b657630250515ee8b1f65b77417e4c9b3Adam Cohen        mLauncher.getWorkspace().resetFinalScrollForPageChange(currentPage);
81935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
82035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // We need to bound the folder to the currently visible CellLayoutChildren
82135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        int left = Math.min(Math.max(bounds.left, centeredLeft),
82235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen                bounds.left + bounds.width() - width);
82335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        int top = Math.min(Math.max(bounds.top, centeredTop),
82435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen                bounds.top + bounds.height() - height);
82535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        // If the folder doesn't fit within the bounds, center it about the desired bounds
82635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        if (width >= bounds.width()) {
82735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen            left = bounds.left + (bounds.width() - width) / 2;
82835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        }
82935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        if (height >= bounds.height()) {
83035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen            top = bounds.top + (bounds.height() - height) / 2;
8310e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen        }
8322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int folderPivotX = width / 2 + (centeredLeft - left);
8342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int folderPivotY = height / 2 + (centeredTop - top);
8352801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        setPivotX(folderPivotX);
8362801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        setPivotY(folderPivotY);
837268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        mFolderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
8382801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (1.0f * folderPivotX / width));
839268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        mFolderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
8402801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (1.0f * folderPivotY / height));
8413bf84d3250bf45f2a5b041245e9bd327e03e22c0Adam Cohen
842662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.width = width;
843662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.height = height;
844662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.x = left;
845662b598c86a1772d95303ef9c921d4bbe342387bAdam Cohen        lp.y = top;
8462801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
8472801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
848268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    float getPivotXForIconAnimation() {
849268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        return mFolderIconPivotX;
850268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    }
851268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    float getPivotYForIconAnimation() {
852268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen        return mFolderIconPivotY;
853268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen    }
854268c4751b547e1470a94030af73a4e7bb8ea221eAdam Cohen
8552801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void setupContentForNumItems(int count) {
8564045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen        setupContentDimensions(count);
8572801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8588e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
8592801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (lp == null) {
8608e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen            lp = new DragLayer.LayoutParams(0, 0);
8618e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen            lp.customPosition = true;
8622801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setLayoutParams(lp);
8632801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
8642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        centerAboutIcon();
8652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
8662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
867234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
868234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
869f4bb1cdecd3cf866a1d87b7b8560234fa7dd4cc5Adam Cohen        int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight()
870f4bb1cdecd3cf866a1d87b7b8560234fa7dd4cc5Adam Cohen                + mFolderNameHeight;
871234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen
872234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        int contentWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
873234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.EXACTLY);
874234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        int contentHeightSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredHeight(),
875234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.EXACTLY);
876234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mContent.measure(contentWidthSpec, contentHeightSpec);
877234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen
878234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mFolderName.measure(contentWidthSpec,
879234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen                MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
880234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        setMeasuredDimension(width, height);
881234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    }
882234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen
8832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void arrangeChildren(ArrayList<View> list) {
8842801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int[] vacant = new int[2];
8852801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (list == null) {
8862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            list = getItemsInReadingOrder();
8872801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
8882801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mContent.removeAllViews();
8892801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
8902801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int i = 0; i < list.size(); i++) {
8912801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            View v = list.get(i);
8922801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mContent.getVacantCell(vacant, 1, 1);
8932801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
8942801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            lp.cellX = vacant[0];
8952801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            lp.cellY = vacant[1];
8962801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            ItemInfo info = (ItemInfo) v.getTag();
8972792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen            if (info.cellX != vacant[0] || info.cellY != vacant[1]) {
8982792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                info.cellX = vacant[0];
8992792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                info.cellY = vacant[1];
9002792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
9012792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen                        info.cellX, info.cellY);
9022792a33ecc9b2def0cdd31756c45f5fe73cf13acAdam Cohen            }
9032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            boolean insert = false;
9042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
9052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
9067c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mItemsInvalidated = true;
9072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
9082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
909a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public int getItemCount() {
910a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mContent.getShortcutsAndWidgets().getChildCount();
911a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
912a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
913a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public View getItemAt(int index) {
914a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mContent.getShortcutsAndWidgets().getChildAt(index);
915a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
916a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
9172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    private void onCloseComplete() {
91805e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        DragLayer parent = (DragLayer) getParent();
9195649c287039ea7908112b41604c3fc2893c4697eMichael Jurka        if (parent != null) {
9205649c287039ea7908112b41604c3fc2893c4697eMichael Jurka            parent.removeView(this);
9215649c287039ea7908112b41604c3fc2893c4697eMichael Jurka        }
9224554ee16f122a3dbd9a8d3b828f1c8c7e7b7fe99Adam Cohen        mDragController.removeDropTarget((DropTarget) this);
92305e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        clearFocus();
924ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        mFolderIcon.requestFocus();
92505e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen
9262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (mRearrangeOnClose) {
9272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setupContentForNumItems(getItemCount());
9282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mRearrangeOnClose = false;
9292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
930afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (getItemCount() <= 1) {
93167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            if (!mDragInProgress && !mSuppressFolderDeletion) {
93267bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                replaceFolderWithFinalItem();
93367bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            } else if (mDragInProgress) {
93467bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen                mDeleteFolderOnDropCompleted = true;
93567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen            }
936afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
93767bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mSuppressFolderDeletion = false;
938afb01ee74243cede19088e694ca82cea5983c603Adam Cohen    }
939afb01ee74243cede19088e694ca82cea5983c603Adam Cohen
940afb01ee74243cede19088e694ca82cea5983c603Adam Cohen    private void replaceFolderWithFinalItem() {
941fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // Add the last remaining child to the workspace in place of the folder
942fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
943fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            @Override
944fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            public void run() {
945fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen);
946fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
947c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen               View child = null;
948fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                // Move the item from the folder to the workspace, in the position of the folder
949fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                if (getItemCount() == 1) {
950fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    ShortcutInfo finalItem = mInfo.contents.get(0);
951c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                    child = mLauncher.createShortcut(R.layout.application, cellLayout,
952fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                            finalItem);
953fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
954fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                            mInfo.screen, mInfo.cellX, mInfo.cellY);
955fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
956487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                if (getItemCount() <= 1) {
957487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    // Remove the folder
958487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
959487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    cellLayout.removeView(mFolderIcon);
960487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    if (mFolderIcon instanceof DropTarget) {
961487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
962487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    }
963487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    mLauncher.removeFolder(mInfo);
964487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                }
965c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                // We add the child after removing the folder to prevent both from existing at
966c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                // the same time in the CellLayout.
967c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                if (child != null) {
968c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                    mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen,
969c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                            mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
970c5e63f3dc7f19d0da8380e425894450302700ab9Adam Cohen                }
971fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            }
972fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        };
973fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        View finalChild = getItemAt(0);
974fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        if (finalChild != null) {
975fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
976afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
977fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        mDestroyed = true;
978fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
979afb01ee74243cede19088e694ca82cea5983c603Adam Cohen
980fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    boolean isDestroyed() {
981fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mDestroyed;
9822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
9832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
984ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    // This method keeps track of the last item in the folder for the purposes
985ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    // of keyboard focus
986ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private void updateTextViewFocus() {
987ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View lastChild = getItemAt(getItemCount() - 1);
988ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        getItemAt(getItemCount() - 1);
989ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        if (lastChild != null) {
990ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusDownId(lastChild.getId());
991ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusRightId(lastChild.getId());
992ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusLeftId(lastChild.getId());
993ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            mFolderName.setNextFocusUpId(lastChild.getId());
994ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
995ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
996ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
997bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onDrop(DragObject d) {
998bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        ShortcutInfo item;
999bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (d.dragInfo instanceof ApplicationInfo) {
1000bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // Came from all apps -- make a copy
1001bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item = ((ApplicationInfo) d.dragInfo).makeShortcut();
1002bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item.spanX = 1;
1003bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item.spanY = 1;
1004bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        } else {
1005bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            item = (ShortcutInfo) d.dragInfo;
1006bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
100705e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // Dragged from self onto self, currently this is the only path possible, however
100805e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // we keep this as a distinct code path.
1009bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (item == mCurrentDragInfo) {
1010bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
1011bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
1012bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            si.cellX = lp.cellX = mEmptyCell[0];
1013bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            si.cellX = lp.cellY = mEmptyCell[1];
1014bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
1015fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            if (d.dragView.hasDrawn()) {
1016fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView);
1017fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            } else {
10182c4cf411f6c30fb2bfb47d2b13b680bda7a266dcWinson Chung                d.deferDragViewCleanupPostAnimation = false;
1019fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                mCurrentDragView.setVisibility(VISIBLE);
1020fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            }
1021e9166b247addcf67542ababb9d453f5bfb33c7b2Adam Cohen            mItemsInvalidated = true;
10224045eb736e76374ec8b53b4cea2eaea47c72db4aAdam Cohen            setupContentDimensions(getItemCount());
1023716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            mSuppressOnAdd = true;
1024bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1025bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mInfo.add(item);
1026bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1027bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1028bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    public void onAdd(ShortcutInfo item) {
1029bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mItemsInvalidated = true;
103005e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // If the item was dropped onto this open folder, we have done the work associated
103105e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // with adding the item to the folder, as indicated by mSuppressOnAdd being set
1032bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (mSuppressOnAdd) return;
1033bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (!findAndSetEmptyCells(item)) {
1034bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // The current layout is full, can we expand it?
1035bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            setupContentForNumItems(getItemCount() + 1);
1036bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            findAndSetEmptyCells(item);
1037bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1038bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        createAndAddShortcut(item);
1039bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        LauncherModel.addOrMoveItemInDatabase(
1040bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
1041bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1042bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1043a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
10447c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        mItemsInvalidated = true;
104505e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // If this item is being dragged from this open folder, we have already handled
104605e0f40e50574f50678a9e1461cb245cddc46abbAdam Cohen        // the work associated with removing the item, so we don't have to do anything here.
1047bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        if (item == mCurrentDragInfo) return;
1048df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        View v = getViewForInfo(item);
1049a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        mContent.removeView(v);
10502801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (mState == STATE_ANIMATING) {
10512801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            mRearrangeOnClose = true;
10522801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        } else {
10532801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            setupContentForNumItems(getItemCount());
10542801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1055afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        if (getItemCount() <= 1) {
1056afb01ee74243cede19088e694ca82cea5983c603Adam Cohen            replaceFolderWithFinalItem();
1057afb01ee74243cede19088e694ca82cea5983c603Adam Cohen        }
1058a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
10597c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen
1060df1e4e868a1970b756486dadd652651d40276d36Adam Cohen    private View getViewForInfo(ShortcutInfo item) {
1061df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        for (int j = 0; j < mContent.getCountY(); j++) {
1062df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            for (int i = 0; i < mContent.getCountX(); i++) {
1063df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                View v = mContent.getChildAt(i, j);
1064df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                if (v.getTag() == item) {
1065df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                    return v;
1066df1e4e868a1970b756486dadd652651d40276d36Adam Cohen                }
1067df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            }
1068df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        }
1069df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        return null;
1070df1e4e868a1970b756486dadd652651d40276d36Adam Cohen    }
1071df1e4e868a1970b756486dadd652651d40276d36Adam Cohen
107276078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public void onItemsChanged() {
1073ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        updateTextViewFocus();
107476078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
1075ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
107676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
107776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
107876078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
10797c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    public ArrayList<View> getItemsInReadingOrder() {
108076078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        return getItemsInReadingOrder(true);
108176078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
108276078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
108376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public ArrayList<View> getItemsInReadingOrder(boolean includeCurrentDragItem) {
10847c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        if (mItemsInvalidated) {
10857c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            mItemsInReadingOrder.clear();
10867c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            for (int j = 0; j < mContent.getCountY(); j++) {
10877c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                for (int i = 0; i < mContent.getCountX(); i++) {
10887c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    View v = mContent.getChildAt(i, j);
10897c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    if (v != null) {
109076078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                        ShortcutInfo info = (ShortcutInfo) v.getTag();
109176078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                        if (info != mCurrentDragInfo || includeCurrentDragItem) {
109276078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                            mItemsInReadingOrder.add(v);
109376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                        }
10947c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                    }
10957c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen                }
10967c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            }
10977c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen            mItemsInvalidated = false;
10987c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        }
10997c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen        return mItemsInReadingOrder;
11007c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohen    }
11018dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
11028dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public void getLocationInDragLayer(int[] loc) {
11038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
11048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
1105ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen
1106ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen    public void onFocusChange(View v, boolean hasFocus) {
1107ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        if (v == mFolderName && hasFocus) {
1108ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen            startEditingFolderName();
1109ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen        }
1110ea0818d475df26d498ce08105bc2bc5582fce5a9Adam Cohen    }
111131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
1112