19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 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
19fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport com.android.internal.R;
20fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport com.google.android.collect.Lists;
21fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
258f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guyimport android.graphics.Paint;
26fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.PixelFormat;
27fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.Rect;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.ColorDrawable;
29fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.drawable.Drawable;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
338f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powellimport android.util.LongSparseArray;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseBooleanArray;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.FocusFinder;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent;
38fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.view.SoundEffectConstants;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewDebug;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewParent;
4375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.accessibility.AccessibilityEvent;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation Notes:
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Some terminology:
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     index    - index of the items that are currently visible
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     position - index of the items in the cursor
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that shows items in a vertically scrolling list. The items
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * come from the {@link ListAdapter} associated with this view.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_entries
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_divider
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_dividerHeight
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_choiceMode
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_headerDividersEnabled
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_footerDividersEnabled
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ListView extends AbsListView {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Used to indicate a no preference for a position type.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int NO_POSITION = -1;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Normal list that does not indicate choices
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int CHOICE_MODE_NONE = 0;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The list allows up to one choice
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int CHOICE_MODE_SINGLE = 1;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The list allows multiple choices
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int CHOICE_MODE_MULTIPLE = 2;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When arrow scrolling, ListView will never scroll more than this factor
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * times the height of the list.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAX_SCROLL_FACTOR = 0.33f;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When arrow scrolling, need a certain amount of pixels to preview next
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * items.  This is usually the fading edge, but if that is small enough,
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * we want to make sure we preview at least this many pixels.
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MIN_SCROLL_PREVIEW_PIXELS = 2;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A class that represents a fixed view in a list, for example a header at the top
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or a footer at the bottom.
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class FixedViewInfo {
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** The view to add to the list */
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public View view;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Object data;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** <code>true</code> if the fixed view should be selectable in the list */
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isSelectable;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Drawable mDivider;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mDividerHeight;
120bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
12124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    private boolean mIsCacheColorOpaque;
12224443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    private boolean mDividerIsOpaque;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mClipDivider;
12424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mHeaderDividersEnabled;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mFooterDividersEnabled;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAreAllItemsSelectable = true;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mItemsCanFocus = false;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mChoiceMode = CHOICE_MODE_NONE;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SparseBooleanArray mCheckStates;
1358f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell    private LongSparseArray<Boolean> mCheckedIdStates;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // used for temporary calculations.
138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private final Rect mTempRect = new Rect();
139a02903fbee6725563da4472bd120f844e9d5518cRomain Guy    private Paint mDividerPaint;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // the single allocated result per list view; kinda cheesey but avoids
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // allocating these thingies too often.
1439c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy    private final ArrowScrollFocusResult mArrowScrollFocusResult = new ArrowScrollFocusResult();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    // Keeps focused children visible through resizes
1469bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    private FocusSelector mFocusSelector;
1479bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListView(Context context) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListView(Context context, AttributeSet attrs) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, attrs, com.android.internal.R.attr.listViewStyle);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListView(Context context, AttributeSet attrs, int defStyle) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs,
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.ListView, defStyle, 0);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence[] entries = a.getTextArray(
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.ListView_entries);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (entries != null) {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setAdapter(new ArrayAdapter<CharSequence>(context,
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    com.android.internal.R.layout.simple_list_item_1, entries));
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (d != null) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If a divider is specified use its intrinsic height for divider height
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setDivider(d);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
174bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Use the height specified, zero being the default
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = a.getDimensionPixelSize(
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.ListView_dividerHeight, 0);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dividerHeight != 0) {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setDividerHeight(dividerHeight);
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
182536fb04c1c419d5dd3816112ab5af7baee7cd549Romain Guy        setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE));
183536fb04c1c419d5dd3816112ab5af7baee7cd549Romain Guy
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The maximum amount a list view will scroll in response to
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   an arrow event.
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMaxScrollAmount() {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Make sure views are touching the top or bottom edge, as appropriate for
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * our gravity
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void adjustViewsUpOrDown() {
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int delta;
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Uh-oh -- we came up short. Slide all views up to make them
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // align with the top
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(0);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getTop() - mListPadding.top;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition != 0) {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space above the first item if it is
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta -= mDividerHeight;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta < 0) {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We only are looking to see if we are too low, not too high
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are too high, slide all views down to align with bottom
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(childCount - 1);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getBottom() - (getHeight() - mListPadding.bottom);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition + childCount < mItemCount) {
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space below the last item if it is
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta += mDividerHeight;
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta > 0) {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (delta != 0) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(-delta);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the top of the list. If addHeaderView is
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
251176f9fc215194411cf0461a178d77fa57486112bGilles Debunne     * the supplied cursor with one that will also account for header and footer
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * views.
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param data Data to associate with this view
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isSelectable whether the item is selectable
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addHeaderView(View v, Object data, boolean isSelectable) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException(
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Cannot add header view to list -- setAdapter has already been called.");
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FixedViewInfo info = new FixedViewInfo();
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.view = v;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.data = data;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.isSelectable = isSelectable;
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderViewInfos.add(info);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the top of the list. If addHeaderView is
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
278176f9fc215194411cf0461a178d77fa57486112bGilles Debunne     * the supplied cursor with one that will also account for header and footer
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * views.
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addHeaderView(View v) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addHeaderView(v, null, true);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getHeaderViewsCount() {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderViewInfos.size();
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Removes a previously-added header view.
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to remove
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the view was removed, false if the view was not a header
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         view
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean removeHeaderView(View v) {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeaderViewInfos.size() > 0) {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean result = false;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataSetObserver.onChanged();
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = true;
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeFixedViewInfo(v, mHeaderViewInfos);
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = where.size();
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; ++i) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FixedViewInfo info = where.get(i);
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (info.view == v) {
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                where.remove(i);
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the bottom of the list. If addFooterView is
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * NOTE: Call this before calling setAdapter. This is so ListView can wrap
329176f9fc215194411cf0461a178d77fa57486112bGilles Debunne     * the supplied cursor with one that will also account for header and footer
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * views.
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param data Data to associate with this view
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isSelectable true if the footer view can be selected
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addFooterView(View v, Object data, boolean isSelectable) {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FixedViewInfo info = new FixedViewInfo();
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.view = v;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.data = data;
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.isSelectable = isSelectable;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterViewInfos.add(info);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // in the case of re-adding a footer view, or adding one later on,
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // we need to notify the observer
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDataSetObserver != null) {
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataSetObserver.onChanged();
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the bottom of the list. If addFooterView is called more
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * than once, the views will appear in the order they were added. Views added using
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this call can take focus if they want.
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplied
355176f9fc215194411cf0461a178d77fa57486112bGilles Debunne     * cursor with one that will also account for header and footer views.
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addFooterView(View v) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addFooterView(v, null, true);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getFooterViewsCount() {
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mFooterViewInfos.size();
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Removes a previously-added footer view.
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to remove
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * true if the view was removed, false if the view was not a footer view
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean removeFooterView(View v) {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFooterViewInfos.size() > 0) {
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean result = false;
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataSetObserver.onChanged();
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = true;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeFixedViewInfo(v, mFooterViewInfos);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the adapter currently in use in this ListView. The returned adapter
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * might not be the same adapter passed to {@link #setAdapter(ListAdapter)} but
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * might be a {@link WrapperListAdapter}.
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The adapter currently used to display data in this ListView.
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setAdapter(ListAdapter)
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListAdapter getAdapter() {
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAdapter;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the data behind this ListView.
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * depending on the ListView features currently in use. For instance, adding
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * headers and/or footers will cause the adapter to be wrapped.
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param adapter The ListAdapter which is responsible for maintaining the
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        data backing this list and for producing a view to represent an
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        item in that data set.
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getAdapter()
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAdapter(ListAdapter adapter) {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (null != mAdapter) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.unregisterDataSetObserver(mDataSetObserver);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        resetList();
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRecycler.clear();
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter = adapter;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedPosition = INVALID_POSITION;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedRowId = INVALID_ROW_ID;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOldItemCount = mItemCount;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mItemCount = mAdapter.getCount();
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkFocus();
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataSetObserver = new AdapterDataSetObserver();
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.registerDataSetObserver(mDataSetObserver);
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position;
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStackFromBottom) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(mItemCount - 1, false);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(0, true);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(position);
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(position);
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount == 0) {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Nothing selected
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSelectionChanged();
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
458cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell            if (mChoiceMode != CHOICE_MODE_NONE &&
459cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell                    mAdapter.hasStableIds() &&
460cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell                    mCheckedIdStates == null) {
461cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell                mCheckedIdStates = new LongSparseArray<Boolean>();
462cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell            }
463cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAreAllItemsSelectable = true;
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkFocus();
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Nothing selected
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCheckStates != null) {
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCheckStates.clear();
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4748f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
4758f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        if (mCheckedIdStates != null) {
4768f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            mCheckedIdStates.clear();
4778f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The list is empty. Clear everything out.
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void resetList() {
4882e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        // The parent's resetList() will remove all views from the layout so we need to
4892e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        // cleanup the state of our footers and headers
4902e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        clearRecycledState(mHeaderViewInfos);
4912e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        clearRecycledState(mFooterViewInfos);
4922e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.resetList();
4942e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayoutMode = LAYOUT_NORMAL;
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4982e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy    private void clearRecycledState(ArrayList<FixedViewInfo> infos) {
4992e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        if (infos != null) {
5002e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            final int count = infos.size();
5012e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5022e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            for (int i = 0; i < count; i++) {
5032e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                final View child = infos.get(i).view;
5042e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                final LayoutParams p = (LayoutParams) child.getLayoutParams();
5052e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                if (p != null) {
5062e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                    p.recycledHeaderFooter = false;
5072e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                }
5082e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            }
5092e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        }
5102e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy    }
5112e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the list needs to show the top fading edge
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean showingTopFadingEdge() {
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mScrollY + mListPadding.top;
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mFirstPosition > 0) || (getChildAt(0).getTop() > listTop);
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the list needs to show the bottom fading edge
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean showingBottomFadingEdge() {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int lastVisiblePosition = mFirstPosition + childCount - 1;
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = mScrollY + getHeight() - mListPadding.bottom;
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (lastVisiblePosition < mItemCount - 1)
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         || (bottomOfBottomChild < listBottom);
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rectTopWithinChild = rect.top;
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // offset so rect is in coordinates of the this view
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        rect.offset(child.getLeft(), child.getTop());
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        rect.offset(-child.getScrollX(), -child.getScrollY());
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int height = getHeight();
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listUnfadedTop = getScrollY();
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listUnfadedBottom = listUnfadedTop + height;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int fadingEdge = getVerticalFadingEdgeLength();
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (showingTopFadingEdge()) {
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // leave room for top fading edge as long as rect isn't at very top
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mSelectedPosition > 0) || (rectTopWithinChild > fadingEdge)) {
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listUnfadedTop += fadingEdge;
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childCount = getChildCount();
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (showingBottomFadingEdge()) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // leave room for bottom fading edge as long as rect isn't at very bottom
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mSelectedPosition < mItemCount - 1)
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || (rect.bottom < (bottomOfBottomChild - fadingEdge))) {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listUnfadedBottom -= fadingEdge;
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int scrollYDelta = 0;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rect.bottom > listUnfadedBottom && rect.top > listUnfadedTop) {
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to MOVE DOWN to get it in view: move down just enough so
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // that the entire rectangle is in view (or at least the first
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // screen size chunk).
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rect.height() > height) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // just enough to get screen size chunk on
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta += (rect.top - listUnfadedTop);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // get entire rect at bottom of screen
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta += (rect.bottom - listUnfadedBottom);
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // make sure we aren't scrolling beyond the end of our children
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int distanceToBottom = bottomOfBottomChild - listUnfadedBottom;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (rect.top < listUnfadedTop && rect.bottom < listUnfadedBottom) {
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to MOVE UP to get it in view: move up just enough so that
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // entire rectangle is in view (or at least the first screen
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // size chunk of it).
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rect.height() > height) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // screen size chunk
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta -= (listUnfadedBottom - rect.bottom);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // entire rect at top
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta -= (listUnfadedTop - rect.top);
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // make sure we aren't scrolling any further than the top our children
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int top = getChildAt(0).getTop();
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int deltaToTop = top - listUnfadedTop;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollYDelta = Math.max(scrollYDelta, deltaToTop);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean scroll = scrollYDelta != 0;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scroll) {
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListItemsBy(-scrollYDelta);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            positionSelector(child);
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSelectedTop = child.getTop();
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return scroll;
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@inheritDoc}
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void fillGap(boolean down) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (down) {
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ? getChildAt(count - 1).getBottom() + mDividerHeight :
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getListPaddingTop();
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(mFirstPosition + count, startOffset);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ? getChildAt(0).getTop() - mDividerHeight :
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getHeight() - getListPaddingBottom();
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(mFirstPosition - 1, startOffset);
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos down to the end of the list view.
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the item associated with pos
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        should be drawn
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected, if it happens to be in the
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         range that we draw.
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillDown(int pos, int nextTop) {
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = (mBottom - mTop) - mListPadding.bottom;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextTop < end && pos < mItemCount) {
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is this the selected item?
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected = pos == mSelectedPosition;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextTop = child.getBottom() + mDividerHeight;
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selected) {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = child;
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos++;
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos up to the top of the list view.
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextBottom The location where the bottom of the item associated
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        with pos should be drawn
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillUp(int pos, int nextBottom) {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = mListPadding.top;
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextBottom > end && pos >= 0) {
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is this the selected item?
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected = pos == mSelectedPosition;
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child = makeAndAddView(pos, nextBottom, false, mListPadding.left, selected);
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextBottom = child.getTop() - mDividerHeight;
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selected) {
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = child;
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos--;
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = pos + 1;
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from top to bottom, starting with mFirstPosition
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the first item should be
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        drawn
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromTop(int nextTop) {
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition < 0) {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFirstPosition = 0;
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fillDown(mFirstPosition, nextTop);
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Put mSelectedPosition in the middle of the screen and then build up and
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * down from there. This method forces mSelectedPosition to the center.
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Top of the area in which children can be drawn, as
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        measured in pixels
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Bottom of the area in which children can be drawn,
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        as measured in pixels
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Currently selected view
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromMiddle(int childrenTop, int childrenBottom) {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int height = childrenBottom - childrenTop;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int position = reconcileSelectedPosition();
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel = makeAndAddView(position, childrenTop, true,
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left, true);
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = position;
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int selHeight = sel.getMeasuredHeight();
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selHeight <= height) {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom((height - selHeight) / 2);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fillAboveAndBelow(sel, position);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Once the selected view as been placed, fill up the visible area above and
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * below it.
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sel The selected view
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The position corresponding to sel
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void fillAboveAndBelow(View sel, int position) {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(position - 1, sel.getTop() - dividerHeight);
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(position + 1, sel.getBottom() + dividerHeight);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(position + 1, sel.getBottom() + dividerHeight);
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(position - 1, sel.getTop() - dividerHeight);
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the grid based on positioning the new selection at a specific
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location. The selection may be moved so that it does not intersect the
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * faded edges. The grid is then filled upwards and downwards from there.
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedTop Where the selected item should be
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromSelection(int selectedTop, int childrenTop, int childrenBottom) {
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fadingEdgeLength = getVerticalFadingEdgeLength();
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength,
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sel = makeAndAddView(selectedPosition, selectedTop, true, mListPadding.left, true);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Some of the newly selected item extends below the bottom of the list
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sel.getBottom() > bottomSelectionPixel) {
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available above the selection into which we can scroll
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // upwards
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceAbove = sel.getTop() - topSelectionPixel;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the bottom of the selected item
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // fully into view
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceBelow = sel.getBottom() - bottomSelectionPixel;
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = Math.min(spaceAbove, spaceBelow);
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now offset the selected item to get it into view
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom(-offset);
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (sel.getTop() < topSelectionPixel) {
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the top of the selected item fully
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // into view
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceAbove = topSelectionPixel - sel.getTop();
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available below the selection into which we can scroll
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // downwards
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceBelow = bottomSelectionPixel - sel.getBottom();
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = Math.min(spaceAbove, spaceBelow);
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Offset the selected item to get it into view
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom(offset);
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Fill in views above and below
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fillAboveAndBelow(sel, selectedPosition);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the bottom-most pixel we can draw the selection into
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Bottom pixel were children can be drawn
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedPosition The position that will be selected
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The bottom-most pixel we can draw the selection into
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getBottomSelectionPixel(int childrenBottom, int fadingEdgeLength,
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int selectedPosition) {
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomSelectionPixel = childrenBottom;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedPosition != mItemCount - 1) {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomSelectionPixel -= fadingEdgeLength;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return bottomSelectionPixel;
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the top-most pixel we can draw the selection into
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Top pixel were children can be drawn
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedPosition The position that will be selected
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The top-most pixel we can draw the selection into
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getTopSelectionPixel(int childrenTop, int fadingEdgeLength, int selectedPosition) {
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // first pixel we can draw the selection into
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topSelectionPixel = childrenTop;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedPosition > 0) {
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topSelectionPixel += fadingEdgeLength;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return topSelectionPixel;
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list based on positioning the new selection relative to the old
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * selection. The new selection will be placed at, above, or below the
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location of the new selection depending on how the selection is moving.
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The selection will then be pinned to the visible part of the screen,
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * excluding the edges that are faded. The list is then filled upwards and
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * downwards from there.
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param oldSel The old selected view. Useful for trying to put the new
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        selection in the same place
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newSel The view that is to become selected. Useful for trying to
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        put the new selection in the same place
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param delta Which way we are moving
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View moveSelection(View oldSel, View newSel, int delta, int childrenTop,
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childrenBottom) {
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fadingEdgeLength = getVerticalFadingEdgeLength();
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomSelectionPixel = getBottomSelectionPixel(childrenTop, fadingEdgeLength,
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (delta > 0) {
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 1: Scrolling down.
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *     Before           After
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   A   |        |   A   |
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   1   |   =>   +-------+
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        |   B   |
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   B   |        |   2   |
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    Try to keep the top of the previously selected item where it was.
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    oldSel = A
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    sel = B
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Put oldSel (A) where it belongs
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            oldSel = makeAndAddView(selectedPosition - 1, oldSel.getTop(), true,
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left, false);
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int dividerHeight = mDividerHeight;
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now put the new selection (B) below that
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeAndAddView(selectedPosition, oldSel.getBottom() + dividerHeight, true,
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left, true);
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Some of the newly selected item extends below the bottom of the list
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel.getBottom() > bottomSelectionPixel) {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space available above the selection into which we can scroll upwards
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceAbove = sel.getTop() - topSelectionPixel;
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space required to bring the bottom of the selected item fully into view
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceBelow = sel.getBottom() - bottomSelectionPixel;
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't scroll more than half the height of the list
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int halfVerticalSpace = (childrenBottom - childrenTop) / 2;
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int offset = Math.min(spaceAbove, spaceBelow);
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offset = Math.min(offset, halfVerticalSpace);
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We placed oldSel, so offset that item
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldSel.offsetTopAndBottom(-offset);
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Now offset the selected item to get it into view
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel.offsetTopAndBottom(-offset);
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (delta < 0) {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 2: Scrolling up.
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *     Before           After
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   A   |        |   A   |
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+   =>   |   1   |
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   B   |        +-------+
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   2   |        |   B   |
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    Try to keep the top of the item about to become selected where it was.
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    newSel = A
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    olSel = B
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (newSel != null) {
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try to position the top of newSel (A) where it was before it was selected
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = makeAndAddView(selectedPosition, newSel.getTop(), true, mListPadding.left,
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        true);
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If (A) was not on screen and so did not have a view, position
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // it above the oldSel (B)
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = makeAndAddView(selectedPosition, oldSel.getTop(), false, mListPadding.left,
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        true);
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Some of the newly selected item extends above the top of the list
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel.getTop() < topSelectionPixel) {
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space required to bring the top of the selected item fully into view
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceAbove = topSelectionPixel - sel.getTop();
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               // Find space available below the selection into which we can scroll downwards
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceBelow = bottomSelectionPixel - sel.getBottom();
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't scroll more than half the height of the list
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int halfVerticalSpace = (childrenBottom - childrenTop) / 2;
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int offset = Math.min(spaceAbove, spaceBelow);
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offset = Math.min(offset, halfVerticalSpace);
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Offset the selected item to get it into view
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel.offsetTopAndBottom(offset);
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillAboveAndBelow(sel, selectedPosition);
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldTop = oldSel.getTop();
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 3: Staying still
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeAndAddView(selectedPosition, oldTop, true, mListPadding.left, true);
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We're staying still...
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldTop < childrenTop) {
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... but the top of the old selection was off screen.
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // (This can happen if the data changes size out from under us)
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int newBottom = sel.getBottom();
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newBottom < childrenTop + 20) {
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Not enough visible -- bring it onscreen
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel.offsetTopAndBottom(childrenTop - sel.getTop());
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillAboveAndBelow(sel, selectedPosition);
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10359bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    private class FocusSelector implements Runnable {
10369bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        private int mPosition;
10379bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        private int mPositionTop;
10389bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
10399bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        public FocusSelector setup(int position, int top) {
10409bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            mPosition = position;
10419bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            mPositionTop = top;
10429bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            return this;
10439bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
10449bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
10459bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        public void run() {
10469bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            setSelectionFromTop(mPosition, mPositionTop);
10479bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
10489bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    }
10499bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
10509bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    @Override
10519bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
10529bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        if (getChildCount() > 0) {
10539bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            View focusedChild = getFocusedChild();
10549bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            if (focusedChild != null) {
10559bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int childPosition = mFirstPosition + indexOfChild(focusedChild);
10569bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int childBottom = focusedChild.getBottom();
10579bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int offset = Math.max(0, childBottom - (h - mPaddingTop));
10589bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int top = focusedChild.getTop() - offset;
10599bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                if (mFocusSelector == null) {
10609bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                    mFocusSelector = new FocusSelector();
10619bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                }
10629bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                post(mFocusSelector.setup(childPosition, top));
10639bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            }
10649bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
10659bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        super.onSizeChanged(w, h, oldw, oldh);
10669bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    }
10679bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Sets up mListPadding
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidth = 0;
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeight = 0;
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                heightMode == MeasureSpec.UNSPECIFIED)) {
108421875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            final View child = obtainView(0, mIsScrap);
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureScrapChild(child, 0, widthMeasureSpec);
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childWidth = child.getMeasuredWidth();
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeight = child.getMeasuredHeight();
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10919c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy            if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
10929c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy                    ((LayoutParams) child.getLayoutParams()).viewType)) {
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mRecycler.addScrapView(child);
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (widthMode == MeasureSpec.UNSPECIFIED) {
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            widthSize = mListPadding.left + mListPadding.right + childWidth +
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getVerticalScrollbarWidth();
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.UNSPECIFIED) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = mListPadding.top + mListPadding.bottom + childHeight +
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getVerticalFadingEdgeLength() * 2;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.AT_MOST) {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: after first layout we should maybe start at the first visible position, not 0
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setMeasuredDimension(widthSize, heightSize);
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWidthMeasureSpec = widthMeasureSpec;
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void measureScrapChild(View child, int position, int widthMeasureSpec) {
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LayoutParams p = (LayoutParams) child.getLayoutParams();
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
1119980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy            p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ViewGroup.LayoutParams.WRAP_CONTENT, 0);
11214df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            child.setLayoutParams(p);
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p.viewType = mAdapter.getItemViewType(position);
11240bf88594c43ced48d862d122e3e84967b3b63658Romain Guy        p.forceAdd = true;
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left + mListPadding.right, p.width);
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lpHeight = p.height;
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeightSpec;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lpHeight > 0) {
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.measure(childWidthSpec, childHeightSpec);
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True to recycle the views used to measure this ListView in
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         UNSPECIFIED/AT_MOST modes, false otherwise.
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1143986003d46add147714ce7e16c9fefa8c18042fc8Romain Guy    @ViewDebug.ExportedProperty
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean recycleOnMeasure() {
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Measures the height of the given range of children (inclusive) and
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * returns the height with this ListView's padding and divider heights
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * included. If maxHeight is provided, the measuring will stop when the
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * current height reaches maxHeight.
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param widthMeasureSpec The width measure spec to be given to a child's
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            {@link View#measure(int, int)}.
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param startPosition The position of the first child to be shown.
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param endPosition The (inclusive) position of the last child to be
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            shown. Specify {@link #NO_POSITION} if the last child should be
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            the last available child from the adapter.
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param maxHeight The maximum height that will be returned (if all the
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            children don't fit in this value, this value will be
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            returned).
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param disallowPartialChildPosition In general, whether the returned
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            height should only contain entire children. This is more
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            powerful--it is the first inclusive position at which partial
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            children will not be allowed. Example: it looks nice to have
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            at least 3 completely visible children, and in portrait this
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            will most likely fit; but in landscape there could be times
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            when even 2 children can not be completely shown, so a value
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            of 2 (remember, inclusive) would be good (assuming
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            startPosition is 0).
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The height of this ListView with the given children.
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int maxHeight, int disallowPartialChildPosition) {
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ListAdapter adapter = mAdapter;
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null) {
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mListPadding.top + mListPadding.bottom;
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Include the padding of the list
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int returnedHeight = mListPadding.top + mListPadding.bottom;
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = ((mDividerHeight > 0) && mDivider != null) ? mDividerHeight : 0;
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The previous height value that was less than maxHeight and contained
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // no partial children
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int prevHeightWithoutPartialChild = 0;
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int i;
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mItemCount - 1 since endPosition parameter is inclusive
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final AbsListView.RecycleBin recycleBin = mRecycler;
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean recyle = recycleOnMeasure();
119521875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        final boolean[] isScrap = mIsScrap;
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (i = startPosition; i <= endPosition; ++i) {
119821875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            child = obtainView(i, isScrap);
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureScrapChild(child, i, widthMeasureSpec);
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (i > 0) {
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Count the divider for all but one child
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                returnedHeight += dividerHeight;
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Recycle the view before we possibly return from the method
12089c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy            if (recyle && recycleBin.shouldRecycleViewType(
12099c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy                    ((LayoutParams) child.getLayoutParams()).viewType)) {
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                recycleBin.addScrapView(child);
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            returnedHeight += child.getMeasuredHeight();
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (returnedHeight >= maxHeight) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We went over, figure out which height to return.  If returnedHeight > maxHeight,
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // then the i'th position did not fit completely.
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (i > disallowPartialChildPosition) // We've past the min pos
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (prevHeightWithoutPartialChild > 0) // We have a prev height
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (returnedHeight != maxHeight) // i'th child did not fit completely
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ? prevHeightWithoutPartialChild
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        : maxHeight;
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                prevHeightWithoutPartialChild = returnedHeight;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // At this point, we went through the range of children, and they each
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // completely fit, so return the returnedHeight
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return returnedHeight;
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int findMotionRow(int y) {
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childCount = getChildCount();
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
124084222e04252720cf681032e865db526ce4a612a4Adam Powell            if (!mStackFromBottom) {
124184222e04252720cf681032e865db526ce4a612a4Adam Powell                for (int i = 0; i < childCount; i++) {
124284222e04252720cf681032e865db526ce4a612a4Adam Powell                    View v = getChildAt(i);
124384222e04252720cf681032e865db526ce4a612a4Adam Powell                    if (y <= v.getBottom()) {
124484222e04252720cf681032e865db526ce4a612a4Adam Powell                        return mFirstPosition + i;
124584222e04252720cf681032e865db526ce4a612a4Adam Powell                    }
124684222e04252720cf681032e865db526ce4a612a4Adam Powell                }
124784222e04252720cf681032e865db526ce4a612a4Adam Powell            } else {
124884222e04252720cf681032e865db526ce4a612a4Adam Powell                for (int i = childCount - 1; i >= 0; i--) {
124984222e04252720cf681032e865db526ce4a612a4Adam Powell                    View v = getChildAt(i);
125084222e04252720cf681032e865db526ce4a612a4Adam Powell                    if (y >= v.getTop()) {
125184222e04252720cf681032e865db526ce4a612a4Adam Powell                        return mFirstPosition + i;
125284222e04252720cf681032e865db526ce4a612a4Adam Powell                    }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Put a specific item at a specific location on the screen and then build
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * up and down from there.
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The reference view to use as the starting point
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param top Pixel offset from the top of this view to the top of the
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        reference view.
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The selected view, or null if the selected view is outside the
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         visible area.
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillSpecific(int position, int top) {
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean tempIsSelected = position == mSelectedPosition;
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View temp = makeAndAddView(position, top, true, mListPadding.left, tempIsSelected);
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Possibly changed again in fillUp if we add rows above this one.
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = position;
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View above;
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View below;
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(position - 1, temp.getTop() - dividerHeight);
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This will correct for the top of the first view not touching the top of the list
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(position + 1, temp.getBottom() + dividerHeight);
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                correctTooHigh(childCount);
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(position + 1, temp.getBottom() + dividerHeight);
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This will correct for the bottom of the last view not touching the bottom of the list
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(position - 1, temp.getTop() - dividerHeight);
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 correctTooLow(childCount);
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tempIsSelected) {
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return temp;
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (above != null) {
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return above;
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return below;
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check if we have dragged the bottom of the list too high (we have pushed the
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top element off the top of the screen when we did not need to). Correct by sliding
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * everything back down.
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childCount Number of children
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooHigh(int childCount) {
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First see if the last item is visible. If it is not, it is OK for the
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // top of the list to be pushed up.
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lastPosition = mFirstPosition + childCount - 1;
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lastPosition == mItemCount - 1 && childCount > 0) {
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the last child ...
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View lastChild = getChildAt(childCount - 1);
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its bottom edge
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the bottom edge of the last view is from the bottom of the
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int bottomOffset = end - lastBottom;
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View firstChild = getChildAt(0);
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too high, and 2) Either there are more rows above the
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // first row or the first row is scrolled off the top of the drawable area
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bottomOffset > 0 && (mFirstPosition > 0 || firstTop < mListPadding.top))  {
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition == 0) {
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Don't pull the top too far down
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop);
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Move everything down
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(bottomOffset);
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition > 0) {
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fill the gap that was opened above mFirstPosition with more rows, if
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // possible
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fillUp(mFirstPosition - 1, firstChild.getTop() - mDividerHeight);
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Close up the remaining gap
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    adjustViewsUpOrDown();
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check if we have dragged the bottom of the list too low (we have pushed the
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bottom element off the bottom of the screen when we did not need to). Correct by sliding
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * everything back up.
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childCount Number of children
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooLow(int childCount) {
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First see if the first item is visible. If it is not, it is OK for the
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bottom of the list to be pushed down.
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition == 0 && childCount > 0) {
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the first child ...
13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View firstChild = getChildAt(0);
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its top edge
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is top of our drawable area
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int start = mListPadding.top;
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the top edge of the first view is from the top of the
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topOffset = firstTop - start;
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View lastChild = getChildAt(childCount - 1);
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastPosition = mFirstPosition + childCount - 1;
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too low, and 2) Either there are more rows below the
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // last row or the last row is scrolled off the bottom of the drawable area
13916198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy            if (topOffset > 0) {
13926198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                if (lastPosition < mItemCount - 1 || lastBottom > end)  {
13936198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    if (lastPosition == mItemCount - 1) {
13946198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Don't pull the bottom too far up
13956198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        topOffset = Math.min(topOffset, lastBottom - end);
13966198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    }
13976198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    // Move everything up
13986198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    offsetChildrenTopAndBottom(-topOffset);
13996198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    if (lastPosition < mItemCount - 1) {
14006198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Fill the gap that was opened below the last position with more rows, if
14016198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // possible
14026198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight);
14036198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Close up the remaining gap
14046198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        adjustViewsUpOrDown();
14056198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    }
14066198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                } else if (lastPosition == mItemCount - 1) {
14076198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    adjustViewsUpOrDown();
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void layoutChildren() {
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean blockLayoutRequests = mBlockLayoutRequests;
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!blockLayoutRequests) {
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBlockLayoutRequests = true;
14184df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        } else {
14194df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return;
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.layoutChildren();
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAdapter == null) {
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childrenTop = mListPadding.top;
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childrenBottom = mBottom - mTop - mListPadding.bottom;
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
1437ead0d4d8282b35a10bf8816cd99a62a8499d9031Romain Guy            int index = 0;
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int delta = 0;
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View sel;
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldSel = null;
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldFirst = null;
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View newSel = null;
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View focusLayoutRestoreView = null;
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Remember stuff we will need down below
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mNextSelectedPosition - mFirstPosition;
14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    newSel = getChildAt(index);
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previously selected view
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mSelectedPosition - mFirstPosition;
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    oldSel = getChildAt(index);
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previous first child
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldFirst = getChildAt(0);
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mNextSelectedPosition >= 0) {
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = mNextSelectedPosition - mSelectedPosition;
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Caution: newSel might be null
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newSel = getChildAt(index + delta);
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean dataChanged = mDataChanged;
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleDataChanged();
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Handle the empty set by removing all views that are visible
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // and calling it a day
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount == 0) {
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
1491b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy            } else if (mItemCount != mAdapter.getCount()) {
1492b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy                throw new IllegalStateException("The content of the adapter has changed but "
1493b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy                        + "ListView did not receive a notification. Make sure the content of "
1494b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy                        + "your adapter is not modified from a background thread, but only "
14953940f2df36fbe6a712c88655fc78244977ebd0abOwen Lin                        + "from the UI thread. [in ListView(" + getId() + ", " + getClass()
14963940f2df36fbe6a712c88655fc78244977ebd0abOwen Lin                        + ") with Adapter(" + mAdapter.getClass() + ")]");
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(mNextSelectedPosition);
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pull all children into the RecycleBin.
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // These views will be reused if possible
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstPosition = mFirstPosition;
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final RecycleBin recycleBin = mRecycler;
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // reset the focus restoration
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View focusLayoutRestoreDirectChild = null;
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Don't put header or footer views into the Recycler. Those are
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // already cached in mHeaderViews;
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < childCount; i++) {
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    recycleBin.addScrapView(getChildAt(i));
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (ViewDebug.TRACE_RECYCLER) {
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ViewDebug.trace(getChildAt(i),
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                recycleBin.fillActiveViews(childCount, firstPosition);
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // take focus back to us temporarily to avoid the eventual
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // call to clear focus when removing the focused child below
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // from messing things up when ViewRoot assigns focus back
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to someone else
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View focusedChild = getFocusedChild();
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focusedChild != null) {
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // TODO: in some cases focusedChild.getParent() == null
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we can remember the focused view to restore after relayout if the
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // data hasn't changed, or if the focused position is a header or footer
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) {
15354df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    focusLayoutRestoreDirectChild = focusedChild;
15364df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    // remember the specific view that had focus
15374df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    focusLayoutRestoreView = findFocus();
15384df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    if (focusLayoutRestoreView != null) {
15394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        // tell it we are going to mess with it
15404df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        focusLayoutRestoreView.onStartTemporaryDetach();
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requestFocus();
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Clear out old views
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            detachAllViewsFromParent();
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newSel != null) {
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom);
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillFromMiddle(childrenTop, childrenBottom);
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillSpecific(mSyncPosition, mSpecificTop);
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillUp(mItemCount - 1, childrenBottom);
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition = 0;
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillFromTop(childrenTop);
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (childCount == 0) {
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!mStackFromBottom) {
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int position = lookForSelectablePosition(0, true);
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        setSelectedPositionInt(position);
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillFromTop(childrenTop);
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int position = lookForSelectablePosition(mItemCount - 1, false);
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        setSelectedPositionInt(position);
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillUp(mItemCount - 1, childrenBottom);
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mSelectedPosition,
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                oldSel == null ? childrenTop : oldSel.getTop());
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (mFirstPosition < mItemCount) {
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mFirstPosition,
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                oldFirst == null ? childrenTop : oldFirst.getTop());
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(0, childrenTop);
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Flush any cached views that did not get reused above
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recycleBin.scrapActiveViews();
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel != null) {
16043616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                // the current selected item should get focus if items
16053616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                // are focusable
16063616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
16073616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
16083616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                            focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
16093616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    if (!focusWasTaken) {
16103616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        // selected item didn't take focus, fine, but still want
16113616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        // to make sure something else outside of the selected view
16123616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        // has focus
16133616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        final View focused = getFocusedChild();
16143616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        if (focused != null) {
16153616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                            focused.clearFocus();
16163616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        }
16173616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        positionSelector(sel);
16183616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    } else {
16193616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        sel.setSelected(false);
16203616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        mSelectorRect.setEmpty();
16213616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    }
16223616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                } else {
16233616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    positionSelector(sel);
16243616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                }
16253616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                mSelectedTop = sel.getTop();
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
16273616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
16283616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    View child = getChildAt(mMotionPosition - mFirstPosition);
1629b4c547a56caebb5900c132ec9d5ce953f89de14fRomain Guy                    if (child != null) positionSelector(child);
16303616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                } else {
16313616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    mSelectedTop = 0;
16323616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    mSelectorRect.setEmpty();
16333616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                }
16343616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy
16353616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                // even if there is not selected position, we may need to restore
16363616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                // focus (i.e. something focusable in touch mode)
16373616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                if (hasFocus() && focusLayoutRestoreView != null) {
16383616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    focusLayoutRestoreView.requestFocus();
16393616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                }
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // tell focus view we are done mucking with it, if it is still in
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // our view hierarchy.
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focusLayoutRestoreView != null
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && focusLayoutRestoreView.getWindowToken() != null) {
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                focusLayoutRestoreView.onFinishTemporaryDetach();
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_NORMAL;
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = false;
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNeedSync = false;
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(mSelectedPosition);
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateScrollIndicators();
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount > 0) {
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSelectionChanged();
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!blockLayoutRequests) {
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBlockLayoutRequests = false;
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child a direct child of this list.
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether child is a header or footer view.
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isDirectChildHeaderOrFooter(View child) {
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<FixedViewInfo> headers = mHeaderViewInfos;
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numHeaders = headers.size();
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numHeaders; i++) {
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child == headers.get(i).view) {
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<FixedViewInfo> footers = mFooterViewInfos;
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numFooters = footers.size();
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numFooters; i++) {
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child == footers.get(i).view) {
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Obtain the view and add it to our list of children. The view can be made
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * fresh, converted from an unused view, or used as is if it was in the
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * recycle bin.
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Logical position in the list
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param y Top or bottom edge of the view to add
16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param flow If flow is true, align top edge to y. If false, align bottom
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        edge to y.
17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenLeft Left edge where children should be positioned
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selected Is this position selected?
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return View that was added
17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected) {
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mDataChanged) {
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Try to use an exsiting view for this position
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child = mRecycler.getActiveView(position);
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child != null) {
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (ViewDebug.TRACE_RECYCLER) {
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ViewDebug.trace(child, ViewDebug.RecyclerTraceType.RECYCLE_FROM_ACTIVE_HEAP,
17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            position, getChildCount());
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Found it -- we're using an existing child
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This just needs to be positioned
17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setupChild(child, position, y, flow, childrenLeft, selected, true);
17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return child;
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make a new view for this position, or convert an unused view if possible
172721875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        child = obtainView(position, mIsScrap);
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This needs to be positioned and measured
173021875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return child;
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a view as a child and make sure it is measured (if necessary) and
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * positioned properly.
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The view to add
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The position of this child
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param y The y position relative to which this view will be positioned
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param flowDown If true, align top edge to y. If false, align bottom
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        edge to y.
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenLeft Left edge where children should be positioned
17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selected Is this position selected?
17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param recycled Has this view been pulled from the recycle bin? If so it
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        does not need to be remeasured.
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected, boolean recycled) {
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean isSelected = selected && shouldShowSelector();
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean updateChildSelected = isSelected != child.isSelected();
17533616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final int mode = mTouchMode;
17543616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL &&
17553616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                mMotionPosition == position;
17563616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final boolean updateChildPressed = isPressed != child.isPressed();
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Respect layout params that are already in the view. Otherwise make some up...
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // noinspection unchecked
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
1763980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy            p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ViewGroup.LayoutParams.WRAP_CONTENT, 0);
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p.viewType = mAdapter.getItemViewType(position);
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17680bf88594c43ced48d862d122e3e84967b3b63658Romain Guy        if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter &&
1769c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            attachViewToParent(child, flowDown ? -1 : 0, p);
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
17720bf88594c43ced48d862d122e3e84967b3b63658Romain Guy            p.forceAdd = false;
17734df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
17744df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                p.recycledHeaderFooter = true;
17754df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            addViewInLayout(child, flowDown ? -1 : 0, p, true);
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (updateChildSelected) {
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setSelected(isSelected);
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17833616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        if (updateChildPressed) {
17843616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy            child.setPressed(isPressed);
17853616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        }
17863616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child instanceof Checkable) {
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((Checkable) child).setChecked(mCheckStates.get(position));
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left + mListPadding.right, p.width);
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lpHeight = p.height;
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childHeightSpec;
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lpHeight > 0) {
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.measure(childWidthSpec, childHeightSpec);
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupLayoutState(child);
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int w = child.getMeasuredWidth();
18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int h = child.getMeasuredHeight();
18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childTop = flowDown ? y : y - h;
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childRight = childrenLeft + w;
18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childBottom = childTop + h;
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.layout(childrenLeft, childTop, childRight, childBottom);
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetLeftAndRight(childrenLeft - child.getLeft());
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetTopAndBottom(childTop - child.getTop());
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCachingStarted && !child.isDrawingCacheEnabled()) {
18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setDrawingCacheEnabled(true);
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean canAnimate() {
18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.canAnimate() && mItemCount > 0;
18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the currently selected item. If in touch mode, the item will not be selected
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but it will still be positioned appropriately. If the specified selection position
18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is less than 0, then the item at position 0 will be selected.
18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Index (starting at 0) of the data item to be selected.
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelection(int position) {
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelectionFromTop(position, 0);
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the selected item and positions the selection y pixels from the top edge
18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the ListView. (If in touch mode, the item will not be selected but it will
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * still be positioned appropriately.)
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Index (starting at 0) of the data item to be selected.
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param y The distance from the top edge of the ListView (plus padding) that the
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        item will be positioned.
18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelectionFromTop(int position, int y) {
18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter == null) {
18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isInTouchMode()) {
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            position = lookForSelectablePosition(position, true);
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position >= 0) {
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setNextSelectedPositionInt(position);
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResurrectToPosition = position;
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (position >= 0) {
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_SPECIFIC;
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSpecificTop = mListPadding.top + y;
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mNeedSync) {
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncPosition = position;
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncRowId = mAdapter.getItemId(position);
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Makes the item at the supplied position selected.
1881f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron     *
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position the position of the item to select
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setSelectionInt(int position) {
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setNextSelectedPositionInt(position);
1887f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        boolean awakeScrollbars = false;
1888f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
1889f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        final int selectedPosition = mSelectedPosition;
1890f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
1891f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (selectedPosition >= 0) {
1892f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            if (position == selectedPosition - 1) {
1893f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                awakeScrollbars = true;
1894f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            } else if (position == selectedPosition + 1) {
1895f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                awakeScrollbars = true;
1896f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            }
1897f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
1898f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layoutChildren();
1900f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
1901f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (awakeScrollbars) {
1902f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
1903f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Find a position that can be selected (i.e., is not a separator).
19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The starting position to look at.
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param lookDown Whether to look down for other positions.
19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The next selectable position starting at position and then searching either up or
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         down. Returns {@link #INVALID_POSITION} if nothing can be found.
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int lookForSelectablePosition(int position, boolean lookDown) {
19169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ListAdapter adapter = mAdapter;
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null || isInTouchMode()) {
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return INVALID_POSITION;
19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = adapter.getCount();
19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mAreAllItemsSelectable) {
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lookDown) {
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = Math.max(0, position);
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (position < count && !adapter.isEnabled(position)) {
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    position++;
19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = Math.min(position, count - 1);
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (position >= 0 && !adapter.isEnabled(position)) {
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    position--;
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position < 0 || position >= count) {
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return position;
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position < 0 || position >= count) {
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return position;
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
194775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov    @Override
194875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
194975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        boolean populated = super.dispatchPopulateAccessibilityEvent(event);
195075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
1951d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani        // If the item count is less than 15 then subtract disabled items from the count and
1952d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani        // position. Otherwise ignore disabled items.
195375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        if (!populated) {
195475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            int itemCount = 0;
195575986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            int currentItemIndex = getSelectedItemPosition();
195675986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
195775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            ListAdapter adapter = getAdapter();
195875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            if (adapter != null) {
1959d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                final int count = adapter.getCount();
1960d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                if (count < 15) {
1961d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                    for (int i = 0; i < count; i++) {
1962d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                        if (adapter.isEnabled(i)) {
1963d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                            itemCount++;
1964d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                        } else if (i <= currentItemIndex) {
1965d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                            currentItemIndex--;
1966d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                        }
196775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov                    }
1968d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                } else {
1969d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani                    itemCount = count;
197075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov                }
197175986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            }
197275986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
197375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            event.setItemCount(itemCount);
197475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov            event.setCurrentItemIndex(currentItemIndex);
197575986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        }
197675986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
197775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        return populated;
197875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov    }
197975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * setSelectionAfterHeaderView set the selection to be the first list item
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * after the header views.
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelectionAfterHeaderView() {
19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = mHeaderViewInfos.size();
19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNextSelectedPosition = 0;
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(count);
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNextSelectedPosition = count;
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_SET_SELECTION;
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
20019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Dispatch in the normal way
20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = super.dispatchKeyEvent(event);
20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!handled) {
20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If we didn't handle it...
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View focused = getFocusedChild();
20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focused != null && event.getAction() == KeyEvent.ACTION_DOWN) {
20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... and our focused child didn't handle it
20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... give it to ourselves so we can scroll if necessary
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = onKeyDown(event.getKeyCode(), event);
20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, repeatCount, event);
20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean commonKey(int keyCode, int count, KeyEvent event) {
20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter == null) {
20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDataChanged) {
20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layoutChildren();
20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
20419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int action = event.getAction();
20429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action != KeyEvent.ACTION_UP) {
20449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition < 0) {
20459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (keyCode) {
20469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_UP:
20479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_DOWN:
20489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_DPAD_CENTER:
20499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_ENTER:
20509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.KEYCODE_SPACE:
20519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (resurrectSelection()) {
20529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return true;
20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (keyCode) {
20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_UP:
20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!event.isAltPressed()) {
20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    while (count > 0) {
20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        handled = arrowScroll(FOCUS_UP);
20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        count--;
20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = fullScroll(FOCUS_UP);
20659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
20679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_DOWN:
20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!event.isAltPressed()) {
20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    while (count > 0) {
20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        handled = arrowScroll(FOCUS_DOWN);
20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        count--;
20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
20759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = fullScroll(FOCUS_DOWN);
20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_LEFT:
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = handleHorizontalFocusWithinListItem(View.FOCUS_LEFT);
20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_RIGHT:
20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = handleHorizontalFocusWithinListItem(View.FOCUS_RIGHT);
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_CENTER:
20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_ENTER:
20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mItemCount > 0 && event.getRepeatCount() == 0) {
20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    keyPressed();
20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = true;
20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_SPACE:
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mPopup == null || !mPopup.isShowing()) {
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!event.isShiftPressed()) {
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pageScroll(FOCUS_DOWN);
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pageScroll(FOCUS_UP);
21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = true;
21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!handled) {
21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled = sendToTextFilter(keyCode, count, event);
21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (handled) {
21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (action) {
21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.ACTION_DOWN:
21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return super.onKeyDown(keyCode, event);
21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.ACTION_UP:
21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return super.onKeyUp(keyCode, event);
21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case KeyEvent.ACTION_MULTIPLE:
21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return super.onKeyMultiple(keyCode, count, event);
21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default: // shouldn't happen
21259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
21269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls up or down by the number of items currently present on screen.
21329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
21349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
21359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean pageScroll(int direction) {
21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int nextPage = -1;
21389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean down = false;
21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1);
21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1);
21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            down = true;
21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextPage >= 0) {
21489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position = lookForSelectablePosition(nextPage, down);
21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position >= 0) {
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLayoutMode = LAYOUT_SPECIFIC;
21519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSpecificTop = mPaddingTop + getVerticalFadingEdgeLength();
21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (down && position > mItemCount - getChildCount()) {
21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_BOTTOM;
21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!down && position < getChildCount()) {
21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_TOP;
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelectionInt(position);
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
2163f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                if (!awakenScrollBars()) {
2164f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                    invalidate();
2165f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                }
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Go to the last or first item if possible (not worrying about panning across or navigating
21769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * within the internal focus of the currently selected item.)
21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean fullScroll(int direction) {
21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean moved = false;
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition != 0) {
21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int position = lookForSelectablePosition(0, true);
21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position >= 0) {
21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_TOP;
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(position);
21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    invokeOnItemScrollListener();
21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                moved = true;
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition < mItemCount - 1) {
21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int position = lookForSelectablePosition(mItemCount - 1, true);
21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position >= 0) {
21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_BOTTOM;
21999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(position);
22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    invokeOnItemScrollListener();
22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                moved = true;
22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2206f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (moved && !awakenScrollBars()) {
2207f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return moved;
22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * To avoid horizontal focus searches changing the selected item, we
22169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * manually focus search within the selected item (as applicable), and
22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * prevent focus from jumping to something within another item.
22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction one of {View.FOCUS_LEFT, View.FOCUS_RIGHT}
22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether this consumes the key event.
22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean handleHorizontalFocusWithinListItem(int direction) {
22229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT)  {
2223304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy            throw new IllegalArgumentException("direction must be one of"
2224304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                    + " {View.FOCUS_LEFT, View.FOCUS_RIGHT}");
22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemsCanFocus && numChildren > 0 && mSelectedPosition != INVALID_POSITION) {
22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View selectedView = getSelectedView();
2230304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy            if (selectedView != null && selectedView.hasFocus() &&
2231304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                    selectedView instanceof ViewGroup) {
2232304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy
22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View currentFocus = selectedView.findFocus();
22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View nextFocus = FocusFinder.getInstance().findNextFocus(
2235304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                        (ViewGroup) selectedView, currentFocus, direction);
22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (nextFocus != null) {
22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // do the math to get interesting rect in next focus' coordinates
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    currentFocus.getFocusedRect(mTempRect);
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    offsetDescendantRectToMyCoords(currentFocus, mTempRect);
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    offsetRectIntoDescendantCoords(nextFocus, mTempRect);
22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (nextFocus.requestFocus(direction, mTempRect)) {
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return true;
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are blocking the key from being handled (by returning true)
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // if the global result is going to be some other view within this
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // list.  this is to acheive the overall goal of having
22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // horizontal d-pad navigation remain in the current item.
2249304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                final View globalNextFocus = FocusFinder.getInstance().findNextFocus(
2250304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                        (ViewGroup) getRootView(), currentFocus, direction);
22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (globalNextFocus != null) {
22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return isViewAncestorOf(globalNextFocus, this);
22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls to the next or previous item if possible.
22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean arrowScroll(int direction) {
22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInLayout = true;
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean handled = arrowScrollImpl(direction);
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (handled) {
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return handled;
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInLayout = false;
22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Handle an arrow scroll going up or down.  Take into account whether items are selectable,
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * whether there are focusable items etc.
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction Either {@link android.view.View#FOCUS_UP} or {@link android.view.View#FOCUS_DOWN}.
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether any scrolling, selection or focus change occured.
22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean arrowScrollImpl(int direction) {
22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (getChildCount() <= 0) {
22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = getSelectedView();
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int amountToScroll = amountToScroll(direction, nextSelectedPosition);
22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if we are moving focus, we may OVERRIDE the default behavior
22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrowScrollFocusResult focusResult = mItemsCanFocus ? arrowScrollFocused(direction) : null;
22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (focusResult != null) {
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextSelectedPosition = focusResult.getSelectedPosition();
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            amountToScroll = focusResult.getAmountToScroll();
23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean needToRedraw = focusResult != null;
23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextSelectedPosition != INVALID_POSITION) {
23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handleNewSelectionChange(selectedView, direction, nextSelectedPosition, focusResult != null);
23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(nextSelectedPosition);
23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(nextSelectedPosition);
23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selectedView = getSelectedView();
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemsCanFocus && focusResult == null) {
23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // there was no new view found to take focus, make sure we
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // don't leave focus with the old selection
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View focused = getFocusedChild();
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (focused != null) {
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    focused.clearFocus();
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            needToRedraw = true;
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (amountToScroll > 0) {
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListItemsBy((direction == View.FOCUS_UP) ? amountToScroll : -amountToScroll);
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            needToRedraw = true;
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if we didn't find a new focusable, make sure any existing focused
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // item that was panned off screen gives up focus.
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemsCanFocus && (focusResult == null)
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && selectedView != null && selectedView.hasFocus()) {
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View focused = selectedView.findFocus();
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (distanceToView(focused) > 0) {
23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                focused.clearFocus();
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if  the current selection is panned off, we need to remove the selection
23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextSelectedPosition == INVALID_POSITION && selectedView != null
23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && !isViewAncestorOf(selectedView, this)) {
23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selectedView = null;
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            hideSelector();
23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // but we don't want to set the ressurect position (that would make subsequent
23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // unhandled key events bring back the item we just scrolled off!)
23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResurrectToPosition = INVALID_POSITION;
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToRedraw) {
23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selectedView != null) {
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                positionSelector(selectedView);
23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSelectedTop = selectedView.getTop();
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2352f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            if (!awakenScrollBars()) {
2353f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                invalidate();
2354f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            }
23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
23569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
23579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
23609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
23639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When selection changes, it is possible that the previously selected or the
23649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * next selected item will change its size.  If so, we need to offset some folks,
23659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and re-layout the items as appropriate.
23669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
23679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedView The currently selected view (before changing selection).
23689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   should be <code>null</code> if there was no previous selection.
23699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction Either {@link android.view.View#FOCUS_UP} or
23709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
23719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newSelectedPosition The position of the next selection.
23729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocusAssigned whether new focus was assigned.  This matters because
23739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        when something has focus, we don't want to show selection (ugh).
23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleNewSelectionChange(View selectedView, int direction, int newSelectedPosition,
23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean newFocusAssigned) {
23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newSelectedPosition == INVALID_POSITION) {
23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("newSelectedPosition needs to be valid");
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // whether or not we are moving down or up, we want to preserve the
23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // top of whatever view is on top:
23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // - moving down: the view that had selection
23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // - moving up: the view that is getting selection
23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View topView;
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View bottomView;
23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topViewIndex, bottomViewIndex;
23889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean topSelected = false;
23899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedIndex = mSelectedPosition - mFirstPosition;
23909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int nextSelectedIndex = newSelectedPosition - mFirstPosition;
23919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_UP) {
23929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topViewIndex = nextSelectedIndex;
23939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomViewIndex = selectedIndex;
23949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView = getChildAt(topViewIndex);
23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView = selectedView;
23969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topSelected = true;
23979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
23989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topViewIndex = selectedIndex;
23999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomViewIndex = nextSelectedIndex;
24009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView = selectedView;
24019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView = getChildAt(bottomViewIndex);
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
24059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // start with top view: is it changing size?
24079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (topView != null) {
24089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView.setSelected(!newFocusAssigned && topSelected);
24099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureAndAdjustDown(topView, topViewIndex, numChildren);
24109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // is the bottom view changing size?
24139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (bottomView != null) {
24149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView.setSelected(!newFocusAssigned && !topSelected);
24159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureAndAdjustDown(bottomView, bottomViewIndex, numChildren);
24169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Re-measure a child, and if its height changes, lay it out preserving its
24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top, and adjust the children below it appropriately.
24229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child
24239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childIndex The view group index of the child.
24249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numChildren The number of children in the view group.
24259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void measureAndAdjustDown(View child, int childIndex, int numChildren) {
24279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int oldHeight = child.getHeight();
24289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        measureItem(child);
24299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (child.getMeasuredHeight() != oldHeight) {
24309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // lay out the view, preserving its top
24319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            relayoutMeasuredItem(child);
24329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // adjust views below appropriately
24349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int heightDelta = child.getMeasuredHeight() - oldHeight;
24359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = childIndex + 1; i < numChildren; i++) {
24369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getChildAt(i).offsetTopAndBottom(heightDelta);
24379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Measure a particular list child.
24439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: unify with setUpChild.
24449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child.
24459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void measureItem(View child) {
24479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ViewGroup.LayoutParams p = child.getLayoutParams();
24489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
24499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p = new ViewGroup.LayoutParams(
2450980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy                    ViewGroup.LayoutParams.MATCH_PARENT,
24519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ViewGroup.LayoutParams.WRAP_CONTENT);
24529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
24559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left + mListPadding.right, p.width);
24569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lpHeight = p.height;
24579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeightSpec;
24589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lpHeight > 0) {
24599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
24609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
24619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
24629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.measure(childWidthSpec, childHeightSpec);
24649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Layout a child that has been measured, preserving its top position.
24689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: unify with setUpChild.
24699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child.
24709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void relayoutMeasuredItem(View child) {
24729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int w = child.getMeasuredWidth();
24739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int h = child.getMeasuredHeight();
24749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childLeft = mListPadding.left;
24759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childRight = childLeft + w;
24769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childTop = child.getTop();
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childBottom = childTop + h;
24789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.layout(childLeft, childTop, childRight, childBottom);
24799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to preview next items when arrow srolling.
24839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getArrowScrollPreviewLength() {
24859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Math.max(MIN_SCROLL_PREVIEW_PIXELS, getVerticalFadingEdgeLength());
24869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine how much we need to scroll in order to get the next selected view
24909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * visible, with a fading edge showing below as applicable.  The amount is
24919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * capped at {@link #getMaxScrollAmount()} .
24929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
24939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
24949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextSelectedPosition The position of the next selection, or
24969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link #INVALID_POSITION} if there is no next selectable position
24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to scroll. Note: this is always positive!  Direction
24989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         needs to be taken into account when actually scrolling.
24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int amountToScroll(int direction, int nextSelectedPosition) {
25019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = getHeight() - mListPadding.bottom;
25029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mListPadding.top;
25039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
25059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_DOWN) {
25079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int indexToMakeVisible = numChildren - 1;
25089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION) {
25099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
25109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
25139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int goalBottom = listBottom;
25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (positionToMakeVisible < mItemCount - 1) {
25179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goalBottom -= getArrowScrollPreviewLength();
25189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (viewToMakeVisible.getBottom() <= goalBottom) {
25219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item is fully visible.
25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION
25269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && (goalBottom - viewToMakeVisible.getTop()) >= getMaxScrollAmount()) {
25279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item already has enough of it visible, changing selection is good enough
25289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
25299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amountToScroll = (viewToMakeVisible.getBottom() - goalBottom);
25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mFirstPosition + numChildren) == mItemCount) {
25349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // last is last in list -> make sure we don't scroll past it
25359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int max = getChildAt(numChildren - 1).getBottom() - listBottom;
25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = Math.min(amountToScroll, max);
25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Math.min(amountToScroll, getMaxScrollAmount());
25409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
25419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int indexToMakeVisible = 0;
25429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION) {
25439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
25449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int goalTop = listTop;
25489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (positionToMakeVisible > 0) {
25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goalTop += getArrowScrollPreviewLength();
25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (viewToMakeVisible.getTop() >= goalTop) {
25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item is fully visible.
25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION &&
25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (viewToMakeVisible.getBottom() - goalTop) >= getMaxScrollAmount()) {
25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item already has enough of it visible, changing selection is good enough
25599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
25609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amountToScroll = (goalTop - viewToMakeVisible.getTop());
25639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mFirstPosition == 0) {
25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // first is first in list -> make sure we don't scroll past it
25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int max = listTop - getChildAt(0).getTop();
25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = Math.min(amountToScroll,  max);
25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Math.min(amountToScroll, getMaxScrollAmount());
25699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Holds results of focus aware arrow scrolling.
25749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private class ArrowScrollFocusResult {
25769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mSelectedPosition;
25779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mAmountToScroll;
25789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
25809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * How {@link android.widget.ListView#arrowScrollFocused} returns its values.
25819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
25829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void populate(int selectedPosition, int amountToScroll) {
25839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSelectedPosition = selectedPosition;
25849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAmountToScroll = amountToScroll;
25859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getSelectedPosition() {
25889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSelectedPosition;
25899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getAmountToScroll() {
25929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAmountToScroll;
25939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
25989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The position of the next selectable position of the views that
26009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         are currently visible, taking into account the fact that there might
26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         be no selection.  Returns {@link #INVALID_POSITION} if there is no
26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         selectable view on screen in the given direction.
26039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
26049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int lookForSelectablePositionOnScreen(int direction) {
26059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int firstPosition = mFirstPosition;
26069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_DOWN) {
26079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int startPos = (mSelectedPosition != INVALID_POSITION) ?
26089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSelectedPosition + 1 :
26099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    firstPosition;
26109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos >= mAdapter.getCount()) {
26119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
26129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos < firstPosition) {
26149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startPos = firstPosition;
26159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastVisiblePos = getLastVisiblePosition();
26189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ListAdapter adapter = getAdapter();
26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int pos = startPos; pos <= lastVisiblePos; pos++) {
26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (adapter.isEnabled(pos)
26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return pos;
26239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
26249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int last = firstPosition + getChildCount() - 1;
26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int startPos = (mSelectedPosition != INVALID_POSITION) ?
26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSelectedPosition - 1 :
26299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    firstPosition + getChildCount() - 1;
26309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos < 0) {
26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos > last) {
26349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startPos = last;
26359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ListAdapter adapter = getAdapter();
26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int pos = startPos; pos >= firstPosition; pos--) {
26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (adapter.isEnabled(pos)
26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
26419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return pos;
26429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
26499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Do an arrow scroll based on focus searching.  If a new view is
26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * given focus, return the selection delta and amount to scroll via
26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * an {@link ArrowScrollFocusResult}, otherwise, return null.
26529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
26549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result if focus has changed, or <code>null</code>.
26569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
26579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrowScrollFocusResult arrowScrollFocused(final int direction) {
26589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View selectedView = getSelectedView();
26599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View newFocus;
26609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedView != null && selectedView.hasFocus()) {
26619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldFocus = selectedView.findFocus();
26629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction);
26639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
26649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == View.FOCUS_DOWN) {
26659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final boolean topFadingEdgeShowing = (mFirstPosition > 0);
26669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int listTop = mListPadding.top +
26679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (topFadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
26689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int ySearchPoint =
26699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (selectedView != null && selectedView.getTop() > listTop) ?
26709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                selectedView.getTop() :
26719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                listTop;
26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTempRect.set(0, ySearchPoint, 0, ySearchPoint);
26739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
26749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final boolean bottomFadingEdgeShowing =
26759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (mFirstPosition + getChildCount() - 1) < mItemCount;
26769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int listBottom = getHeight() - mListPadding.bottom -
26779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (bottomFadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
26789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int ySearchPoint =
26799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (selectedView != null && selectedView.getBottom() < listBottom) ?
26809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                selectedView.getBottom() :
26819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                listBottom;
26829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTempRect.set(0, ySearchPoint, 0, ySearchPoint);
26839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newFocus = FocusFinder.getInstance().findNextFocusFromRect(this, mTempRect, direction);
26859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newFocus != null) {
26889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionOfNewFocus = positionOfNewFocus(newFocus);
26899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if the focus change is in a different new position, make sure
26919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we aren't jumping over another selectable position
26929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition != INVALID_POSITION && positionOfNewFocus != mSelectedPosition) {
26939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int selectablePosition = lookForSelectablePositionOnScreen(direction);
26949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (selectablePosition != INVALID_POSITION &&
26959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((direction == View.FOCUS_DOWN && selectablePosition < positionOfNewFocus) ||
26969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (direction == View.FOCUS_UP && selectablePosition > positionOfNewFocus))) {
26979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return null;
26989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
26999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int focusScroll = amountToScrollToNewFocus(direction, newFocus, positionOfNewFocus);
27029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int maxScrollAmount = getMaxScrollAmount();
27049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focusScroll < maxScrollAmount) {
27059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // not moving too far, safe to give next view focus
27069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newFocus.requestFocus(direction);
27079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArrowScrollFocusResult.populate(positionOfNewFocus, focusScroll);
27089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mArrowScrollFocusResult;
27099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (distanceToView(newFocus) < maxScrollAmount){
27109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Case to consider:
27119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // too far to get entire next focusable on screen, but by going
27129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // max scroll amount, we are getting it at least partially in view,
27139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // so give it focus and scroll the max ammount.
27149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newFocus.requestFocus(direction);
27159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArrowScrollFocusResult.populate(positionOfNewFocus, maxScrollAmount);
27169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mArrowScrollFocusResult;
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocus The view that would have focus.
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the position that contains newFocus
27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int positionOfNewFocus(View newFocus) {
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numChildren; i++) {
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View child = getChildAt(i);
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isViewAncestorOf(newFocus, child)) {
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mFirstPosition + i;
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw new IllegalArgumentException("newFocus is not a child of any of the"
27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + " children of the list!");
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return true if child is an ancestor of parent, (or equal to the parent).
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isViewAncestorOf(View child, View parent) {
27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (child == parent) {
27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ViewParent theParent = child.getParent();
27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (theParent instanceof ViewGroup) && isViewAncestorOf((View) theParent, parent);
27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine how much we need to scroll in order to get newFocus in view.
27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
27539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
27549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocus The view that would take focus.
27559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param positionOfNewFocus The position of the list item containing newFocus
27569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to scroll.  Note: this is always positive!  Direction
27579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   needs to be taken into account when actually scrolling.
27589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int amountToScrollToNewFocus(int direction, View newFocus, int positionOfNewFocus) {
27609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int amountToScroll = 0;
27619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        newFocus.getDrawingRect(mTempRect);
27629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetDescendantRectToMyCoords(newFocus, mTempRect);
27639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_UP) {
27649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTempRect.top < mListPadding.top) {
27659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = mListPadding.top - mTempRect.top;
27669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (positionOfNewFocus > 0) {
27679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    amountToScroll += getArrowScrollPreviewLength();
27689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
27719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int listBottom = getHeight() - mListPadding.bottom;
27729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTempRect.bottom > listBottom) {
27739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = mTempRect.bottom - listBottom;
27749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (positionOfNewFocus < mItemCount - 1) {
27759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    amountToScroll += getArrowScrollPreviewLength();
27769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return amountToScroll;
27809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine the distance to the nearest edge of a view in a particular
2784fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * direction.
2785fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *
27869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param descendant A descendant of this list.
27879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The distance, or 0 if the nearest edge is already on screen.
27889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int distanceToView(View descendant) {
27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int distance = 0;
27919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        descendant.getDrawingRect(mTempRect);
27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetDescendantRectToMyCoords(descendant, mTempRect);
27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = mBottom - mTop - mListPadding.bottom;
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTempRect.bottom < mListPadding.top) {
27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            distance = mListPadding.top - mTempRect.bottom;
27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mTempRect.top > listBottom) {
27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            distance = mTempRect.top - listBottom;
27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return distance;
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scroll the children by amount, adding a view at the end and removing
28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * views that fall off as necessary.
28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param amount The amount (positive or negative) to scroll.
28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void scrollListItemsBy(int amount) {
28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetChildrenTopAndBottom(amount);
28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = getHeight() - mListPadding.bottom;
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mListPadding.top;
2814c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final AbsListView.RecycleBin recycleBin = mRecycler;
28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (amount < 0) {
28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // shifted items up
28189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may need to pan views into the bottom space
28209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numChildren = getChildCount();
28219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View last = getChildAt(numChildren - 1);
28229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (last.getBottom() < listBottom) {
28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int lastVisiblePosition = mFirstPosition + numChildren - 1;
28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lastVisiblePosition < mItemCount - 1) {
28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    last = addViewBelow(last, lastVisiblePosition);
28269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    numChildren++;
28279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
28289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
28299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
28309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may have brought in the last child of the list that is skinnier
28339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // than the fading edge, thereby leaving space at the end.  need
28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to shift back
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (last.getBottom() < listBottom) {
28369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(listBottom - last.getBottom());
28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // top views may be panned off screen
28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View first = getChildAt(0);
28419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (first.getBottom() < listTop) {
2842c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();
2843c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
28442d51bff2b6597804307d8883a071ff18adc2644aRomain Guy                    detachViewFromParent(first);
2845c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    recycleBin.addScrapView(first);
2846c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else {
28472d51bff2b6597804307d8883a071ff18adc2644aRomain Guy                    removeViewInLayout(first);
2848c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
28499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                first = getChildAt(0);
28509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition++;
28519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
28539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // shifted items down
28549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View first = getChildAt(0);
28559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may need to pan views into top
28579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((first.getTop() > listTop) && (mFirstPosition > 0)) {
28589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                first = addViewAbove(first, mFirstPosition);
28599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition--;
28609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may have brought the very first child of the list in too far and
28639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to shift it back
28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (first.getTop() > listTop) {
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(listTop - first.getTop());
28669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastIndex = getChildCount() - 1;
28699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View last = getChildAt(lastIndex);
28709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // bottom view may be panned off screen
28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (last.getTop() > listBottom) {
2873c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();
2874c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
28752d51bff2b6597804307d8883a071ff18adc2644aRomain Guy                    detachViewFromParent(last);
2876c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    recycleBin.addScrapView(last);
2877c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else {
28782d51bff2b6597804307d8883a071ff18adc2644aRomain Guy                    removeViewInLayout(last);
2879c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
28809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                last = getChildAt(--lastIndex);
28819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View addViewAbove(View theView, int position) {
28869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int abovePosition = position - 1;
288721875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        View view = obtainView(abovePosition, mIsScrap);
28889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int edgeOfNewChild = theView.getTop() - mDividerHeight;
288921875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left,
289021875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy                false, mIsScrap[0]);
28919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view;
28929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View addViewBelow(View theView, int position) {
28959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int belowPosition = position + 1;
289621875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        View view = obtainView(belowPosition, mIsScrap);
28979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int edgeOfNewChild = theView.getBottom() + mDividerHeight;
289821875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left,
289921875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy                false, mIsScrap[0]);
29009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view;
29019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Indicates that the views created by the ListAdapter can contain focusable
29059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * items.
29069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
29079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param itemsCanFocus true if items can get focus, false otherwise
29089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setItemsCanFocus(boolean itemsCanFocus) {
29109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemsCanFocus = itemsCanFocus;
29119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!itemsCanFocus) {
29129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
29139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the views created by the ListAdapter can contain focusable
29189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * items.
29199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getItemsCanFocus() {
29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItemsCanFocus;
29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29242d6afea6813be3081138874cf879ac8b0860e4efRomain Guy    /**
29252d6afea6813be3081138874cf879ac8b0860e4efRomain Guy     * @hide Pending API council approval.
29262d6afea6813be3081138874cf879ac8b0860e4efRomain Guy     */
29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
292824443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    public boolean isOpaque() {
29298f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        return (mCachingStarted && mIsCacheColorOpaque && mDividerIsOpaque &&
29308f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                hasOpaqueScrollbars()) || super.isOpaque();
293124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    }
293224443ea3992e372e47daa50266b0f2ec38cac388Romain Guy
293324443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    @Override
293424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    public void setCacheColorHint(int color) {
29358f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        final boolean opaque = (color >>> 24) == 0xFF;
29368f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        mIsCacheColorOpaque = opaque;
29378f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        if (opaque) {
2938a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            if (mDividerPaint == null) {
2939a02903fbee6725563da4472bd120f844e9d5518cRomain Guy                mDividerPaint = new Paint();
2940a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            }
29418f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy            mDividerPaint.setColor(color);
29428f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        }
294324443ea3992e372e47daa50266b0f2ec38cac388Romain Guy        super.setCacheColorHint(color);
294424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    }
29459d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell
294624443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    @Override
29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchDraw(Canvas canvas) {
29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Draw the dividers
29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
2950bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell        final boolean drawDividers = dividerHeight > 0 && mDivider != null;
29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29529d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell        if (drawDividers) {
29539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Only modify the top and bottom in the loop, we set the left and right here
29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Rect bounds = mTempRect;
29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.left = mPaddingLeft;
29569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.right = mRight - mLeft - mPaddingRight;
29579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int count = getChildCount();
29599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int headerCount = mHeaderViewInfos.size();
2960bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell            final int itemCount = mItemCount;
2961bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell            final int footerLimit = itemCount - mFooterViewInfos.size() - 1;
29629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean headerDividers = mHeaderDividersEnabled;
29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean footerDividers = mFooterDividersEnabled;
29649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int first = mFirstPosition;
29652bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy            final boolean areAllItemsSelectable = mAreAllItemsSelectable;
29662bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy            final ListAdapter adapter = mAdapter;
2967e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // If the list is opaque *and* the background is not, we want to
2968e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // fill a rect where the dividers would be for non-selectable items
2969e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // If the list is opaque and the background is also opaque, we don't
2970e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // need to draw anything since the background will do it for us
2971bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell            final boolean fillForMissingDividers = drawDividers && isOpaque() && !super.isOpaque();
2972e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy
2973e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) {
2974a02903fbee6725563da4472bd120f844e9d5518cRomain Guy                mDividerPaint = new Paint();
2975e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy                mDividerPaint.setColor(getCacheColorHint());
2976a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            }
29778f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy            final Paint paint = mDividerPaint;
29789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell            final int listBottom = mBottom - mTop - mListPadding.bottom + mScrollY;
29809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
2981bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                int bottom = 0;
29820b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell
2983bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                final int scrollY = mScrollY;
29849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < count; i++) {
29859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if ((headerDividers || first + i >= headerCount) &&
29869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (footerDividers || first + i < footerLimit)) {
29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        View child = getChildAt(i);
29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        bottom = child.getBottom();
29892bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy                        // Don't draw dividers next to items that are not enabled
29909d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                        if (drawDividers) {
29918f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                            if ((areAllItemsSelectable ||
29928f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
29938f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                            adapter.isEnabled(first + i + 1))))) {
29948f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = bottom;
29958f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = bottom + dividerHeight;
29968f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                drawDivider(canvas, bounds, i);
2997e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy                            } else if (fillForMissingDividers) {
29988f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = bottom;
29998f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = bottom + dividerHeight;
30008f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                canvas.drawRect(bounds, paint);
30018f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                            }
30029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
30039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
30049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
30059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
30069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int top;
30079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int listTop = mListPadding.top;
30089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3009bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                final int scrollY = mScrollY;
3010bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
30119d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                for (int i = 0; i < count; i++) {
30129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if ((headerDividers || first + i >= headerCount) &&
30139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (footerDividers || first + i < footerLimit)) {
30149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        View child = getChildAt(i);
30159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        top = child.getTop();
30162bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy                        // Don't draw dividers next to items that are not enabled
3017bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                        if (drawDividers && top > listTop) {
30188f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                            if ((areAllItemsSelectable ||
30198f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
30208f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                            adapter.isEnabled(first + i + 1))))) {
30218f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = top - dividerHeight;
30228f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = top;
30238f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                // Give the method the child ABOVE the divider, so we
30248f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                // subtract one from our child
30258f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                // position. Give -1 when there is no child above the
30268f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                // divider.
30278f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                drawDivider(canvas, bounds, i - 1);
3028e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy                            } else if (fillForMissingDividers) {
30298f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = top - dividerHeight;
30308f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = top;
30318f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                canvas.drawRect(bounds, paint);
30328f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                            }
30339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
30349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
30359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3036bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
30379d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                if (count > 0 && scrollY > 0 && drawDividers) {
30389d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                    bounds.top = listBottom;
30399d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                    bounds.bottom = listBottom + dividerHeight;
30409d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell                    drawDivider(canvas, bounds, -1);
3041bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                }
30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Draw the indicators (these should be drawn above the dividers) and children
30469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.dispatchDraw(canvas);
30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draws a divider for the given child in the given bounds.
30519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
30529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The canvas to draw to.
30539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bounds The bounds of the divider.
30549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childIndex The index of child (of the View) above the divider.
30559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            This will be -1 if there is no child above the divider to be
30569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            drawn.
30579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void drawDivider(Canvas canvas, Rect bounds, int childIndex) {
30599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This widget draws the same divider for all children
30609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Drawable divider = mDivider;
30619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean clipDivider = mClipDivider;
30629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!clipDivider) {
30649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            divider.setBounds(bounds);
30659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
30669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            canvas.save();
30679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            canvas.clipRect(bounds);
30689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        divider.draw(canvas);
30719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (clipDivider) {
30739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            canvas.restore();
30749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the drawable that will be drawn between each item in the list.
30799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
30809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the current drawable drawn between list elements
30819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getDivider() {
30839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDivider;
30849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the drawable that will be drawn between each item in the list. If the drawable does
30889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not have an intrinsic height, you should also call {@link #setDividerHeight(int)}
30899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
30909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param divider The drawable to use.
30919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDivider(Drawable divider) {
30939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (divider != null) {
30949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDividerHeight = divider.getIntrinsicHeight();
30959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClipDivider = divider instanceof ColorDrawable;
30969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
30979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDividerHeight = 0;
30989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClipDivider = false;
30999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDivider = divider;
310124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy        mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE;
31029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayoutIfNecessary();
31039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Returns the height of the divider that will be drawn between each item in the list.
31079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDividerHeight() {
31099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDividerHeight;
31109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the height of the divider that will be drawn between each item in the list. Calling
31149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
31159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param height The new height of the divider in pixels.
31179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDividerHeight(int height) {
31199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDividerHeight = height;
31209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayoutIfNecessary();
31219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables the drawing of the divider for header views.
31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param headerDividersEnabled True to draw the headers, false otherwise.
31279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setFooterDividersEnabled(boolean)
31299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #addHeaderView(android.view.View)
31309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setHeaderDividersEnabled(boolean headerDividersEnabled) {
31329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderDividersEnabled = headerDividersEnabled;
31339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
31349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables the drawing of the divider for footer views.
31389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param footerDividersEnabled True to draw the footers, false otherwise.
31409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setHeaderDividersEnabled(boolean)
31429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #addFooterView(android.view.View)
31439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFooterDividersEnabled(boolean footerDividersEnabled) {
31459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterDividersEnabled = footerDividersEnabled;
31469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
31479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3148bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
31499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
31509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
31519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
31529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int closetChildIndex = -1;
31549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (gainFocus && previouslyFocusedRect != null) {
31559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previouslyFocusedRect.offset(mScrollX, mScrollY);
31569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3157c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell            final ListAdapter adapter = mAdapter;
3158d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            // Don't cache the result of getChildCount or mFirstPosition here,
3159d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            // it could change in layoutChildren.
3160d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            if (adapter.getCount() < getChildCount() + mFirstPosition) {
3161c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell                mLayoutMode = LAYOUT_NORMAL;
3162c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell                layoutChildren();
3163c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell            }
3164c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell
31659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // figure out which item should be selected based on previously
31669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // focused rect
31679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Rect otherRect = mTempRect;
31689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int minDistance = Integer.MAX_VALUE;
31699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childCount = getChildCount();
3170d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            final int firstPosition = mFirstPosition;
31719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < childCount; i++) {
31739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // only consider selectable views
31749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!adapter.isEnabled(firstPosition + i)) {
31759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
31769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                View other = getChildAt(i);
31799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                other.getDrawingRect(otherRect);
31809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetDescendantRectToMyCoords(other, otherRect);
31819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int distance = getDistance(previouslyFocusedRect, otherRect, direction);
31829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (distance < minDistance) {
31849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    minDistance = distance;
31859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    closetChildIndex = i;
31869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (closetChildIndex >= 0) {
31919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(closetChildIndex + mFirstPosition);
31929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
31939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
31949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (non-Javadoc)
32009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
32019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Children specified in XML are assumed to be header views. After we have
32029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parsed them move them out of the children list and into mHeaderViews.
32039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
32059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFinishInflate() {
32069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onFinishInflate();
32079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = getChildCount();
32099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
32109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; ++i) {
32119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                addHeaderView(getChildAt(i));
32129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeAllViews();
32149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
32189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.View#findViewById(int)
32199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * First look in our children, then in any header and footer views that may be scrolled off.
32209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
32229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected View findViewTraversal(int id) {
32239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
32249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v = super.findViewTraversal(id);
32259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (v == null) {
32269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
32279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
32289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
32299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewInHeadersOrFooters(mFooterViewInfos, id);
32319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
32329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
32339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
32369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
32399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
32409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Look in the passed in list of headers or footers for the view.
32419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
32439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where != null) {
32449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int len = where.size();
32459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View v;
32469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < len; i++) {
32489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                v = where.get(i).view;
32499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!v.isRootNamespace()) {
32519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v = v.findViewById(id);
32529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (v != null) {
32549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return v;
32559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
32569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
32579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
32609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
32639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.View#findViewWithTag(String)
32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * First look in our children, then in any header and footer views that may be scrolled off.
32659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
32679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected View findViewWithTagTraversal(Object tag) {
32689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
32699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v = super.findViewWithTagTraversal(tag);
32709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (v == null) {
32719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewTagInHeadersOrFooters(mHeaderViewInfos, tag);
32729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
32739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
32749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewTagInHeadersOrFooters(mFooterViewInfos, tag);
32779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
32789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
32799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
32829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
32859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
32869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Look in the passed in list of headers or footers for the view with the tag.
32879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    View findViewTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
32899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where != null) {
32909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int len = where.size();
32919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View v;
32929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < len; i++) {
32949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                v = where.get(i).view;
32959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!v.isRootNamespace()) {
32979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v = v.findViewWithTag(tag);
32989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (v != null) {
33009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return v;
33019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
33029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
33039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
33069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
33099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
33109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemsCanFocus && ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
33119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Don't handle edge touches immediately -- they may actually belong to one of our
33129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // descendants.
33139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
33149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onTouchEvent(ev);
33169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
33199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setChoiceMode(int)
33209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
33219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The current choice mode
33229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
33239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChoiceMode() {
33249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mChoiceMode;
33259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
33289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
33299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
33309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * List allows up to one item to  be in a chosen state. By setting the choiceMode to
33319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
33329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
33339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
33349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #CHOICE_MODE_MULTIPLE}
33359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
33369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setChoiceMode(int choiceMode) {
33379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChoiceMode = choiceMode;
33388f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        if (mChoiceMode != CHOICE_MODE_NONE) {
33398f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            if (mCheckStates == null) {
33408f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                mCheckStates = new SparseBooleanArray();
33418f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            }
3342cb704cd1e05ecd9bbd9bebd16f3b816dcb0c5309Adam Powell            if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
33438f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                mCheckedIdStates = new LongSparseArray<Boolean>();
33448f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            }
33459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
33499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performItemClick(View view, int position, long id) {
33509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode != CHOICE_MODE_NONE) {
33539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled = true;
33549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
33568f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                boolean newValue = !mCheckStates.get(position, false);
33578f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                mCheckStates.put(position, newValue);
33588f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
33598f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    if (newValue) {
33608f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
33618f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    } else {
33628f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                        mCheckedIdStates.delete(mAdapter.getItemId(position));
33638f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    }
33648f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                }
33659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
33668f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                boolean newValue = !mCheckStates.get(position, false);
33678f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                if (newValue) {
33689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCheckStates.clear();
33699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCheckStates.put(position, true);
33708f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
33718f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                        mCheckedIdStates.clear();
33728f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
33738f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    }
33748f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                }
33759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = true;
33789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rememberSyncState();
33799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
33809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handled |= super.performItemClick(view, position, id);
33839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
33859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
33889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the checked state of the specified position. The is only valid if
33899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
33909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #CHOICE_MODE_MULTIPLE}.
3391fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *
33929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The item whose checked state is to be checked
3393fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * @param value The new checked state for the item
33949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
33959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setItemChecked(int position, boolean value) {
33969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode == CHOICE_MODE_NONE) {
33979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
33989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
34019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCheckStates.put(position, value);
34028f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
34038f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                if (value) {
34048f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
34058f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                } else {
34068f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    mCheckedIdStates.delete(mAdapter.getItemId(position));
34078f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                }
34088f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            }
34099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
34108f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
3411845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot            // Clear all values if we're checking something, or unchecking the currently
3412845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot            // selected item
3413845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot            if (value || isItemChecked(position)) {
3414845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot                mCheckStates.clear();
34158f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                if (updateIds) {
34168f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    mCheckedIdStates.clear();
34178f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                }
3418845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot            }
34198842f0bd5c97cb39f6912392f34ba7435c275a42Romain Guy            // this may end up selecting the value we just cleared but this way
3420845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot            // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
34218842f0bd5c97cb39f6912392f34ba7435c275a42Romain Guy            if (value) {
34229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCheckStates.put(position, true);
34238f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                if (updateIds) {
34248f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
34258f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                }
34269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
34279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Do not generate a data change while we are in the layout phase
34309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mInLayout && !mBlockLayoutRequests) {
34319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = true;
34329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rememberSyncState();
34339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
34349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
34389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the checked state of the specified position. The result is only
3439abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
34409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or {@link #CHOICE_MODE_MULTIPLE}.
34419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
34429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The item whose checked state to return
3443abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     * @return The item's checked state or <code>false</code> if choice mode
3444abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     *         is invalid
34459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
34469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setChoiceMode(int)
34479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isItemChecked(int position) {
34499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
34509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mCheckStates.get(position);
34519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
34549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
34579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the currently checked item. The result is only valid if the choice
3458abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     * mode has been set to {@link #CHOICE_MODE_SINGLE}.
34599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
34609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The position of the currently checked item or
34619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         {@link #INVALID_POSITION} if nothing is selected
34629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
34639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setChoiceMode(int)
34649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getCheckedItemPosition() {
34669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
34679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mCheckStates.keyAt(0);
34689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
34719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
34749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the set of checked items in the list. The result is only valid if
3475abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
34769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
34779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return  A SparseBooleanArray which will return true for each call to
3478abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     *          get(int position) where position is a position in the list,
3479abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     *          or <code>null</code> if the choice mode is set to
3480abca4e8384c71721670f860b0d6d544fde8559ccKenny Root     *          {@link #CHOICE_MODE_NONE}.
34819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SparseBooleanArray getCheckedItemPositions() {
34839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode != CHOICE_MODE_NONE) {
34849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mCheckStates;
34859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
34879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3490fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * Returns the set of checked items ids. The result is only valid if the
34918f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * choice mode has not been set to {@link #CHOICE_MODE_NONE}.
3492fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *
3493fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * @return A new array which contains the id of each checked item in the
3494fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *         list.
34958f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     *
3496463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell     * @deprecated Use {@link #getCheckedItemIds()} instead.
3497ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy     */
3498ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy    public long[] getCheckItemIds() {
3499463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Use new behavior that correctly handles stable ID mapping.
3500463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        if (mAdapter != null && mAdapter.hasStableIds()) {
3501463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            return getCheckedItemIds();
3502463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        }
3503463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3504463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Old behavior was buggy, but would sort of work for adapters without stable IDs.
3505463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Fall back to it to support legacy apps.
3506463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null && mAdapter != null) {
3507463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final SparseBooleanArray states = mCheckStates;
3508463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final int count = states.size();
3509463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final long[] ids = new long[count];
3510463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final ListAdapter adapter = mAdapter;
3511463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3512463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            int checkedCount = 0;
3513463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            for (int i = 0; i < count; i++) {
3514463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                if (states.valueAt(i)) {
3515463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                    ids[checkedCount++] = adapter.getItemId(states.keyAt(i));
3516463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                }
3517463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            }
3518463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3519463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            // Trim array if needed. mCheckStates may contain false values
3520463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            // resulting in checkedCount being smaller than count.
3521463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            if (checkedCount == count) {
3522463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                return ids;
3523463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            } else {
3524463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                final long[] result = new long[checkedCount];
3525463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                System.arraycopy(ids, 0, result, 0, checkedCount);
3526463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3527463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                return result;
3528463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            }
3529463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        }
3530463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        return new long[0];
35318f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell    }
35328f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
35338f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell    /**
35348f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * Returns the set of checked items ids. The result is only valid if the
35358f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * choice mode has not been set to {@link #CHOICE_MODE_NONE} and the adapter
35368f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
35378f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     *
35388f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * @return A new array which contains the id of each checked item in the
35398f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     *         list.
35408f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     */
35418f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell    public long[] getCheckedItemIds() {
35428f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        if (mChoiceMode == CHOICE_MODE_NONE || mCheckedIdStates == null || mAdapter == null) {
35438f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            return new long[0];
3544ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy        }
35458f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
35468f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        final LongSparseArray<Boolean> idStates = mCheckedIdStates;
35478f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        final int count = idStates.size();
35488f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        final long[] ids = new long[count];
35498f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
35508f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        for (int i = 0; i < count; i++) {
35518f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            ids[i] = idStates.keyAt(i);
35528f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        }
35538f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
35548f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        return ids;
3555ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy    }
3556ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy
3557ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy    /**
35589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear any choices previously set
35599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearChoices() {
35619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCheckStates != null) {
35629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCheckStates.clear();
35639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35648f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        if (mCheckedIdStates != null) {
35658f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            mCheckedIdStates.clear();
35668f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        }
35679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class SavedState extends BaseSavedState {
35709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SparseBooleanArray checkState;
35718f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        LongSparseArray<Boolean> checkIdState;
35729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
35749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructor called from {@link ListView#onSaveInstanceState()}
35759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
35768f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        SavedState(Parcelable superState, SparseBooleanArray checkState,
35778f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                LongSparseArray<Boolean> checkIdState) {
35789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(superState);
35799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.checkState = checkState;
35808f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            this.checkIdState = checkIdState;
35819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
35849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructor called from {@link #CREATOR}
35859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
35869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private SavedState(Parcel in) {
35879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(in);
35889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkState = in.readSparseBooleanArray();
35898f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            long[] idState = in.createLongArray();
35908f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell
35918f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            if (idState.length > 0) {
35928f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                checkIdState = new LongSparseArray<Boolean>();
35938f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell                checkIdState.setValues(idState, Boolean.TRUE);
35948f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            }
35959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
35989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel out, int flags) {
35999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.writeToParcel(out, flags);
36009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.writeSparseBooleanArray(checkState);
36018f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
36029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
36059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
36069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "ListView.SavedState{"
36079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Integer.toHexString(System.identityHashCode(this))
36089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " checkState=" + checkState + "}";
36099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final Parcelable.Creator<SavedState> CREATOR
36129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                = new Parcelable.Creator<SavedState>() {
36139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState createFromParcel(Parcel in) {
36149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState(in);
36159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState[] newArray(int size) {
36189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState[size];
36199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
36219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
36229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
36249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Parcelable onSaveInstanceState() {
36259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
36268f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        return new SavedState(superState, mCheckStates, mCheckedIdStates);
36279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
36289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
36309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onRestoreInstanceState(Parcelable state) {
36319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
36329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
36349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ss.checkState != null) {
36369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           mCheckStates = ss.checkState;
36379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36398f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        if (ss.checkIdState != null) {
36408f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell            mCheckedIdStates = ss.checkIdState;
36418f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell        }
36429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
36439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3644