19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport android.annotation.IntDef;
2094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.annotation.NonNull;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
22499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Intent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
2523f4432437b2ab742971055b7eb79b346894f24bAlan Viveretteimport android.os.Bundle;
265fade8c69aef621312232ef0647502d7a63990b9Romain Guyimport android.os.Trace;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
285d565faab21324862fa24490f116424e1b668b1dAlan Viveretteimport android.util.MathUtils;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
31499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.view.SoundEffectConstants;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
338d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sappersteinimport android.view.ViewDebug;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
3594a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.view.ViewHierarchyEncoder;
363e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viveretteimport android.view.ViewRootImpl;
378a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
3823f4432437b2ab742971055b7eb79b346894f24bAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
395b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
405b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
4199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport android.view.accessibility.AccessibilityNodeProvider;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.animation.GridLayoutAnimationController;
43499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.widget.RemoteViews.RemoteView;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4523f4432437b2ab742971055b7eb79b346894f24bAlan Viveretteimport com.android.internal.R;
4623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
47d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.Retention;
48d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.RetentionPolicy;
49d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that shows items in two-dimensional scrolling grid. The items in the
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grid come from the {@link ListAdapter} associated with this view.
5441ec65355bd6ded652769725b276d47c54a0d913Scott Main *
554c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/layout/gridview.html">Grid
564c359b76f9a030f92a302ba74a528faa170bad4eScott Main * View</a> guide.</p>
5799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas *
5884c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_horizontalSpacing
5984c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_verticalSpacing
6084c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_stretchMode
6184c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_columnWidth
6284c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_numColumns
6384c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy * @attr ref android.R.styleable#GridView_gravity
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
65499cb9f516062b654952d282f211bee44c31a3c2Winson Chung@RemoteView
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class GridView extends AbsListView {
67d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    /** @hide */
68d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @IntDef({NO_STRETCH, STRETCH_SPACING, STRETCH_COLUMN_WIDTH, STRETCH_SPACING_UNIFORM})
69d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @Retention(RetentionPolicy.SOURCE)
70d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public @interface StretchMode {}
71d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye
7284c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy    /**
7384c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     * Disables stretching.
7499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
7599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * @see #setStretchMode(int)
7684c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int NO_STRETCH = 0;
7884c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy    /**
7984c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     * Stretches the spacing between columns.
8099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
8199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * @see #setStretchMode(int)
8284c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     */
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int STRETCH_SPACING = 1;
8484c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy    /**
8584c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     * Stretches columns.
8699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
8799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * @see #setStretchMode(int)
8884c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     */
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int STRETCH_COLUMN_WIDTH = 2;
9084c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy    /**
9184c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     * Stretches the spacing between columns. The spacing is uniform.
9299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
9399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * @see #setStretchMode(int)
9484c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int STRETCH_SPACING_UNIFORM = 3;
9684c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy
9784c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy    /**
9884c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     * Creates as many columns as can fit on screen.
9999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
10099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * @see #setNumColumns(int)
10184c6b95a7776ea5924a7c3e5a511c4df5c75924dRomain Guy     */
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int AUTO_FIT = -1;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNumColumns = AUTO_FIT;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mHorizontalSpacing = 0;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRequestedHorizontalSpacing;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVerticalSpacing = 0;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mStretchMode = STRETCH_COLUMN_WIDTH;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mColumnWidth;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRequestedColumnWidth;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRequestedNumColumns;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View mReferenceView = null;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View mReferenceViewInSelectedRow = null;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
117a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio    private int mGravity = Gravity.START;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Rect mTempRect = new Rect();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GridView(Context context) {
12248774533f1cfe3036919a2f73631e07b7c284617Adam Powell        this(context, null);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GridView(Context context, AttributeSet attrs) {
12623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        this(context, attrs, R.attr.gridViewStyle);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
129617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public GridView(Context context, AttributeSet attrs, int defStyleAttr) {
130617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
131617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
132617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
133617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public GridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
134617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
136617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
13723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                attrs, R.styleable.GridView, defStyleAttr, defStyleRes);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int hSpacing = a.getDimensionPixelOffset(
14023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                R.styleable.GridView_horizontalSpacing, 0);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHorizontalSpacing(hSpacing);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int vSpacing = a.getDimensionPixelOffset(
14423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                R.styleable.GridView_verticalSpacing, 0);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setVerticalSpacing(vSpacing);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        int index = a.getInt(R.styleable.GridView_stretchMode, STRETCH_COLUMN_WIDTH);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (index >= 0) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setStretchMode(index);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        int columnWidth = a.getDimensionPixelOffset(R.styleable.GridView_columnWidth, -1);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (columnWidth > 0) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setColumnWidth(columnWidth);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        int numColumns = a.getInt(R.styleable.GridView_numColumns, 1);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setNumColumns(numColumns);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        index = a.getInt(R.styleable.GridView_gravity, -1);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (index >= 0) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setGravity(index);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListAdapter getAdapter() {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAdapter;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
174499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
175499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * through the specified intent.
176499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
177499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
1785c022639d7e1eebbeb190975980621a286bb2ff1Sunny Goyal    @android.view.RemotableViewMethod(asyncImpl="setRemoteViewsAdapterAsync")
179499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void setRemoteViewsAdapter(Intent intent) {
180499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.setRemoteViewsAdapter(intent);
181499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
182499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
183499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the data behind this GridView.
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param adapter the adapter providing the grid's data
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAdapter(ListAdapter adapter) {
190df36b0579e1e550de3d66a20362717e49b23235cRomain Guy        if (mAdapter != null && mDataSetObserver != null) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.unregisterDataSetObserver(mDataSetObserver);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        resetList();
19599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas        mRecycler.clear();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAdapter = adapter;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedPosition = INVALID_POSITION;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedRowId = INVALID_ROW_ID;
200f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell
201f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        // AbsListView#setAdapter will update choice mode states.
202f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        super.setAdapter(adapter);
203f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOldItemCount = mItemCount;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mItemCount = mAdapter.getCount();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = true;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkFocus();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataSetObserver = new AdapterDataSetObserver();
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.registerDataSetObserver(mDataSetObserver);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position;
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStackFromBottom) {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(mItemCount - 1, false);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(0, true);
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(position);
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(position);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
22599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas            checkFocus();
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Nothing selected
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int lookForSelectablePosition(int position, boolean lookDown) {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ListAdapter adapter = mAdapter;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null || isInTouchMode()) {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return INVALID_POSITION;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (position < 0 || position >= mItemCount) {
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return INVALID_POSITION;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return position;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@inheritDoc}
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void fillGap(boolean down) {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int verticalSpacing = mVerticalSpacing;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (down) {
2578c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            int paddingTop = 0;
2588c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
2598c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                paddingTop = getListPaddingTop();
2608c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ?
2628c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                    getChildAt(count - 1).getBottom() + verticalSpacing : paddingTop;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position = mFirstPosition + count;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStackFromBottom) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position += numColumns - 1;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(position, startOffset);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(numColumns, verticalSpacing, getChildCount());
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2708c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            int paddingBottom = 0;
2718c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
2728c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                paddingBottom = getListPaddingBottom();
2738c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ?
2758c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                    getChildAt(0).getTop() - verticalSpacing : getHeight() - paddingBottom;
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position = mFirstPosition;
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position -= numColumns;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position--;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(position, startOffset);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(numColumns, verticalSpacing, getChildCount());
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos down to the end of the list view.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the item associated with pos
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        should be drawn
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected, if it happens to be in the
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         range that we draw.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillDown(int pos, int nextTop) {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3018c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        int end = (mBottom - mTop);
3028c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
3038c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            end -= mListPadding.bottom;
3048c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextTop < end && pos < mItemCount) {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View temp = makeRow(pos, nextTop, true);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (temp != null) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = temp;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3128bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy            // mReferenceView will change with each call to makeRow()
3138bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy            // do not cache in a local variable outside of this loop
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextTop = mReferenceView.getBottom() + mVerticalSpacing;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos += mNumColumns;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen        setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View makeRow(int startPos, int y, boolean flow) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int columnWidth = mColumnWidth;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int horizontalSpacing = mHorizontalSpacing;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
327a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio        final boolean isLayoutRtl = isLayoutRtl();
328a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int last;
330a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio        int nextLeft;
331a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio
332a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio        if (isLayoutRtl) {
333a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio            nextLeft = getWidth() - mListPadding.right - columnWidth -
334a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio                    ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0);
335a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio        } else {
336a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio            nextLeft = mListPadding.left +
337a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio                    ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0);
338a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio        }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            last = Math.min(startPos + mNumColumns, mItemCount);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            last = startPos + 1;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startPos = Math.max(0, startPos - mNumColumns + 1);
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (last - startPos < mNumColumns) {
347a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio                final int deltaLeft = (mNumColumns - (last - startPos)) * (columnWidth + horizontalSpacing);
348a598720ad6ae21a07aaae50c9469dc3799c3fc30Fabrice Di Meglio                nextLeft += (isLayoutRtl ? -1 : +1) * deltaLeft;
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean hasFocus = shouldShowSelector();
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean inClick = touchModeDrawsInPressedState();
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3588bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy        View child = null;
359661041194c0c5b0fe1ee659589531397e2d58d41Yigit Boyar        final int nextChildDir = isLayoutRtl ? -1 : +1;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int pos = startPos; pos < last; pos++) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is this the selected item?
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected = pos == selectedPosition;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // does the list view have focus or contain focus
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int where = flow ? -1 : pos - startPos;
3668bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy            child = makeAndAddView(pos, y, flow, nextLeft, selected, where);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
368661041194c0c5b0fe1ee659589531397e2d58d41Yigit Boyar            nextLeft += nextChildDir * columnWidth;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pos < last - 1) {
370661041194c0c5b0fe1ee659589531397e2d58d41Yigit Boyar                nextLeft += nextChildDir * horizontalSpacing;
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selected && (hasFocus || inClick)) {
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = child;
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3788bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy        mReferenceView = child;
37999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedView != null) {
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mReferenceViewInSelectedRow = mReferenceView;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos up to the top of the list view.
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextBottom The location where the bottom of the item associated
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        with pos should be drawn
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillUp(int pos, int nextBottom) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4008c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        int end = 0;
4018c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
4028c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            end = mListPadding.top;
4038c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        }
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextBottom > end && pos >= 0) {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View temp = makeRow(pos, nextBottom, false);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (temp != null) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = temp;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextBottom = mReferenceView.getTop() - mVerticalSpacing;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFirstPosition = pos;
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos -= mNumColumns;
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mStackFromBottom) {
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFirstPosition = Math.max(0, pos + 1);
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
423b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen        setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from top to bottom, starting with mFirstPosition
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the first item should be
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        drawn
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromTop(int nextTop) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition < 0) {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFirstPosition = 0;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition -= mFirstPosition % mNumColumns;
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fillDown(mFirstPosition, nextTop);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromBottom(int lastPosition, int nextBottom) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lastPosition = Math.max(lastPosition, mSelectedPosition);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lastPosition = Math.min(lastPosition, mItemCount - 1);
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int invertedPosition = mItemCount - 1 - lastPosition;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lastPosition = mItemCount - 1 - (invertedPosition - (invertedPosition % mNumColumns));
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fillUp(lastPosition, nextBottom);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillSelection(int childrenTop, int childrenBottom) {
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = reconcileSelectedPosition();
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int verticalSpacing = mVerticalSpacing;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowStart;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowEnd = -1;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = selectedPosition - (selectedPosition % numColumns);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int invertedSelection = mItemCount - 1 - selectedPosition;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowEnd = mItemCount - 1 - (invertedSelection - (invertedSelection % numColumns));
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = Math.max(0, rowEnd - numColumns + 1);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int fadingEdgeLength = getVerticalFadingEdgeLength();
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength, rowStart);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View sel = makeRow(mStackFromBottom ? rowEnd : rowStart, topSelectionPixel, true);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = rowStart;
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View referenceView = mReferenceView;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowStart + numColumns, referenceView.getBottom() + verticalSpacing);
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinToBottom(childrenBottom);
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - numColumns, referenceView.getTop() - verticalSpacing);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom,
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fadingEdgeLength, numColumns, rowStart);
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = bottomSelectionPixel - referenceView.getBottom();
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            offsetChildrenTopAndBottom(offset);
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - 1, referenceView.getTop() - verticalSpacing);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinToTop(childrenTop);
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowEnd + numColumns, referenceView.getBottom() + verticalSpacing);
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void pinToTop(int childrenTop) {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition == 0) {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int top = getChildAt(0).getTop();
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = childrenTop - top;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (offset < 0) {
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(offset);
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void pinToBottom(int childrenBottom) {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition + count == mItemCount) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int bottom = getChildAt(count - 1).getBottom();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = childrenBottom - bottom;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (offset > 0) {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(offset);
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
51899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas    }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int findMotionRow(int y) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numColumns = mNumColumns;
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < childCount; i += numColumns) {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (y <= getChildAt(i).getBottom()) {
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return mFirstPosition + i;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = childCount - 1; i >= 0; i -= numColumns) {
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (y >= getChildAt(i).getTop()) {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return mFirstPosition + i;
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Layout during a scroll that results from tracking motion events. Places
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the mMotionPosition view at the offset specified by mMotionViewTop, and
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * then build surrounding views from there.
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position the position at which to start filling
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param top the top of the view at that position
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The selected view, or null if the selected view is outside the
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         visible area.
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillSpecific(int position, int top) {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int motionRowStart;
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int motionRowEnd = -1;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            motionRowStart = position - (position % numColumns);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int invertedSelection = mItemCount - 1 - position;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            motionRowEnd = mItemCount - 1 - (invertedSelection - (invertedSelection % numColumns));
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            motionRowStart = Math.max(0, motionRowEnd - numColumns + 1);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View temp = makeRow(mStackFromBottom ? motionRowEnd : motionRowStart, top, true);
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Possibly changed again in fillUp if we add rows above this one.
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = motionRowStart;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View referenceView = mReferenceView;
5748bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy        // We didn't have anything to layout, bail out
5758bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy        if (referenceView == null) {
5768bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy            return null;
5778bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy        }
5788bcdc0764f2f569173863655f96cdec2aea2d0daRomain Guy
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int verticalSpacing = mVerticalSpacing;
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View above;
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View below;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(motionRowStart - numColumns, referenceView.getTop() - verticalSpacing);
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(motionRowStart + numColumns, referenceView.getBottom() + verticalSpacing);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Check if we have dragged the bottom of the grid too high
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childCount = getChildCount();
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                correctTooHigh(numColumns, verticalSpacing, childCount);
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(motionRowEnd + numColumns, referenceView.getBottom() + verticalSpacing);
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(motionRowStart - 1, referenceView.getTop() - verticalSpacing);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Check if we have dragged the bottom of the grid too high
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childCount = getChildCount();
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                correctTooLow(numColumns, verticalSpacing, childCount);
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (temp != null) {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return temp;
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (above != null) {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return above;
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return below;
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooHigh(int numColumns, int verticalSpacing, int childCount) {
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First see if the last item is visible
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int lastPosition = mFirstPosition + childCount - 1;
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lastPosition == mItemCount - 1 && childCount > 0) {
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the last child ...
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View lastChild = getChildAt(childCount - 1);
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its bottom edge
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the bottom edge of the last view is from the bottom of the
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
62799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas            int bottomOffset = end - lastBottom;
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View firstChild = getChildAt(0);
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too high, and 2) Either there are more rows above the
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // first row or the first row is scrolled off the top of the drawable area
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bottomOffset > 0 && (mFirstPosition > 0 || firstTop < mListPadding.top))  {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition == 0) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Don't pull the top too far down
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop);
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
63999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Move everything down
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(bottomOffset);
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition > 0) {
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fill the gap that was opened above mFirstPosition with more rows, if
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // possible
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fillUp(mFirstPosition - (mStackFromBottom ? 1 : numColumns),
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            firstChild.getTop() - verticalSpacing);
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Close up the remaining gap
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    adjustViewsUpOrDown();
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooLow(int numColumns, int verticalSpacing, int childCount) {
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition == 0 && childCount > 0) {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the first child ...
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View firstChild = getChildAt(0);
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its top edge
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is top of our drawable area
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int start = mListPadding.top;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the top edge of the first view is from the top of the
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topOffset = firstTop - start;
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View lastChild = getChildAt(childCount - 1);
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastPosition = mFirstPosition + childCount - 1;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too low, and 2) Either there are more rows below the
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // last row or the last row is scrolled off the bottom of the drawable area
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (topOffset > 0 && (lastPosition < mItemCount - 1 || lastBottom > end))  {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lastPosition == mItemCount - 1 ) {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Don't pull the bottom too far up
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    topOffset = Math.min(topOffset, lastBottom - end);
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
68299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Move everything up
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(-topOffset);
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lastPosition < mItemCount - 1) {
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fill the gap that was opened below the last position with more rows, if
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // possible
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fillDown(lastPosition + (!mStackFromBottom ? 1 : numColumns),
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            lastChild.getBottom() + verticalSpacing);
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Close up the remaining gap
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    adjustViewsUpOrDown();
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the grid based on positioning the new selection at a specific
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location. The selection may be moved so that it does not intersect the
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * faded edges. The grid is then filled upwards and downwards from there.
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedTop Where the selected item should be
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromSelection(int selectedTop, int childrenTop, int childrenBottom) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int fadingEdgeLength = getVerticalFadingEdgeLength();
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int verticalSpacing = mVerticalSpacing;
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowStart;
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowEnd = -1;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = selectedPosition - (selectedPosition % numColumns);
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int invertedSelection = mItemCount - 1 - selectedPosition;
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowEnd = mItemCount - 1 - (invertedSelection - (invertedSelection % numColumns));
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = Math.max(0, rowEnd - numColumns + 1);
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View referenceView;
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength, rowStart);
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength,
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                numColumns, rowStart);
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sel = makeRow(mStackFromBottom ? rowEnd : rowStart, selectedTop, true);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Possibly changed again in fillUp if we add rows above this one.
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = rowStart;
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        referenceView = mReferenceView;
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        adjustForTopFadingEdge(referenceView, topSelectionPixel, bottomSelectionPixel);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        adjustForBottomFadingEdge(referenceView, topSelectionPixel, bottomSelectionPixel);
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - numColumns, referenceView.getTop() - verticalSpacing);
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowStart + numColumns, referenceView.getBottom() + verticalSpacing);
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowEnd + numColumns, referenceView.getBottom() + verticalSpacing);
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - 1, referenceView.getTop() - verticalSpacing);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the bottom-most pixel we can draw the selection into
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Bottom pixel were children can be drawn
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numColumns Number of columns in the grid
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param rowStart The start of the row that will contain the selection
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The bottom-most pixel we can draw the selection into
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getBottomSelectionPixel(int childrenBottom, int fadingEdgeLength,
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numColumns, int rowStart) {
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Last pixel we can draw the selection into
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomSelectionPixel = childrenBottom;
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rowStart + numColumns - 1 < mItemCount - 1) {
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomSelectionPixel -= fadingEdgeLength;
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return bottomSelectionPixel;
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the top-most pixel we can draw the selection into
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Top pixel were children can be drawn
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param rowStart The start of the row that will contain the selection
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The top-most pixel we can draw the selection into
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getTopSelectionPixel(int childrenTop, int fadingEdgeLength, int rowStart) {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // first pixel we can draw the selection into
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topSelectionPixel = childrenTop;
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rowStart > 0) {
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topSelectionPixel += fadingEdgeLength;
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return topSelectionPixel;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move all views upwards so the selected row does not interesect the bottom
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * fading edge (if necessary).
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childInSelectedRow A child in the row that contains the selection
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param topSelectionPixel The topmost pixel we can draw the selection into
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bottomSelectionPixel The bottommost pixel we can draw the
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        selection into
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void adjustForBottomFadingEdge(View childInSelectedRow,
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topSelectionPixel, int bottomSelectionPixel) {
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Some of the newly selected item extends below the bottom of the
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // list
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childInSelectedRow.getBottom() > bottomSelectionPixel) {
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available above the selection into which we can
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // scroll upwards
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spaceAbove = childInSelectedRow.getTop() - topSelectionPixel;
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the bottom of the selected item
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // fully into view
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spaceBelow = childInSelectedRow.getBottom() - bottomSelectionPixel;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int offset = Math.min(spaceAbove, spaceBelow);
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now offset the selected item to get it into view
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            offsetChildrenTopAndBottom(-offset);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move all views upwards so the selected row does not interesect the top
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * fading edge (if necessary).
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childInSelectedRow A child in the row that contains the selection
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param topSelectionPixel The topmost pixel we can draw the selection into
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bottomSelectionPixel The bottommost pixel we can draw the
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        selection into
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void adjustForTopFadingEdge(View childInSelectedRow,
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topSelectionPixel, int bottomSelectionPixel) {
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Some of the newly selected item extends above the top of the list
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childInSelectedRow.getTop() < topSelectionPixel) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the top of the selected item
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // fully into view
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spaceAbove = topSelectionPixel - childInSelectedRow.getTop();
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available below the selection into which we can
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // scroll downwards
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spaceBelow = bottomSelectionPixel - childInSelectedRow.getBottom();
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int offset = Math.min(spaceAbove, spaceBelow);
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now offset the selected item to get it into view
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            offsetChildrenTopAndBottom(offset);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
847499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Smoothly scroll to the specified adapter position. The view will
848499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * scroll such that the indicated position is displayed.
849499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param position Scroll to this adapter position.
850499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
851499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @android.view.RemotableViewMethod
852499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void smoothScrollToPosition(int position) {
853499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.smoothScrollToPosition(position);
854499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
855499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
856499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
857499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Smoothly scroll to the specified adapter position offset. The view will
858499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * scroll such that the indicated position is displayed.
859499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param offset The amount to offset from the adapter position to scroll to.
860499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
861499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @android.view.RemotableViewMethod
862499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void smoothScrollByOffset(int offset) {
863499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.smoothScrollByOffset(offset);
864499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
865499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
866499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the grid based on positioning the new selection relative to the old
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * selection. The new selection will be placed at, above, or below the
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location of the new selection depending on how the selection is moving.
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The selection will then be pinned to the visible part of the screen,
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * excluding the edges that are faded. The grid is then filled upwards and
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * downwards from there.
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param delta Which way we are moving
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View moveSelection(int delta, int childrenTop, int childrenBottom) {
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int fadingEdgeLength = getVerticalFadingEdgeLength();
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int verticalSpacing = mVerticalSpacing;
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int oldRowStart;
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowStart;
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowEnd = -1;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            oldRowStart = (selectedPosition - delta) - ((selectedPosition - delta) % numColumns);
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = selectedPosition - (selectedPosition % numColumns);
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int invertedSelection = mItemCount - 1 - selectedPosition;
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowEnd = mItemCount - 1 - (invertedSelection - (invertedSelection % numColumns));
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = Math.max(0, rowEnd - numColumns + 1);
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invertedSelection = mItemCount - 1 - (selectedPosition - delta);
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            oldRowStart = mItemCount - 1 - (invertedSelection - (invertedSelection % numColumns));
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            oldRowStart = Math.max(0, oldRowStart - numColumns + 1);
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int rowDelta = rowStart - oldRowStart;
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength, rowStart);
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength,
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                numColumns, rowStart);
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Possibly changed again in fillUp if we add rows above this one.
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = rowStart;
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View referenceView;
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rowDelta > 0) {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 1: Scrolling down.
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int oldBottom = mReferenceViewInSelectedRow == null ? 0 :
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mReferenceViewInSelectedRow.getBottom();
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeRow(mStackFromBottom ? rowEnd : rowStart, oldBottom + verticalSpacing, true);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            referenceView = mReferenceView;
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustForBottomFadingEdge(referenceView, topSelectionPixel, bottomSelectionPixel);
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (rowDelta < 0) {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 2: Scrolling up.
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int oldTop = mReferenceViewInSelectedRow == null ?
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    0 : mReferenceViewInSelectedRow .getTop();
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeRow(mStackFromBottom ? rowEnd : rowStart, oldTop - verticalSpacing, false);
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            referenceView = mReferenceView;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustForTopFadingEdge(referenceView, topSelectionPixel, bottomSelectionPixel);
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Keep selection where it was
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int oldTop = mReferenceViewInSelectedRow == null ?
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    0 : mReferenceViewInSelectedRow .getTop();
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeRow(mStackFromBottom ? rowEnd : rowStart, oldTop, true);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            referenceView = mReferenceView;
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - numColumns, referenceView.getTop() - verticalSpacing);
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowStart + numColumns, referenceView.getBottom() + verticalSpacing);
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(rowEnd + numColumns, referenceView.getBottom() + verticalSpacing);
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(rowStart - 1, referenceView.getTop() - verticalSpacing);
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
963edd9508aba83a0e6ed49cce3840783c1c72d1430Adam Lesinski    private boolean determineColumns(int availableSpace) {
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int requestedHorizontalSpacing = mRequestedHorizontalSpacing;
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int stretchMode = mStretchMode;
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int requestedColumnWidth = mRequestedColumnWidth;
967edd9508aba83a0e6ed49cce3840783c1c72d1430Adam Lesinski        boolean didNotInitiallyFit = false;
96899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mRequestedNumColumns == AUTO_FIT) {
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (requestedColumnWidth > 0) {
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Client told us to pick the number of columns
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mNumColumns = (availableSpace + requestedHorizontalSpacing) /
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (requestedColumnWidth + requestedHorizontalSpacing);
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Just make up a number if we don't have enough info
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mNumColumns = 2;
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We picked the columns
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNumColumns = mRequestedNumColumns;
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
98299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNumColumns <= 0) {
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNumColumns = 1;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (stretchMode) {
98899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas            case NO_STRETCH:
98999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                // Nobody stretches
99099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                mColumnWidth = requestedColumnWidth;
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHorizontalSpacing = requestedHorizontalSpacing;
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
99499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas            default:
99599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                int spaceLeftOver = availableSpace - (mNumColumns * requestedColumnWidth)
99699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        - ((mNumColumns - 1) * requestedHorizontalSpacing);
99799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
99899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                if (spaceLeftOver < 0) {
99999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                    didNotInitiallyFit = true;
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                switch (stretchMode) {
100399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                    case STRETCH_COLUMN_WIDTH:
100499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        // Stretch the columns
100599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        mColumnWidth = requestedColumnWidth + spaceLeftOver / mNumColumns;
100699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        mHorizontalSpacing = requestedHorizontalSpacing;
100799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        break;
100899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
100999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                    case STRETCH_SPACING:
101099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        // Stretch the spacing between columns
101199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        mColumnWidth = requestedColumnWidth;
101299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        if (mNumColumns > 1) {
101399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                            mHorizontalSpacing = requestedHorizontalSpacing
101499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                                    + spaceLeftOver / (mNumColumns - 1);
101599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        } else {
101699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                            mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
101799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        }
101899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        break;
101999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
102099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                    case STRETCH_SPACING_UNIFORM:
102199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        // Stretch the spacing between columns
102299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        mColumnWidth = requestedColumnWidth;
102399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        if (mNumColumns > 1) {
102499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                            mHorizontalSpacing = requestedHorizontalSpacing
102599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                                    + spaceLeftOver / (mNumColumns + 1);
102699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        } else {
102799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                            mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
102899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        }
102999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                        break;
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
103299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas                break;
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1034edd9508aba83a0e6ed49cce3840783c1c72d1430Adam Lesinski        return didNotInitiallyFit;
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Sets up mListPadding
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (widthMode == MeasureSpec.UNSPECIFIED) {
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mColumnWidth > 0) {
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                widthSize = mColumnWidth + mListPadding.left + mListPadding.right;
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                widthSize = mListPadding.left + mListPadding.right;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            widthSize += getVerticalScrollbarWidth();
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
105599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidth = widthSize - mListPadding.left - mListPadding.right;
1057edd9508aba83a0e6ed49cce3840783c1c72d1430Adam Lesinski        boolean didNotInitiallyFit = determineColumns(childWidth);
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeight = 0;
1060189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        int childState = 0;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = mItemCount;
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
106521875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            final View child = obtainView(0, mIsScrap);
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1067aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell            AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (p == null) {
1069aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell                p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
10704df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                child.setLayoutParams(p);
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.viewType = mAdapter.getItemViewType(0);
107392539d5c75922b430b7f69a14144b6a61045f1f4Alan Viverette            p.isEnabled = mAdapter.isEnabled(0);
10740bf88594c43ced48d862d122e3e84967b3b63658Romain Guy            p.forceAdd = true;
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childHeightSpec = getChildMeasureSpec(
1077d5dbf4b2a09c9cf2d17fa6af3fdf75d1fb774056Adam Powell                    MeasureSpec.makeSafeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
1078b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski                            MeasureSpec.UNSPECIFIED), 0, p.height);
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childWidthSpec = getChildMeasureSpec(
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.measure(childWidthSpec, childHeightSpec);
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeight = child.getMeasuredHeight();
1084189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            childState = combineMeasuredStates(childState, child.getMeasuredState());
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mRecycler.shouldRecycleViewType(p.viewType)) {
1087079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                mRecycler.addScrapView(child, -1);
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
109099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.UNSPECIFIED) {
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = mListPadding.top + mListPadding.bottom + childHeight +
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getVerticalFadingEdgeLength() * 2;
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.AT_MOST) {
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ourSize =  mListPadding.top + mListPadding.bottom;
109899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numColumns = mNumColumns;
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i += numColumns) {
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ourSize += childHeight;
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (i + numColumns < count) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ourSize += mVerticalSpacing;
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (ourSize >= heightSize) {
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ourSize = heightSize;
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = ourSize;
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1113189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        if (widthMode == MeasureSpec.AT_MOST && mRequestedNumColumns != AUTO_FIT) {
1114189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            int ourSize = (mRequestedNumColumns*mColumnWidth)
1115189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn                    + ((mRequestedNumColumns-1)*mHorizontalSpacing)
1116189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn                    + mListPadding.left + mListPadding.right;
1117edd9508aba83a0e6ed49cce3840783c1c72d1430Adam Lesinski            if (ourSize > widthSize || didNotInitiallyFit) {
1118189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn                widthSize |= MEASURED_STATE_TOO_SMALL;
1119189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            }
1120189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        }
1121189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setMeasuredDimension(widthSize, heightSize);
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWidthMeasureSpec = widthMeasureSpec;
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void attachLayoutAnimationParameters(View child,
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ViewGroup.LayoutParams params, int index, int count) {
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GridLayoutAnimationController.AnimationParameters animationParams =
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (animationParams == null) {
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animationParams = new GridLayoutAnimationController.AnimationParameters();
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            params.layoutAnimationParameters = animationParams;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animationParams.count = count;
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animationParams.index = index;
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animationParams.columnsCount = mNumColumns;
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animationParams.rowsCount = count / mNumColumns;
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animationParams.column = index % mNumColumns;
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animationParams.row = index / mNumColumns;
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int invertedIndex = count - 1 - index;
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns);
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns;
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void layoutChildren() {
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean blockLayoutRequests = mBlockLayoutRequests;
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!blockLayoutRequests) {
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBlockLayoutRequests = true;
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.layoutChildren();
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAdapter == null) {
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childrenTop = mListPadding.top;
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childrenBottom = mBottom - mTop - mListPadding.bottom;
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int index;
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int delta = 0;
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View sel;
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldSel = null;
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldFirst = null;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View newSel = null;
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Remember stuff we will need down below
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mNextSelectedPosition - mFirstPosition;
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    newSel = getChildAt(index);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mNextSelectedPosition >= 0) {
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = mNextSelectedPosition - mSelectedPosition;
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previously selected view
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mSelectedPosition - mFirstPosition;
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    oldSel = getChildAt(index);
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previous first child
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldFirst = getChildAt(0);
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean dataChanged = mDataChanged;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleDataChanged();
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Handle the empty set by removing all views that are visible
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // and calling it a day
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount == 0) {
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(mNextSelectedPosition);
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12283e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
12293e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            View accessibilityFocusLayoutRestoreView = null;
12303e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            int accessibilityFocusPosition = INVALID_POSITION;
12313e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
12323e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Remember which child, if any, had accessibility focus. This must
12333e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // occur before recycling any views, since that will clear
12343e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // accessibility focus.
12353e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            final ViewRootImpl viewRootImpl = getViewRootImpl();
12363e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            if (viewRootImpl != null) {
12373e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
12383e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                if (focusHost != null) {
12393e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    final View focusChild = getAccessibilityFocusedChild(focusHost);
12403e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    if (focusChild != null) {
12413e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        if (!dataChanged || focusChild.hasTransientState()
12423e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                                || mAdapterHasStableIds) {
12433e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            // The views won't be changing, so try to maintain
12443e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            // focus on the current host and virtual view.
12453e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            accessibilityFocusLayoutRestoreView = focusHost;
12463e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            accessibilityFocusLayoutRestoreNode = viewRootImpl
12473e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                                    .getAccessibilityFocusedVirtualView();
12483e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        }
12493e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
12503e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // Try to maintain focus at the same position.
12513e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        accessibilityFocusPosition = getPositionForView(focusChild);
12523e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    }
12533e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                }
12545d565faab21324862fa24490f116424e1b668b1dAlan Viverette            }
12555d565faab21324862fa24490f116424e1b668b1dAlan Viverette
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pull all children into the RecycleBin.
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // These views will be reused if possible
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstPosition = mFirstPosition;
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final RecycleBin recycleBin = mRecycler;
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < childCount; i++) {
1263079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                    recycleBin.addScrapView(getChildAt(i), firstPosition+i);
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                recycleBin.fillActiveViews(childCount, firstPosition);
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Clear out old views
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            detachAllViewsFromParent();
1271539ee8716b4f81260bab2e9f3dc5d88d81c99985Adam Powell            recycleBin.removeSkippedScrap();
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newSel != null) {
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom);
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillSelection(childrenTop, childrenBottom);
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition = 0;
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillFromTop(childrenTop);
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillUp(mItemCount - 1, childrenBottom);
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillSpecific(mSelectedPosition, mSpecificTop);
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillSpecific(mSyncPosition, mSpecificTop);
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Move the selection relative to its old position
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = moveSelection(delta, childrenTop, childrenBottom);
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (childCount == 0) {
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!mStackFromBottom) {
130391c8613679959a5fde4f72fe6dd80023d9a1a9e7Romain Guy                        setSelectedPositionInt(mAdapter == null || isInTouchMode() ?
130491c8613679959a5fde4f72fe6dd80023d9a1a9e7Romain Guy                                INVALID_POSITION : 0);
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillFromTop(childrenTop);
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int last = mItemCount - 1;
130891c8613679959a5fde4f72fe6dd80023d9a1a9e7Romain Guy                        setSelectedPositionInt(mAdapter == null || isInTouchMode() ?
130991c8613679959a5fde4f72fe6dd80023d9a1a9e7Romain Guy                                INVALID_POSITION : last);
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillFromBottom(last, childrenBottom);
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mSelectedPosition, oldSel == null ?
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                childrenTop : oldSel.getTop());
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (mFirstPosition < mItemCount)  {
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mFirstPosition, oldFirst == null ?
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                childrenTop : oldFirst.getTop());
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(0, childrenTop);
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Flush any cached views that did not get reused above
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recycleBin.scrapActiveViews();
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel != null) {
1330079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn               positionSelector(INVALID_POSITION, sel);
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               mSelectedTop = sel.getTop();
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1333e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                final boolean inTouchMode = mTouchMode > TOUCH_MODE_DOWN
1334e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                        && mTouchMode < TOUCH_MODE_SCROLL;
1335e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                if (inTouchMode) {
1336e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // If the user's finger is down, select the motion position.
1337e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    final View child = getChildAt(mMotionPosition - mFirstPosition);
1338e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    if (child != null) {
1339e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                        positionSelector(mMotionPosition, child);
1340e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    }
1341e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                } else if (mSelectedPosition != INVALID_POSITION) {
1342e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // If we had previously positioned the selector somewhere,
1343e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // put it back there. It might not match up with the data,
1344e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // but it's transitioning out so it's not a big deal.
1345e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    final View child = getChildAt(mSelectorPosition - mFirstPosition);
1346e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    if (child != null) {
1347e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                        positionSelector(mSelectorPosition, child);
1348e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    }
1349e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                } else {
1350e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // Otherwise, clear selection.
1351e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    mSelectedTop = 0;
1352e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    mSelectorRect.setEmpty();
1353e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                }
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13563e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Attempt to restore accessibility focus, if necessary.
13572e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette            if (viewRootImpl != null) {
13582e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost();
13592e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                if (newAccessibilityFocusedView == null) {
13602e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                    if (accessibilityFocusLayoutRestoreView != null
13612e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) {
13622e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final AccessibilityNodeProvider provider =
13632e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
13642e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        if (accessibilityFocusLayoutRestoreNode != null && provider != null) {
13652e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
13662e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                    accessibilityFocusLayoutRestoreNode.getSourceNodeId());
13672e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            provider.performAction(virtualViewId,
13682e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
13692e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        } else {
13702e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
13712e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        }
13722e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                    } else if (accessibilityFocusPosition != INVALID_POSITION) {
13732e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        // Bound the position within the visible children.
13742e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final int position = MathUtils.constrain(
13752e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                accessibilityFocusPosition - mFirstPosition, 0,
13762e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                getChildCount() - 1);
13772e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final View restoreView = getChildAt(position);
13782e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        if (restoreView != null) {
13792e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            restoreView.requestAccessibilityFocus();
13802e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        }
13815d565faab21324862fa24490f116424e1b668b1dAlan Viverette                    }
13825d565faab21324862fa24490f116424e1b668b1dAlan Viverette                }
13835d565faab21324862fa24490f116424e1b668b1dAlan Viverette            }
13845d565faab21324862fa24490f116424e1b668b1dAlan Viverette
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_NORMAL;
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = false;
1387161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell            if (mPositionScrollAfterLayout != null) {
1388161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell                post(mPositionScrollAfterLayout);
1389161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell                mPositionScrollAfterLayout = null;
1390161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell            }
13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNeedSync = false;
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(mSelectedPosition);
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateScrollIndicators();
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount > 0) {
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSelectionChanged();
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!blockLayoutRequests) {
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBlockLayoutRequests = false;
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
141026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * Obtains the view and adds it to our list of children. The view can be
141126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * made fresh, converted from an unused view, or used as is if it was in
141226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * the recycle bin.
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
141426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param position logical position in the list
141526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param y top or bottom edge of the view to add
141626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param flow {@code true} to align top edge to y, {@code false} to align
141726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *             bottom edge to y
141826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param childrenLeft left edge where children should be positioned
141926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param selected {@code true} if the position is selected, {@code false}
142026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 otherwise
142126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param where position at which to add new item in the list
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return View that was added
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected, int where) {
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mDataChanged) {
142721875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            // Try to use an existing view for this position
142826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            final View activeView = mRecycler.getActiveView(position);
142926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            if (activeView != null) {
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Found it -- we're using an existing child
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This just needs to be positioned
143226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                setupChild(activeView, position, y, flow, childrenLeft, selected, true, where);
143326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                return activeView;
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make a new view for this position, or convert an unused view if
143826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // possible.
143926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final View child = obtainView(position, mIsScrap);
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
144126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // This needs to be positioned and measured.
144221875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0], where);
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return child;
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
144826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * Adds a view as a child and make sure it is measured (if necessary) and
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * positioned properly.
14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
145126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param child the view to add
145226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param position the position of this child
145326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param y the y position relative to which this view will be positioned
145426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param flowDown {@code true} to align top edge to y, {@code false} to
145526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 align bottom edge to y
145626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param childrenLeft left edge where children should be positioned
145726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param selected {@code true} if the position is selected, {@code false}
145826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 otherwise
145926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param isAttachedToWindow {@code true} if the view is already attached
146026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                           to the window, e.g. whether it was reused, or
146126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                           {@code false} otherwise
146226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param where position at which to add new item in the list
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
146526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette    private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
146626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            boolean selected, boolean isAttachedToWindow, int where) {
14675fade8c69aef621312232ef0647502d7a63990b9Romain Guy        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "setupGridItem");
14685fade8c69aef621312232ef0647502d7a63990b9Romain Guy
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isSelected = selected && shouldShowSelector();
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean updateChildSelected = isSelected != child.isSelected();
14713616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final int mode = mTouchMode;
147226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL
147326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                && mMotionPosition == position;
14743616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final boolean updateChildPressed = isPressed != child.isPressed();
147526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final boolean needToMeasure = !isAttachedToWindow || updateChildSelected
147626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                || child.isLayoutRequested();
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Respect layout params that are already in the view. Otherwise make
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // some up...
1480aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell        AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
1482aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p.viewType = mAdapter.getItemViewType(position);
148592539d5c75922b430b7f69a14144b6a61045f1f4Alan Viverette        p.isEnabled = mAdapter.isEnabled(position);
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
148726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // Set up view state before attaching the view, since we may need to
148826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // rely on the jumpDrawablesToCurrentState() call that occurs as part
148926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // of view attachment.
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (updateChildSelected) {
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setSelected(isSelected);
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isSelected) {
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requestFocus();
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14973616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        if (updateChildPressed) {
14983616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy            child.setPressed(isPressed);
14993616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        }
15003616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy
1501f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
1502f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell            if (child instanceof Checkable) {
1503f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell                ((Checkable) child).setChecked(mCheckStates.get(position));
1504d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn            } else if (getContext().getApplicationInfo().targetSdkVersion
1505d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn                    >= android.os.Build.VERSION_CODES.HONEYCOMB) {
1506d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn                child.setActivated(mCheckStates.get(position));
1507f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell            }
1508f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        }
1509f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell
151026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        if (isAttachedToWindow && !p.forceAdd) {
151126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            attachViewToParent(child, where, p);
151226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette
151326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            // If the view isn't attached, or if it's attached but for a different
151426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            // position, then jump the drawables.
151526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            if (!isAttachedToWindow
151626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                    || (((AbsListView.LayoutParams) child.getLayoutParams()).scrappedFromPosition)
151726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                            != position) {
151826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                child.jumpDrawablesToCurrentState();
151926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            }
152026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        } else {
152126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            p.forceAdd = false;
152226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            addViewInLayout(child, where, p, true);
152326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        }
152426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childHeightSpec = ViewGroup.getChildMeasureSpec(
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childWidthSpec = ViewGroup.getChildMeasureSpec(
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.measure(childWidthSpec, childHeightSpec);
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupLayoutState(child);
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int w = child.getMeasuredWidth();
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int h = child.getMeasuredHeight();
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childLeft;
154026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final int childTop = flowDown ? y : y - h;
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1542e56ffdc7b31b0937628609cc3bbaa15879023569Fabrice Di Meglio        final int layoutDirection = getLayoutDirection();
1543c0053223bedf33581b0830fb87be32c1f26e5372Fabrice Di Meglio        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
15446a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
15456a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio            case Gravity.LEFT:
15466a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                childLeft = childrenLeft;
15476a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                break;
15486a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio            case Gravity.CENTER_HORIZONTAL:
15496a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                childLeft = childrenLeft + ((mColumnWidth - w) / 2);
15506a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                break;
15516a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio            case Gravity.RIGHT:
15526a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                childLeft = childrenLeft + mColumnWidth - w;
15536a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                break;
15546a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio            default:
15556a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                childLeft = childrenLeft;
15566a03640539405afbdefe72894759281b98aa6e6fFabrice Di Meglio                break;
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childRight = childLeft + w;
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childBottom = childTop + h;
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.layout(childLeft, childTop, childRight, childBottom);
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetLeftAndRight(childLeft - child.getLeft());
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetTopAndBottom(childTop - child.getTop());
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
156826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        if (mCachingStarted && !child.isDrawingCacheEnabled()) {
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setDrawingCacheEnabled(true);
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1571079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn
15725fade8c69aef621312232ef0647502d7a63990b9Romain Guy        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the currently selected item
157799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Index (starting at 0) of the data item to be selected.
157999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If in touch mode, the item will not be selected but it will still be positioned
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * appropriately.
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelection(int position) {
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isInTouchMode()) {
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(position);
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResurrectToPosition = position;
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayoutMode = LAYOUT_SET_SELECTION;
15911fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        if (mPositionScroller != null) {
15921fa179ef41c06bd19da70fd9bf95741238791940Adam Powell            mPositionScroller.stop();
15931fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        }
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Makes the item at the supplied position selected.
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position the position of the new selection
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setSelectionInt(int position) {
1604f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        int previousSelectedPosition = mNextSelectedPosition;
1605f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
16061fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        if (mPositionScroller != null) {
16071fa179ef41c06bd19da70fd9bf95741238791940Adam Powell            mPositionScroller.stop();
16081fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        }
16091fa179ef41c06bd19da70fd9bf95741238791940Adam Powell
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setNextSelectedPositionInt(position);
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layoutChildren();
161299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
161399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas        final int next = mStackFromBottom ? mItemCount - 1  - mNextSelectedPosition :
1614f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            mNextSelectedPosition;
1615f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        final int previous = mStackFromBottom ? mItemCount - 1
1616f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                - previousSelectedPosition : previousSelectedPosition;
1617f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
1618f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        final int nextRow = next / mNumColumns;
1619f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        final int previousRow = previous / mNumColumns;
1620f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
1621f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (nextRow != previousRow) {
1622f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
1623f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
1624f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, repeatCount, event);
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean commonKey(int keyCode, int count, KeyEvent event) {
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter == null) {
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDataChanged) {
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layoutChildren();
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int action = event.getAction();
1653aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        if (KeyEvent.isConfirmKey(keyCode)
1654759f9fed70adf0f6e955b0ecca5b21ab5a42ac0dMichael Wright                && event.hasNoModifiers() && action != KeyEvent.ACTION_UP) {
1655aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            handled = resurrectSelectionIfNeeded();
1656aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
1657aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright                keyPressed();
1658aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright                handled = true;
1659aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            }
1660aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        }
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1662aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        if (!handled && action != KeyEvent.ACTION_UP) {
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (keyCode) {
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_LEFT:
16654e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
16668d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_LEFT);
16674e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_RIGHT:
16714e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
16728d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_RIGHT);
16734e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_UP:
16774e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
16788d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_UP);
16794e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
16808d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_DOWN:
16854e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
16868d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_DOWN);
16874e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
16888d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16924e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                case KeyEvent.KEYCODE_PAGE_UP:
16934e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
16948d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
16954e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
16968d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
16974e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
16984e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    break;
16994e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
17004e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                case KeyEvent.KEYCODE_PAGE_DOWN:
17014e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
17028d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
17034e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
17048d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
17054e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
17064e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    break;
17074e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
17084e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                case KeyEvent.KEYCODE_MOVE_HOME:
17094e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
17108d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
17114e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
17124e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    break;
17134e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
17144e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                case KeyEvent.KEYCODE_MOVE_END:
17154e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (event.hasNoModifiers()) {
17168d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                        handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
17174e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
17184e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    break;
17194e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
17204e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                case KeyEvent.KEYCODE_TAB:
17218c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                    // TODO: Sometimes it is useful to be able to TAB through the items in
17224e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    //     a GridView sequentially.  Unfortunately this can create an
17234e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    //     asymmetry in TAB navigation order unless the list selection
17244e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    //     always reverts to the top or bottom when receiving TAB focus from
17258c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                    //     another widget.
17268c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                    if (event.hasNoModifiers()) {
17278c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                        handled = resurrectSelectionIfNeeded()
17288c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                                || sequenceScroll(FOCUS_FORWARD);
17298c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
17308c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                        handled = resurrectSelectionIfNeeded()
17318c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky                                || sequenceScroll(FOCUS_BACKWARD);
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17378d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        if (handled) {
17388d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            return true;
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17418d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        if (sendToTextFilter(keyCode, count, event)) {
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
17438d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        }
17448d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown
17458d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        switch (action) {
17468d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_DOWN:
17478d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyDown(keyCode, event);
17488d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_UP:
17498d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyUp(keyCode, event);
17508d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_MULTIPLE:
17518d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyMultiple(keyCode, count, event);
17528d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            default:
17538d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return false;
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls up or down by the number of items currently present on screen.
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean pageScroll(int direction) {
17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int nextPage = -1;
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
176764d50a67f44f6f8627b6d5203f0e3b26dc4f71e5Romain Guy            nextPage = Math.max(0, mSelectedPosition - getChildCount());
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
176964d50a67f44f6f8627b6d5203f0e3b26dc4f71e5Romain Guy            nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount());
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextPage >= 0) {
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectionInt(nextPage);
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
1775f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Go to the last or first item if possible.
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}.
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether selection was moved.
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean fullScroll(int direction) {
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean moved = false;
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_SET_SELECTION;
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectionInt(0);
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            moved = true;
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_SET_SELECTION;
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectionInt(mItemCount - 1);
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            moved = true;
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
180299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
1803f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (moved) {
1804f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
1805f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return moved;
18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls to the next or previous item, horizontally or vertically.
18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean arrowScroll(int direction) {
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int startOfRowPos;
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int endOfRowPos;
18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean moved = false;
18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startOfRowPos = (selectedPosition / numColumns) * numColumns;
18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            endOfRowPos = Math.min(startOfRowPos + numColumns - 1, mItemCount - 1);
18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int invertedSelection = mItemCount - 1 - selectedPosition;
18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            endOfRowPos = mItemCount - 1 - (invertedSelection / numColumns) * numColumns;
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startOfRowPos = Math.max(0, endOfRowPos - numColumns + 1);
18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (direction) {
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FOCUS_UP:
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (startOfRowPos > 0) {
18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_MOVE_SELECTION;
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(Math.max(0, selectedPosition - numColumns));
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    moved = true;
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FOCUS_DOWN:
18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (endOfRowPos < mItemCount - 1) {
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_MOVE_SELECTION;
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(Math.min(selectedPosition + numColumns, mItemCount - 1));
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    moved = true;
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
1851599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson        }
1852599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson
1853599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson        final boolean isLayoutRtl = isLayoutRtl();
1854599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson        if (selectedPosition > startOfRowPos && ((direction == FOCUS_LEFT && !isLayoutRtl) ||
1855599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson                (direction == FOCUS_RIGHT && isLayoutRtl))) {
1856599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            mLayoutMode = LAYOUT_MOVE_SELECTION;
1857599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            setSelectionInt(Math.max(0, selectedPosition - 1));
1858599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            moved = true;
1859599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson        } else if (selectedPosition < endOfRowPos && ((direction == FOCUS_LEFT && isLayoutRtl) ||
1860599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson                (direction == FOCUS_RIGHT && !isLayoutRtl))) {
1861599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            mLayoutMode = LAYOUT_MOVE_SELECTION;
1862599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            setSelectionInt(Math.min(selectedPosition + 1, mItemCount - 1));
1863599b64f937dc30468344f2cbdd27861431f0f459Jorn Jacobsson            moved = true;
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (moved) {
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1871f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (moved) {
1872f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
1873f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
187499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return moved;
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18784e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    /**
18794e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * Goes to the next or previous item according to the order set by the
18804e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * adapter.
18814e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     */
18824e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    boolean sequenceScroll(int direction) {
18834e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        int selectedPosition = mSelectedPosition;
18844e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        int numColumns = mNumColumns;
18854e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        int count = mItemCount;
18864e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
18874e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        int startOfRow;
18884e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        int endOfRow;
18894e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        if (!mStackFromBottom) {
18904e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            startOfRow = (selectedPosition / numColumns) * numColumns;
18914e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            endOfRow = Math.min(startOfRow + numColumns - 1, count - 1);
18924e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        } else {
18934e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            int invertedSelection = count - 1 - selectedPosition;
18944e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            endOfRow = count - 1 - (invertedSelection / numColumns) * numColumns;
18954e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            startOfRow = Math.max(0, endOfRow - numColumns + 1);
18964e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
18974e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
18984e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        boolean moved = false;
18994e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        boolean showScroll = false;
19004e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        switch (direction) {
19014e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case FOCUS_FORWARD:
19024e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (selectedPosition < count - 1) {
19034e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    // Move to the next item.
19044e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    mLayoutMode = LAYOUT_MOVE_SELECTION;
19054e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    setSelectionInt(selectedPosition + 1);
19064e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    moved = true;
19074e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    // Show the scrollbar only if changing rows.
19084e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    showScroll = selectedPosition == endOfRow;
19094e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
19104e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
19114e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
19124e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case FOCUS_BACKWARD:
19134e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (selectedPosition > 0) {
19144e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    // Move to the previous item.
19154e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    mLayoutMode = LAYOUT_MOVE_SELECTION;
19164e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    setSelectionInt(selectedPosition - 1);
19174e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    moved = true;
19184e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    // Show the scrollbar only if changing rows.
19194e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    showScroll = selectedPosition == startOfRow;
19204e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
19214e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
19224e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
19234e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
19244e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        if (moved) {
19254e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
19264e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            invokeOnItemScrollListener();
19274e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
19284e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
19294e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        if (showScroll) {
19304e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            awakenScrollBars();
19314e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
19324e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
19334e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        return moved;
19344e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    }
19354e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int closestChildIndex = -1;
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (gainFocus && previouslyFocusedRect != null) {
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previouslyFocusedRect.offset(mScrollX, mScrollY);
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // figure out which item should be selected based on previously
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // focused rect
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Rect otherRect = mTempRect;
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int minDistance = Integer.MAX_VALUE;
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childCount = getChildCount();
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < childCount; i++) {
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // only consider view's on appropriate edge of grid
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!isCandidateSelection(i, direction)) {
19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View other = getChildAt(i);
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                other.getDrawingRect(otherRect);
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetDescendantRectToMyCoords(other, otherRect);
19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int distance = getDistance(previouslyFocusedRect, otherRect, direction);
19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (distance < minDistance) {
19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    minDistance = distance;
19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    closestChildIndex = i;
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (closestChildIndex >= 0) {
19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(closestChildIndex + mFirstPosition);
19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Is childIndex a candidate for next focus given the direction the focus
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * change is coming from?
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childIndex The index to check.
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction The direction, one of
19794e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     *        {FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, FOCUS_BACKWARD}
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether childIndex is a candidate.
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isCandidateSelection(int childIndex, int direction) {
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int invertedIndex = count - 1 - childIndex;
19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowStart;
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowEnd;
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = childIndex - (childIndex % mNumColumns);
19918c8ac8125ac93e87733994190bb54925d188bdc1Evan Rosky            rowEnd = Math.min(rowStart + mNumColumns - 1, count);
19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowEnd = count - 1 - (invertedIndex - (invertedIndex % mNumColumns));
19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowStart = Math.max(0, rowEnd - mNumColumns + 1);
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (direction) {
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case View.FOCUS_RIGHT:
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // coming from left, selection is only valid if it is on left
20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // edge
20019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return childIndex == rowStart;
20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case View.FOCUS_DOWN:
20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // coming from top; only valid if in top row
20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return rowStart == 0;
20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case View.FOCUS_LEFT:
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // coming from right, must be on right edge
20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return childIndex == rowEnd;
20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case View.FOCUS_UP:
20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // coming from bottom, need to be in last row
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return rowEnd == count - 1;
20114e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case View.FOCUS_FORWARD:
20124e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                // coming from top-left, need to be first in top row
20134e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                return childIndex == rowStart && rowStart == 0;
20144e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case View.FOCUS_BACKWARD:
20154e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                // coming from bottom-right, need to be last in bottom row
20164e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                return childIndex == rowEnd && rowEnd == count - 1;
20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("direction must be one of "
20194e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, "
20204e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        + "FOCUS_FORWARD, FOCUS_BACKWARD}.");
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20250b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Set the gravity for this grid. Gravity describes how the child views
20260b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * are horizontally aligned. Defaults to Gravity.LEFT
20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param gravity the gravity to apply to this grid's children
20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_gravity
20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGravity(int gravity) {
20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mGravity != gravity) {
20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mGravity = gravity;
20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20400b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Describes how the child views are horizontally aligned. Defaults to Gravity.LEFT
20410b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20420b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return the gravity that will be applied to this grid's children
20430b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20440b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_gravity
20450b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
20460b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getGravity() {
20470b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mGravity;
20480b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
20490b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell
20500b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
20519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the amount of horizontal (x) spacing to place between each item
20529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the grid.
20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param horizontalSpacing The amount of horizontal space between items,
20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in pixels.
20569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_horizontalSpacing
20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setHorizontalSpacing(int horizontalSpacing) {
20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (horizontalSpacing != mRequestedHorizontalSpacing) {
20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRequestedHorizontalSpacing = horizontalSpacing;
20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20660b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
20670b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Returns the amount of horizontal spacing currently used between each item in the grid.
20680b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20690b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * <p>This is only accurate for the current layout. If {@link #setHorizontalSpacing(int)}
20700b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * has been called but layout is not yet complete, this method may return a stale value.
20710b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * To get the horizontal spacing that was explicitly requested use
20720b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * {@link #getRequestedHorizontalSpacing()}.</p>
20730b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20740b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return Current horizontal spacing between each item in pixels
20750b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20760b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #setHorizontalSpacing(int)
20770b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #getRequestedHorizontalSpacing()
20780b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20790b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_horizontalSpacing
20800b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
20810b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getHorizontalSpacing() {
20820b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mHorizontalSpacing;
20830b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
20840b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell
20850b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
20860b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Returns the requested amount of horizontal spacing between each item in the grid.
20870b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20880b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * <p>The value returned may have been supplied during inflation as part of a style,
20890b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * the default GridView style, or by a call to {@link #setHorizontalSpacing(int)}.
20900b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * If layout is not yet complete or if GridView calculated a different horizontal spacing
20910b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * from what was requested, this may return a different value from
20920b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * {@link #getHorizontalSpacing()}.</p>
20930b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20940b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return The currently requested horizontal spacing between items, in pixels
20950b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20960b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #setHorizontalSpacing(int)
20970b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #getHorizontalSpacing()
20980b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
20990b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_horizontalSpacing
21000b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
21010b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getRequestedHorizontalSpacing() {
21020b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mRequestedHorizontalSpacing;
21030b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the amount of vertical (y) spacing to place between each item
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the grid.
21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param verticalSpacing The amount of vertical space between items,
21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in pixels.
21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21120b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #getVerticalSpacing()
21130b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_verticalSpacing
21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVerticalSpacing(int verticalSpacing) {
21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (verticalSpacing != mVerticalSpacing) {
21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVerticalSpacing = verticalSpacing;
21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21240b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Returns the amount of vertical spacing between each item in the grid.
21250b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21260b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return The vertical spacing between items in pixels
21270b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21280b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #setVerticalSpacing(int)
21290b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21300b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_verticalSpacing
21310b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
21320b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getVerticalSpacing() {
21330b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mVerticalSpacing;
21340b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
21350b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell
21360b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Control how items are stretched to fill their space.
21389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stretchMode Either {@link #NO_STRETCH},
21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #STRETCH_SPACING}, {@link #STRETCH_SPACING_UNIFORM}, or {@link #STRETCH_COLUMN_WIDTH}.
21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_stretchMode
21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2144d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public void setStretchMode(@StretchMode int stretchMode) {
21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (stretchMode != mStretchMode) {
21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStretchMode = stretchMode;
21479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
21489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2151d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @StretchMode
21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStretchMode() {
21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStretchMode;
21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the width of columns in the grid.
21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param columnWidth The column width, in pixels.
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_columnWidth
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setColumnWidth(int columnWidth) {
21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (columnWidth != mRequestedColumnWidth) {
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRequestedColumnWidth = columnWidth;
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21710b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Return the width of a column in the grid.
21720b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21730b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * <p>This may not be valid yet if a layout is pending.</p>
21740b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21750b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return The column width in pixels
21760b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21770b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #setColumnWidth(int)
21780b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #getRequestedColumnWidth()
21790b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21800b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_columnWidth
21810b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
21820b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getColumnWidth() {
21830b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mColumnWidth;
21840b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
21850b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell
21860b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
21870b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * Return the requested width of a column in the grid.
21880b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21890b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * <p>This may not be the actual column width used. Use {@link #getColumnWidth()}
21900b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * to retrieve the current real width of a column.</p>
21910b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21920b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @return The requested column width in pixels
21930b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21940b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #setColumnWidth(int)
21950b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @see #getColumnWidth()
21960b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     *
21970b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     * @attr ref android.R.styleable#GridView_columnWidth
21980b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell     */
21990b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    public int getRequestedColumnWidth() {
22000b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell        return mRequestedColumnWidth;
22010b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    }
22020b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell
22030b7413d5d6239b7bc43816bea5187b323a633b11Adam Powell    /**
22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the number of columns in the grid
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numColumns The desired number of columns.
22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @attr ref android.R.styleable#GridView_numColumns
22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setNumColumns(int numColumns) {
22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numColumns != mRequestedNumColumns) {
22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRequestedNumColumns = numColumns;
22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayoutIfNecessary();
22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
221699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
22178d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein    /**
221899441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     * Get the number of columns in the grid.
22198d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein     * Returns {@link #AUTO_FIT} if the Grid has never been laid out.
22208d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein     *
22218d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein     * @attr ref android.R.styleable#GridView_numColumns
222299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas     *
22238d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein     * @see #setNumColumns(int)
22248d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein     */
22258d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein    @ViewDebug.ExportedProperty
222699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas    public int getNumColumns() {
22278d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein        return mNumColumns;
22288d9db8e4c774bb75bc8c08cc5309a7c0712ce017Andrew Sapperstein    }
22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Make sure views are touching the top or bottom edge, as appropriate for
22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * our gravity
22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void adjustViewsUpOrDown() {
22359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int delta;
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child;
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Uh-oh -- we came up short. Slide all views up to make them
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // align with the top
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(0);
22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getTop() - mListPadding.top;
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition != 0) {
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space above the first item if it is
22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta -= mVerticalSpacing;
22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta < 0) {
22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We only are looking to see if we are too low, not too high
22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are too high, slide all views down to align with bottom
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(childCount - 1);
22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getBottom() - (getHeight() - mListPadding.bottom);
225999441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
22609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition + childCount < mItemCount) {
22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space below the last item if it is
22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta += mVerticalSpacing;
22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
226599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta > 0) {
22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We only are looking to see if we are too high, not too low
22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (delta != 0) {
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(-delta);
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
227799441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected int computeVerticalScrollExtent() {
22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numColumns = mNumColumns;
22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int rowCount = (count + numColumns - 1) / numColumns;
228499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int extent = rowCount * 100;
22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View view = getChildAt(0);
22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int top = view.getTop();
22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int height = view.getHeight();
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (height > 0) {
22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                extent += (top * 100) / height;
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            view = getChildAt(count - 1);
22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int bottom = view.getBottom();
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            height = view.getHeight();
22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (height > 0) {
22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                extent -= ((bottom - getHeight()) * 100) / height;
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return extent;
23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected int computeVerticalScrollOffset() {
23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition >= 0 && getChildCount() > 0) {
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = getChildAt(0);
23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int top = view.getTop();
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int height = view.getHeight();
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (height > 0) {
2313f2a204e792df5593cfe54efc95d04b7e764795c1Adam Powell                final int numColumns = mNumColumns;
2314f2a204e792df5593cfe54efc95d04b7e764795c1Adam Powell                final int rowCount = (mItemCount + numColumns - 1) / numColumns;
2315bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                // In case of stackFromBottom the calculation of whichRow needs
2316bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                // to take into account that counting from the top the first row
2317bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                // might not be entirely filled.
2318bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                final int oddItemsOnFirstRow = isStackFromBottom() ? ((rowCount * numColumns) -
2319bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                        mItemCount) : 0;
2320bbf7b4cdcfbc5aa436500dad96e73f7a3b32e794Pieter-Jan Vandormael                final int whichRow = (mFirstPosition + oddItemsOnFirstRow) / numColumns;
2321f2a204e792df5593cfe54efc95d04b7e764795c1Adam Powell                return Math.max(whichRow * 100 - (top * 100) / height +
2322f2a204e792df5593cfe54efc95d04b7e764795c1Adam Powell                        (int) ((float) mScrollY / getHeight() * rowCount * 100), 0);
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected int computeVerticalScrollRange() {
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // TODO: Account for vertical spacing too
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numColumns = mNumColumns;
23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int rowCount = (mItemCount + numColumns - 1) / numColumns;
2333637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        int result = Math.max(rowCount * 100, 0);
2334637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (mScrollY != 0) {
2335637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            // Compensate for overscroll
2336637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            result += Math.abs((int) ((float) mScrollY / getHeight() * rowCount * 100));
2337637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
2338637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        return result;
23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23418a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
2342a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
2343a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return GridView.class.getName();
23448a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
23458a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
2346a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    /** @hide */
23478a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
2348a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2349a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette        super.onInitializeAccessibilityNodeInfoInternal(info);
23505b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
23515b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int columnsCount = getNumColumns();
23525b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int rowsCount = getCount() / columnsCount;
235376769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final int selectionMode = getSelectionModeForAccessibility();
235476769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final CollectionInfo collectionInfo = CollectionInfo.obtain(
235577c180a5137348022fce388930a9781863f83e74Alan Viverette                rowsCount, columnsCount, false, selectionMode);
23565b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        info.setCollectionInfo(collectionInfo);
235723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
235823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        if (columnsCount > 0 || rowsCount > 0) {
235923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            info.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION);
236023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
236123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    }
236223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
236323f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    /** @hide */
236423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    @Override
236523f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
236623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        if (super.performAccessibilityActionInternal(action, arguments)) {
236723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            return true;
236823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
236923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
237023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        switch (action) {
237123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            case R.id.accessibilityActionScrollToPosition: {
237223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                // GridView only supports scrolling in one direction, so we can
237323f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                // ignore the column argument.
237423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                final int numColumns = getNumColumns();
237523f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                final int row = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_ROW_INT, -1);
237623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                final int position = Math.min(row * numColumns, getCount() - 1);
237723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                if (row >= 0) {
237823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    // The accessibility service gets data asynchronously, so
237923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    // we'll be a little lenient by clamping the last position.
238023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    smoothScrollToPosition(position);
238123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    return true;
238223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                }
238323f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            } break;
238423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
238523f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
238623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        return false;
23875b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    }
23885b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
23895b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    @Override
23905b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    public void onInitializeAccessibilityNodeInfoForItem(
23915b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            View view, int position, AccessibilityNodeInfo info) {
23925b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
23935b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
23945b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int count = getCount();
23955b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int columnsCount = getNumColumns();
23965b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int rowsCount = count / columnsCount;
23975b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
23985b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int row;
23995b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final int column;
24005b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        if (!mStackFromBottom) {
24015b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            column = position % columnsCount;
24025b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            row = position / columnsCount;
24035b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        } else {
24045b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            final int invertedIndex = count - 1 - position;
24055b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
24065b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            column = columnsCount - 1 - (invertedIndex % columnsCount);
24075b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            row = rowsCount - 1 - invertedIndex / columnsCount;
24085b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        }
24095b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
24105b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
2411061b16ff88ede08b0333d2bad5f1f9b60a302183Steven Dao        final boolean isHeading = lp != null && lp.viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
241276769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final boolean isSelected = isItemChecked(position);
241376769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
241477c180a5137348022fce388930a9781863f83e74Alan Viverette                row, 1, column, 1, isHeading, isSelected);
24155b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        info.setCollectionItemInfo(itemInfo);
24168a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
241794a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
241894a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    /** @hide */
241994a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    @Override
242094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
242194a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        super.encodeProperties(encoder);
242294a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        encoder.addProperty("numColumns", getNumColumns());
242394a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    }
24248a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov}
2425