1290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal/**
2290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * Copyright (C) 2015 The Android Open Source Project
3290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal *
4290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * Licensed under the Apache License, Version 2.0 (the "License");
5290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * you may not use this file except in compliance with the License.
6290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * You may obtain a copy of the License at
7290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal *
8290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal *      http://www.apache.org/licenses/LICENSE-2.0
9290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal *
10290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * Unless required by applicable law or agreed to in writing, software
11290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * distributed under the License is distributed on an "AS IS" BASIS,
12290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * See the License for the specific language governing permissions and
14290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal * limitations under the License.
15290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal */
16290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
17f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenpackage com.android.launcher3.folder;
18290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
19e4766230ff8115c5897ebee74c145bcae822581eSunny Goyalimport android.annotation.SuppressLint;
20290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport android.content.Context;
213333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyalimport android.graphics.Canvas;
22290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport android.util.AttributeSet;
23290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport android.util.Log;
24b7e15adc7b67cb1d70ca72014b200dd6cbbf166aSunny Goyalimport android.view.Gravity;
25290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport android.view.LayoutInflater;
26290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport android.view.View;
274ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyalimport android.view.ViewDebug;
284846193300245c8c0a1f9bde3175f273df044309Sunny Goyalimport android.view.animation.DecelerateInterpolator;
29290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
30f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.BubbleTextView;
31f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.CellLayout;
32f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.DeviceProfile;
33290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
34f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.InvariantDeviceProfile;
35f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.ItemInfo;
36f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.Launcher;
37f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.LauncherAppState;
38f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.LauncherModel;
39f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.PagedView;
40f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.R;
41f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.ShortcutAndWidgetContainer;
42f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.ShortcutInfo;
43f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.Utilities;
44290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport com.android.launcher3.Workspace.ItemOperator;
45fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.dragndrop.DragController;
463333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyalimport com.android.launcher3.keyboard.ViewGroupFocusHelper;
476e74e899d314663415f54895227bb79a51fd734bTony Wickhamimport com.android.launcher3.pageindicators.PageIndicator;
481f3f07d47c29cba3b70bcd15ebb65a077f55a558Sunny Goyalimport com.android.launcher3.util.Themes;
49091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
50290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
51290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport java.util.ArrayList;
52290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport java.util.HashMap;
53290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyalimport java.util.Iterator;
544846193300245c8c0a1f9bde3175f273df044309Sunny Goyalimport java.util.Map;
55290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
56b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyalpublic class FolderPagedView extends PagedView {
57290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
58290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private static final String TAG = "FolderPagedView";
59290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
60b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    private static final boolean ALLOW_FOLDER_SCROLL = true;
61b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal
62290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private static final int REORDER_ANIMATION_DURATION = 230;
634846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    private static final int START_VIEW_REORDER_DELAY = 30;
644846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
655d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal
663b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal    /**
673b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal     * Fraction of the width to scroll when showing the next page hint.
683b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal     */
693b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal    private static final float SCROLL_HINT_FRACTION = 0.07f;
703b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal
71290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private static final int[] sTempPosArray = new int[2];
72290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
737066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal    public final boolean mIsRtl;
743b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal
75290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private final LayoutInflater mInflater;
763333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    private final ViewGroupFocusHelper mFocusIndicatorHelper;
77091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen
78091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
79290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
804ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyal    @ViewDebug.ExportedProperty(category = "launcher")
81e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    private final int mMaxCountX;
824ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyal    @ViewDebug.ExportedProperty(category = "launcher")
83e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    private final int mMaxCountY;
844ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyal    @ViewDebug.ExportedProperty(category = "launcher")
85e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    private final int mMaxItemsPerPage;
86290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
87290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private int mAllocatedContentSize;
884ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyal    @ViewDebug.ExportedProperty(category = "launcher")
89290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private int mGridCountX;
904ffec48dec5da7bcf719ac0c37ee5e58f9ea2c1aSunny Goyal    @ViewDebug.ExportedProperty(category = "launcher")
91290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private int mGridCountY;
92290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
93290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private Folder mFolder;
94290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private PagedFolderKeyEventListener mKeyListener;
95290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
96c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal    private PageIndicator mPageIndicator;
975d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal
98290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public FolderPagedView(Context context, AttributeSet attrs) {
99290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        super(context, attrs);
10087f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal        InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
1012c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung        mMaxCountX = profile.numFolderColumns;
1022c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung        mMaxCountY = profile.numFolderRows;
103b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal
104290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        mMaxItemsPerPage = mMaxCountX * mMaxCountY;
105290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
106290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        mInflater = LayoutInflater.from(context);
1073b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal
1087066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal        mIsRtl = Utilities.isRtl(getResources());
109db184fdc7bd652e45216a453541ab4a266457a3aSunny Goyal        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
1104d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal
1111f3f07d47c29cba3b70bcd15ebb65a077f55a558Sunny Goyal        setEdgeGlowColor(Themes.getAttrColor(context, android.R.attr.colorEdgeEffect));
1123333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
113290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
114290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
115290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void setFolder(Folder folder) {
116290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        mFolder = folder;
117290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        mKeyListener = new PagedFolderKeyEventListener(folder);
118c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal        mPageIndicator = (PageIndicator) folder.findViewById(R.id.folder_page_indicator);
119d0a6ae7f645e6ba564aebb50316c53fa2e119459Sunny Goyal        initParentViews(folder);
120290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
121290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
122290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    /**
123290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * Sets up the grid size such that {@param count} items can fit in the grid.
124290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
125290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * maintaining the restrictions of {@link #mMaxCountX} &amp; {@link #mMaxCountY}.
126290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     */
127290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    private void setupContentDimensions(int count) {
128290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        mAllocatedContentSize = count;
129290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        boolean done;
130290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (count >= mMaxItemsPerPage) {
131290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            mGridCountX = mMaxCountX;
132290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            mGridCountY = mMaxCountY;
133290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            done = true;
134290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        } else {
135290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            done = false;
136290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
137290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
138290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        while (!done) {
139290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int oldCountX = mGridCountX;
140290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int oldCountY = mGridCountY;
141290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (mGridCountX * mGridCountY < count) {
142290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Current grid is too small, expand it
143290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                if ((mGridCountX <= mGridCountY || mGridCountY == mMaxCountY) && mGridCountX < mMaxCountX) {
144290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    mGridCountX++;
145290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                } else if (mGridCountY < mMaxCountY) {
146290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    mGridCountY++;
147290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                }
148290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                if (mGridCountY == 0) mGridCountY++;
149290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            } else if ((mGridCountY - 1) * mGridCountX >= count && mGridCountY >= mGridCountX) {
150290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                mGridCountY = Math.max(0, mGridCountY - 1);
151290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            } else if ((mGridCountX - 1) * mGridCountY >= count) {
152290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                mGridCountX = Math.max(0, mGridCountX - 1);
153290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
154290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            done = mGridCountX == oldCountX && mGridCountY == oldCountY;
155290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
156290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
157e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        // Update grid size
158e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        for (int i = getPageCount() - 1; i >= 0; i--) {
159290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            getPageAt(i).setGridSize(mGridCountX, mGridCountY);
160290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
161290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
162290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
1633333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    @Override
1643333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    protected void dispatchDraw(Canvas canvas) {
1653333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        mFocusIndicatorHelper.draw(canvas);
1663333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        super.dispatchDraw(canvas);
1673333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    }
1683333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal
169b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
170b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * Binds items to the layout.
171b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * @return list of items that could not be bound, probably because we hit the max size limit.
172b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
173290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
174e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        ArrayList<View> icons = new ArrayList<View>();
175b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal        ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
176b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal
177290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (ShortcutInfo item : items) {
178b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal            if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
179b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal                extra.add(item);
180b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal            } else {
181b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal                icons.add(createNewView(item));
182b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal            }
183290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
184e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        arrangeChildren(icons, icons.size(), false);
185b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal        return extra;
186290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
187290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
188290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    /**
189290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * Create space for a new item at the end, and returns the rank for that item.
190290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * Also sets the current page to the last page.
191290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     */
192e393d3af369c452f3b5f5d9c0a23a83aa3aa736bSunny Goyal    public int allocateRankForNewItem() {
193290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int rank = getItemCount();
1948f288aac99a11d52fd9747f360a8ce3bb521b17aWinson        ArrayList<View> views = new ArrayList<>(mFolder.getItemsInReadingOrder());
1955d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        views.add(rank, null);
1965d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        arrangeChildren(views, views.size(), false);
1975d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        setCurrentPage(rank / mMaxItemsPerPage);
198290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return rank;
199290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
200290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
201290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public View createAndAddViewForRank(ShortcutInfo item, int rank) {
202e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        View icon = createNewView(item);
2035d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        addViewForRank(icon, item, rank);
204e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        return icon;
205290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
206290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
207b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
208b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * Adds the {@param view} to the layout based on {@param rank} and updated the position
209b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * related attributes. It assumes that {@param item} is already attached to the view.
210b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
211290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void addViewForRank(View view, ShortcutInfo item, int rank) {
212e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        int pagePos = rank % mMaxItemsPerPage;
213e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        int pageNo = rank / mMaxItemsPerPage;
214290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
215290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        item.rank = rank;
216290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        item.cellX = pagePos % mGridCountX;
217290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        item.cellY = pagePos / mGridCountX;
218290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
219e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
220e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        lp.cellX = item.cellX;
221e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        lp.cellY = item.cellY;
222e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        getPageAt(pageNo).addViewToCellLayout(
223e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal                view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
224290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
225290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
226e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    @SuppressLint("InflateParams")
227b8c663c492d32963b6ee33750fc985f037c58f10Sunny Goyal    public View createNewView(ShortcutInfo item) {
228290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
229e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal                R.layout.folder_application, null, false);
2301cd01b023acc123b771765b7297d8aaedac224e0Sunny Goyal        textView.applyFromShortcutInfo(item);
231290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        textView.setOnClickListener(mFolder);
232290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        textView.setOnLongClickListener(mFolder);
2333333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        textView.setOnFocusChangeListener(mFocusIndicatorHelper);
234290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        textView.setOnKeyListener(mKeyListener);
235290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
236e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        textView.setLayoutParams(new CellLayout.LayoutParams(
237e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal                item.cellX, item.cellY, item.spanX, item.spanY));
238290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return textView;
239290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
240290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
241290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    @Override
242290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public CellLayout getPageAt(int index) {
243290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return (CellLayout) getChildAt(index);
244290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
245290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
246290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public CellLayout getCurrentCellLayout() {
247290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return getPageAt(getNextPage());
248290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
249290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
250e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    private CellLayout createAndAddNewPage() {
2512fd020860533e18c64a93d14d11cb2d34bc9cbafTony        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
252c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal        CellLayout page = (CellLayout) mInflater.inflate(R.layout.folder_page, this, false);
253e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
254e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
255e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        page.setInvertIfRtl(true);
256e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        page.setGridSize(mGridCountX, mGridCountY);
257290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
25822fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal        addView(page, -1, generateDefaultLayoutParams());
259e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        return page;
260290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
261290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
262a1fbd84b791474a9e86b67caeaf27b8429afba73Sunny Goyal    @Override
263a1fbd84b791474a9e86b67caeaf27b8429afba73Sunny Goyal    protected int getChildGap() {
264a1fbd84b791474a9e86b67caeaf27b8429afba73Sunny Goyal        return getPaddingLeft() + getPaddingRight();
265a1fbd84b791474a9e86b67caeaf27b8429afba73Sunny Goyal    }
266a1fbd84b791474a9e86b67caeaf27b8429afba73Sunny Goyal
267290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void setFixedSize(int width, int height) {
26822fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal        width -= (getPaddingLeft() + getPaddingRight());
26922fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal        height -= (getPaddingTop() + getPaddingBottom());
270290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (int i = getChildCount() - 1; i >= 0; i --) {
271290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            ((CellLayout) getChildAt(i)).setFixedSize(width, height);
272290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
273290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
274290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
275290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void removeItem(View v) {
276290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (int i = getChildCount() - 1; i >= 0; i --) {
277290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            getPageAt(i).removeView(v);
278290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
279290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
280290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
281c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal    @Override
282c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
283c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal        super.onScrollChanged(l, t, oldl, oldt);
284c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal        mPageIndicator.setScroll(l, mMaxScrollX);
285c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal    }
286c64cfdd8fa18de45fc1646c8ef2449f39ef83022Sunny Goyal
287290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    /**
288290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * Updates position and rank of all the children in the view.
289290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * It essentially removes all views from all the pages and then adds them again in appropriate
290290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * page.
291290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     *
292290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * @param list the ordered list of children.
293290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * @param itemCount if greater than the total children count, empty spaces are left
294290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     * at the end, otherwise it is ignored.
295290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     *
296290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal     */
297290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void arrangeChildren(ArrayList<View> list, int itemCount) {
298e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        arrangeChildren(list, itemCount, true);
299e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    }
300e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal
301a07c2f5c80908e8a612f4681314a7068b92baa9fSunny Goyal    @SuppressLint("RtlHardcoded")
302e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal    private void arrangeChildren(ArrayList<View> list, int itemCount, boolean saveChanges) {
303290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        ArrayList<CellLayout> pages = new ArrayList<CellLayout>();
304290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (int i = 0; i < getChildCount(); i++) {
305290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            CellLayout page = (CellLayout) getChildAt(i);
306290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            page.removeAllViews();
307290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            pages.add(page);
308290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
309290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        setupContentDimensions(itemCount);
310290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
311290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        Iterator<CellLayout> pageItr = pages.iterator();
312290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        CellLayout currentPage = null;
313290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
314290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int position = 0;
315290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int newX, newY, rank;
316290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
317290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        rank = 0;
3184846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        for (int i = 0; i < itemCount; i++) {
3194846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            View v = list.size() > i ? list.get(i) : null;
320290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (currentPage == null || position >= mMaxItemsPerPage) {
321290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Next page
322290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                if (pageItr.hasNext()) {
323290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    currentPage = pageItr.next();
324290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                } else {
325e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal                    currentPage = createAndAddNewPage();
326290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                }
327290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                position = 0;
328290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
329290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
3304846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            if (v != null) {
3314846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
3324846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                newX = position % mGridCountX;
3334846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                newY = position / mGridCountX;
3344846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                ItemInfo info = (ItemInfo) v.getTag();
3354846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                if (info.cellX != newX || info.cellY != newY || info.rank != rank) {
3364846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                    info.cellX = newX;
3374846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                    info.cellY = newY;
3384846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                    info.rank = rank;
3394846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                    if (saveChanges) {
34043bf11d9c95f76c2dfeb625b23cb458df81252b3Sunny Goyal                        mFolder.mLauncher.getModelWriter().addOrMoveItemInDatabase(info,
3414846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                                mFolder.mInfo.id, 0, info.cellX, info.cellY);
3424846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                    }
343e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal                }
3444846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                lp.cellX = info.cellX;
3454846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                lp.cellY = info.cellY;
3464846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                currentPage.addViewToCellLayout(
3474846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                        v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
348317698bd012c1930b83bb4e2e47ac9e363fa6c6aSunny Goyal
349317698bd012c1930b83bb4e2e47ac9e363fa6c6aSunny Goyal                if (rank < FolderIcon.NUM_ITEMS_IN_PREVIEW && v instanceof BubbleTextView) {
350317698bd012c1930b83bb4e2e47ac9e363fa6c6aSunny Goyal                    ((BubbleTextView) v).verifyHighRes();
351317698bd012c1930b83bb4e2e47ac9e363fa6c6aSunny Goyal                }
352290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
3534846193300245c8c0a1f9bde3175f273df044309Sunny Goyal
354290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            rank ++;
355290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            position++;
356290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
357290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
358e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal        // Remove extra views.
359290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        boolean removed = false;
360290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        while (pageItr.hasNext()) {
361e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal            removeView(pageItr.next());
362e4766230ff8115c5897ebee74c145bcae822581eSunny Goyal            removed = true;
363290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
364290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (removed) {
365290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            setCurrentPage(0);
366290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
3675d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal
368b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal        setEnableOverscroll(getPageCount() > 1);
3695d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal
3705d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        // Update footer
371c487bd34ace268dd8be5480ba884baed6096f76eSunny Goyal        mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
372a07c2f5c80908e8a612f4681314a7068b92baa9fSunny Goyal        // Set the gravity as LEFT or RIGHT instead of START, as START depends on the actual text.
373a07c2f5c80908e8a612f4681314a7068b92baa9fSunny Goyal        mFolder.mFolderName.setGravity(getPageCount() > 1 ?
374a07c2f5c80908e8a612f4681314a7068b92baa9fSunny Goyal                (mIsRtl ? Gravity.RIGHT : Gravity.LEFT) : Gravity.CENTER_HORIZONTAL);
375290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
376290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
377290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public int getDesiredWidth() {
37822fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal        return getPageCount() > 0 ?
37922fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal                (getPageAt(0).getDesiredWidth() + getPaddingLeft() + getPaddingRight()) : 0;
380290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
381290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
382290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public int getDesiredHeight()  {
38322fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal        return  getPageCount() > 0 ?
38422fc63ee298335b5f5c603ea1b77dc0e6180b16aSunny Goyal                (getPageAt(0).getDesiredHeight() + getPaddingTop() + getPaddingBottom()) : 0;
385290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
386290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
387290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public int getItemCount() {
388e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal        int lastPageIndex = getChildCount() - 1;
389e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal        if (lastPageIndex < 0) {
390e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal            // If there are no pages, nothing has yet been added to the folder.
391e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal            return 0;
3924846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        }
393e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal        return getPageAt(lastPageIndex).getShortcutsAndWidgets().getChildCount()
394e85d7145222ba1311cd9280726d8419b84f2f94bSunny Goyal                + lastPageIndex * mMaxItemsPerPage;
395290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
396290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
397b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
398b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * @return the rank of the cell nearest to the provided pixel position.
399b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
400290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public int findNearestArea(int pixelX, int pixelY) {
401290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pageIndex = getNextPage();
402290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        CellLayout page = getPageAt(pageIndex);
403f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
404290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (mFolder.isLayoutRtl()) {
405290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
406290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
407290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return Math.min(mAllocatedContentSize - 1,
408290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                pageIndex * mMaxItemsPerPage + sTempPosArray[1] * mGridCountX + sTempPosArray[0]);
409290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
410290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
411290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public boolean isFull() {
412b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal        return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
413290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
414290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
415feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham    public View getFirstItem() {
416feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        if (getChildCount() < 1) {
417feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham            return null;
418feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        }
419feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        ShortcutAndWidgetContainer currContainer = getCurrentCellLayout().getShortcutsAndWidgets();
420feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        if (mGridCountX > 0) {
421feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham            return currContainer.getChildAt(0, 0);
422feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        } else {
423feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham            return currContainer.getChildAt(0);
424feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        }
425feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham    }
426feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham
427290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public View getLastItem() {
428290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (getChildCount() < 1) {
429290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            return null;
430290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
431feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        ShortcutAndWidgetContainer currContainer = getCurrentCellLayout().getShortcutsAndWidgets();
432feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham        int lastRank = currContainer.getChildCount() - 1;
433290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (mGridCountX > 0) {
434feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham            return currContainer.getChildAt(lastRank % mGridCountX, lastRank / mGridCountX);
435290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        } else {
436feec2171f84f465feab96631c9d067d032aa8f88Tony Wickham            return currContainer.getChildAt(lastRank);
437290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
438290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
439290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
440b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
441b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * Iterates over all its items in a reading order.
442b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * @return the view for which the operator returned true.
443b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
444290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public View iterateOverItems(ItemOperator op) {
445290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (int k = 0 ; k < getChildCount(); k++) {
446290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            CellLayout page = getPageAt(k);
447290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            for (int j = 0; j < page.getCountY(); j++) {
448290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                for (int i = 0; i < page.getCountX(); i++) {
449290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    View v = page.getChildAt(i, j);
450c52ba710053e4c6927937dd1a26d1abe06b6fa99Sunny Goyal                    if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v)) {
451290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        return v;
452290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    }
453290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                }
454290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
455290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
456290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        return null;
457290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
458290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
459290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public String getAccessibilityDescription() {
460f4f89ef608245d39bbddda05f291361d2ae06667Sunny Goyal        return getContext().getString(R.string.folder_opened, mGridCountX, mGridCountY);
461290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
462290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
463b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
464b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * Sets the focus on the first visible child.
465b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
466290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void setFocusOnFirstChild() {
467290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        View firstChild = getCurrentCellLayout().getChildAt(0, 0);
468290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (firstChild != null) {
469290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            firstChild.requestFocus();
470290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
471290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
472290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
473290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    @Override
474290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    protected void notifyPageSwitchListener() {
475290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        super.notifyPageSwitchListener();
476290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (mFolder != null) {
477290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            mFolder.updateTextViewFocus();
478290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
479290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
480290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
4814846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    /**
4824846193300245c8c0a1f9bde3175f273df044309Sunny Goyal     * Scrolls the current view by a fraction
4834846193300245c8c0a1f9bde3175f273df044309Sunny Goyal     */
4843b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal    public void showScrollHint(int direction) {
485f5440cbd6c0525769d24b890e16313a728831e04Sunny Goyal        float fraction = (direction == Folder.SCROLL_LEFT) ^ mIsRtl
4863b0883fcda88dd192549055a387fb41e1c2c17adSunny Goyal                ? -SCROLL_HINT_FRACTION : SCROLL_HINT_FRACTION;
4874846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        int hint = (int) (fraction * getWidth());
4884846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        int scroll = getScrollForPage(getNextPage()) + hint;
4894d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal        int delta = scroll - getScrollX();
4904846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        if (delta != 0) {
4914846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            mScroller.setInterpolator(new DecelerateInterpolator());
4924d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal            mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION);
4934846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            invalidate();
4944846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        }
4954846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    }
4964846193300245c8c0a1f9bde3175f273df044309Sunny Goyal
4974846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    public void clearScrollHint() {
4984d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal        if (getScrollX() != getScrollForPage(getNextPage())) {
4994846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            snapToPage(getNextPage());
5004846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        }
5014846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    }
5024846193300245c8c0a1f9bde3175f273df044309Sunny Goyal
5034846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    /**
5044846193300245c8c0a1f9bde3175f273df044309Sunny Goyal     * Finish animation all the views which are animating across pages
5054846193300245c8c0a1f9bde3175f273df044309Sunny Goyal     */
5064846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    public void completePendingPageChanges() {
5075d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal        if (!mPendingAnimations.isEmpty()) {
5085d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal            HashMap<View, Runnable> pendingViews = new HashMap<>(mPendingAnimations);
5094846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            for (Map.Entry<View, Runnable> e : pendingViews.entrySet()) {
5104846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                e.getKey().animate().cancel();
5114846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                e.getValue().run();
5124846193300245c8c0a1f9bde3175f273df044309Sunny Goyal            }
5134846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        }
5144846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    }
5154846193300245c8c0a1f9bde3175f273df044309Sunny Goyal
5164846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    public boolean rankOnCurrentPage(int rank) {
5174846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        int p = rank / mMaxItemsPerPage;
5184846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        return p == getNextPage();
5194846193300245c8c0a1f9bde3175f273df044309Sunny Goyal    }
5204846193300245c8c0a1f9bde3175f273df044309Sunny Goyal
521290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    @Override
5229ccafbff26f5835ab9725d876d1bf7ccd08ccf84Sunny Goyal    protected void onPageBeginTransition() {
5239ccafbff26f5835ab9725d876d1bf7ccd08ccf84Sunny Goyal        super.onPageBeginTransition();
5249ccafbff26f5835ab9725d876d1bf7ccd08ccf84Sunny Goyal        // Ensure that adjacent pages have high resolution icons
5259ccafbff26f5835ab9725d876d1bf7ccd08ccf84Sunny Goyal        verifyVisibleHighResIcons(getCurrentPage() - 1);
5269ccafbff26f5835ab9725d876d1bf7ccd08ccf84Sunny Goyal        verifyVisibleHighResIcons(getCurrentPage() + 1);
52734b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal    }
52834b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal
52934b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal    /**
53034b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal     * Ensures that all the icons on the given page are of high-res
53134b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal     */
53234b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal    public void verifyVisibleHighResIcons(int pageNo) {
53334b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal        CellLayout page = getPageAt(pageNo);
53434b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal        if (page != null) {
53534b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal            ShortcutAndWidgetContainer parent = page.getShortcutsAndWidgets();
53634b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal            for (int i = parent.getChildCount() - 1; i >= 0; i--) {
53734b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal                ((BubbleTextView) parent.getChildAt(i)).verifyHighRes();
53834b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal            }
53934b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal        }
54034b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal    }
54134b6527cefd36fbd5da78464ce9771e379158552Sunny Goyal
542ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    public int getAllocatedContentSize() {
543ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal        return mAllocatedContentSize;
544ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    }
545ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal
546b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal    /**
547b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     * Reorders the items such that the {@param empty} spot moves to {@param target}
548b863415c17aaaf6012647df5ed14803f89f94bcbSunny Goyal     */
549290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    public void realTimeReorder(int empty, int target) {
5504846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        completePendingPageChanges();
551290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int delay = 0;
5524846193300245c8c0a1f9bde3175f273df044309Sunny Goyal        float delayAmount = START_VIEW_REORDER_DELAY;
553290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
554290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        // Animation only happens on the current page.
555290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pageToAnimate = getNextPage();
556290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
557290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pageT = target / mMaxItemsPerPage;
558290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pagePosT = target % mMaxItemsPerPage;
559290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
560290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (pageT != pageToAnimate) {
561290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            Log.e(TAG, "Cannot animate when the target cell is invisible");
562290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
563290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pagePosE = empty % mMaxItemsPerPage;
564290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int pageE = empty / mMaxItemsPerPage;
565290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
566290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int startPos, endPos;
567290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int moveStart, moveEnd;
568290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        int direction;
569290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
570290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if (target == empty) {
571290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            // No animation
572290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            return;
573290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        } else if (target > empty) {
574290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            // Items will move backwards to make room for the empty cell.
575290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            direction = 1;
576290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
577290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            // If empty cell is in a different page, move them instantly.
578290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (pageE < pageToAnimate) {
579290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveStart = empty;
580290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Instantly move the first item in the current page.
581290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveEnd = pageToAnimate * mMaxItemsPerPage;
582290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Animate the 2nd item in the current page, as the first item was already moved to
583290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // the last page.
584290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                startPos = 0;
585290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            } else {
586290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveStart = moveEnd = -1;
587290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                startPos = pagePosE;
588290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
589290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
590290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            endPos = pagePosT;
591290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        } else {
592290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            // The items will move forward.
593290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            direction = -1;
594290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
595290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (pageE > pageToAnimate) {
596290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Move the items immediately.
597290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveStart = empty;
598290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Instantly move the last item in the current page.
599290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveEnd = (pageToAnimate + 1) * mMaxItemsPerPage - 1;
600290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
601290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                // Animations start with the second last item in the page
602290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                startPos = mMaxItemsPerPage - 1;
603290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            } else {
604290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                moveStart = moveEnd = -1;
605290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                startPos = pagePosE;
606290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
607290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
608290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            endPos = pagePosT;
609290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
610290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
611290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        // Instant moving views.
612290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        while (moveStart != moveEnd) {
613290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int rankToMove = moveStart + direction;
614290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int p = rankToMove / mMaxItemsPerPage;
615290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int pagePos = rankToMove % mMaxItemsPerPage;
616290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int x = pagePos % mGridCountX;
617290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int y = pagePos / mGridCountX;
618290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
619290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            final CellLayout page = getPageAt(p);
620290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            final View v = page.getChildAt(x, y);
621290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (v != null) {
622290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                if (pageToAnimate != p) {
623290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    page.removeView(v);
624290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    addViewForRank(v, (ShortcutInfo) v.getTag(), moveStart);
625290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                } else {
626290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    // Do a fake animation before removing it.
627290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    final int newRank = moveStart;
628290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    final float oldTranslateX = v.getTranslationX();
629290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
630290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    Runnable endAction = new Runnable() {
631290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
632290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        @Override
633290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        public void run() {
6345d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal                            mPendingAnimations.remove(v);
635290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                            v.setTranslationX(oldTranslateX);
636290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                            ((CellLayout) v.getParent().getParent()).removeView(v);
637290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                            addViewForRank(v, (ShortcutInfo) v.getTag(), newRank);
638290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        }
639290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    };
640290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    v.animate()
6417066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal                        .translationXBy((direction > 0 ^ mIsRtl) ? -v.getWidth() : v.getWidth())
642290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        .setDuration(REORDER_ANIMATION_DURATION)
643290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        .setStartDelay(0)
644290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                        .withEndAction(endAction);
6455d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal                    mPendingAnimations.put(v, endAction);
646290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                }
647290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
648290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            moveStart = rankToMove;
649290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
650290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
651290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        if ((endPos - startPos) * direction <= 0) {
652290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            // No animation
653290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            return;
654290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
655290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal
656290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        CellLayout page = getPageAt(pageToAnimate);
657290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        for (int i = startPos; i != endPos; i += direction) {
658290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            int nextPos = i + direction;
659290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            View v = page.getChildAt(nextPos % mGridCountX, nextPos / mGridCountX);
660290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (v != null) {
661290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                ((ItemInfo) v.getTag()).rank -= direction;
662290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
663290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            if (page.animateChildToPosition(v, i % mGridCountX, i / mGridCountX,
664290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                    REORDER_ANIMATION_DURATION, delay, true, true)) {
665290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal                delay += delayAmount;
6664846193300245c8c0a1f9bde3175f273df044309Sunny Goyal                delayAmount *= VIEW_REORDER_DELAY_FACTOR;
667290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal            }
668290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal        }
669290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal    }
670b7e15adc7b67cb1d70ca72014b200dd6cbbf166aSunny Goyal
671b7e15adc7b67cb1d70ca72014b200dd6cbbf166aSunny Goyal    public int itemsPerPage() {
672b7e15adc7b67cb1d70ca72014b200dd6cbbf166aSunny Goyal        return mMaxItemsPerPage;
673b7e15adc7b67cb1d70ca72014b200dd6cbbf166aSunny Goyal    }
6744d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal
6754d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal    @Override
6760de011705b132eacdd10f7bfb5cdc4bd79a147e8Hyunyoung Song    protected void getEdgeVerticalPosition(int[] pos) {
6774d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal        pos[0] = 0;
6784d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal        pos[1] = getViewportHeight();
6794d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal    }
680290800b5b7d575fd709f244f54a5fa5b63b58876Sunny Goyal}
681