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
190363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyarimport com.google.android.collect.Lists;
200363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
21fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport com.android.internal.R;
224e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brownimport com.android.internal.util.Predicate;
23fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne
247b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.IdRes;
2594a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.annotation.NonNull;
260363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyarimport android.annotation.Nullable;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
28499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Intent;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
318f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guyimport android.graphics.Paint;
32fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.PixelFormat;
33fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.Rect;
34fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.graphics.drawable.Drawable;
350363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyarimport android.os.Bundle;
360363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyarimport android.os.Trace;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
3830ee76cf05f785bbf819b71954242c835c597ce1alanvimport android.util.MathUtils;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseBooleanArray;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.FocusFinder;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
42fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunneimport android.view.SoundEffectConstants;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewDebug;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
4694a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.view.ViewHierarchyEncoder;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewParent;
483e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viveretteimport android.view.ViewRootImpl;
498a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
5023f4432437b2ab742971055b7eb79b346894f24bAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
515b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
525b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
533e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viveretteimport android.view.accessibility.AccessibilityNodeProvider;
54499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.widget.RemoteViews.RemoteView;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
57b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyarimport java.util.List;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation Notes:
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Some terminology:
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     index    - index of the items that are currently visible
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     position - index of the items in the cursor
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that shows items in a vertically scrolling list. The items
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * come from the {@link ListAdapter} associated with this view.
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
734c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>
744c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
7541ec65355bd6ded652769725b276d47c54a0d913Scott Main *
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_entries
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_divider
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_dividerHeight
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_headerDividersEnabled
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_footerDividersEnabled
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
82499cb9f516062b654952d282f211bee44c31a3c2Winson Chung@RemoteView
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ListView extends AbsListView {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Used to indicate a no preference for a position type.
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int NO_POSITION = -1;
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
115744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
116744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Drawable mDivider;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mDividerHeight;
120fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen
121637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    Drawable mOverScrollHeader;
122637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    Drawable mOverScrollFooter;
123637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
12424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    private boolean mIsCacheColorOpaque;
12524443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    private boolean mDividerIsOpaque;
12624443ea3992e372e47daa50266b0f2ec38cac388Romain Guy
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mHeaderDividersEnabled;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mFooterDividersEnabled;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAreAllItemsSelectable = true;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mItemsCanFocus = false;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // used for temporary calculations.
135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private final Rect mTempRect = new Rect();
136a02903fbee6725563da4472bd120f844e9d5518cRomain Guy    private Paint mDividerPaint;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // the single allocated result per list view; kinda cheesey but avoids
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // allocating these thingies too often.
1409c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy    private final ArrowScrollFocusResult mArrowScrollFocusResult = new ArrowScrollFocusResult();
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    // Keeps focused children visible through resizes
1439bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    private FocusSelector mFocusSelector;
1448350f7dbc3a62211b2891f35911e4073d24c4cc5Adam Powell
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListView(Context context) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListView(Context context, AttributeSet attrs) {
1507b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        this(context, attrs, R.attr.listViewStyle);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
153617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ListView(Context context, AttributeSet attrs, int defStyleAttr) {
154617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
155617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
156617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
157617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
158617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
160617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
1617b2f86488cb28568074a5a97b84a66b862473409Alan Viverette                attrs, R.styleable.ListView, defStyleAttr, defStyleRes);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1637b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (entries != null) {
1657b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            setAdapter(new ArrayAdapter<>(context, R.layout.simple_list_item_1, entries));
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1687b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        final Drawable d = a.getDrawable(R.styleable.ListView_divider);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (d != null) {
1707b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            // Use an implicit divider height which may be explicitly
1717b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            // overridden by android:dividerHeight further down.
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setDivider(d);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1747b2f86488cb28568074a5a97b84a66b862473409Alan Viverette
1757b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        final Drawable osHeader = a.getDrawable(R.styleable.ListView_overScrollHeader);
176637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (osHeader != null) {
177637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            setOverscrollHeader(osHeader);
178637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
179637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
1807b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        final Drawable osFooter = a.getDrawable(R.styleable.ListView_overScrollFooter);
181637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (osFooter != null) {
182637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            setOverscrollFooter(osFooter);
183637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
184637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
1857b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        // Use an explicit divider height, if specified.
1867b2f86488cb28568074a5a97b84a66b862473409Alan Viverette        if (a.hasValueOrEmpty(R.styleable.ListView_dividerHeight)) {
1877b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            final int dividerHeight = a.getDimensionPixelSize(
1887b2f86488cb28568074a5a97b84a66b862473409Alan Viverette                    R.styleable.ListView_dividerHeight, 0);
1897b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            if (dividerHeight != 0) {
1907b2f86488cb28568074a5a97b84a66b862473409Alan Viverette                setDividerHeight(dividerHeight);
1917b2f86488cb28568074a5a97b84a66b862473409Alan Viverette            }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The maximum amount a list view will scroll in response to
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   an arrow event.
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMaxScrollAmount() {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Make sure views are touching the top or bottom edge, as appropriate for
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * our gravity
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void adjustViewsUpOrDown() {
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int delta;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Uh-oh -- we came up short. Slide all views up to make them
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // align with the top
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(0);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getTop() - mListPadding.top;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition != 0) {
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space above the first item if it is
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta -= mDividerHeight;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta < 0) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We only are looking to see if we are too low, not too high
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are too high, slide all views down to align with bottom
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(childCount - 1);
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delta = child.getBottom() - (getHeight() - mListPadding.bottom);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition + childCount < mItemCount) {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It's OK to have some space below the last item if it is
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // part of the vertical spacing
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta += mDividerHeight;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (delta > 0) {
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = 0;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (delta != 0) {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(-delta);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25672e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Add a fixed view to appear at the top of the list. If this method is
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
26072e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Note: When first introduced, this method could only be called before
26172e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
262e8222dddaf2e3da14380101e818d4254899e0c0dChet Haase     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
26372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * called at any time. If the ListView's adapter does not extend
26472e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
26572e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * instance of {@link WrapperListAdapter}.
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param data Data to associate with this view
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isSelectable whether the item is selectable
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addHeaderView(View v, Object data, boolean isSelectable) {
27272e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        final FixedViewInfo info = new FixedViewInfo();
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.view = v;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.data = data;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.isSelectable = isSelectable;
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderViewInfos.add(info);
27720cc605b69a017316112929666255226c184a376Alan Viverette        mAreAllItemsSelectable &= isSelectable;
27822c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen
27972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        // Wrap the adapter if it wasn't already wrapped.
28072e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        if (mAdapter != null) {
28172e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            if (!(mAdapter instanceof HeaderViewListAdapter)) {
282744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan                wrapHeaderListAdapterInternal();
28372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            }
28472e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette
28572e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            // In the case of re-adding a header view, or adding one later on,
28672e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            // we need to notify the observer.
28772e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            if (mDataSetObserver != null) {
28872e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette                mDataSetObserver.onChanged();
28972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            }
29022c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen        }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the top of the list. If addHeaderView is
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
29872e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Note: When first introduced, this method could only be called before
29972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
300e8222dddaf2e3da14380101e818d4254899e0c0dChet Haase     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
30172e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * called at any time. If the ListView's adapter does not extend
30272e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
30372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * instance of {@link WrapperListAdapter}.
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addHeaderView(View v) {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addHeaderView(v, null, true);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getHeaderViewsCount() {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderViewInfos.size();
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Removes a previously-added header view.
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to remove
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the view was removed, false if the view was not a header
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         view
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean removeHeaderView(View v) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeaderViewInfos.size() > 0) {
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean result = false;
326247a0f0a16f956c463644f732dacb6c8d0979ba3Adam Powell            if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
32722c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                if (mDataSetObserver != null) {
32822c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                    mDataSetObserver.onChanged();
32922c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                }
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = true;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeFixedViewInfo(v, mHeaderViewInfos);
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = where.size();
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; ++i) {
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FixedViewInfo info = where.get(i);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (info.view == v) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                where.remove(i);
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a fixed view to appear at the bottom of the list. If addFooterView is
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called more than once, the views will appear in the order they were
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * added. Views added using this call can take focus if they want.
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
35472e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Note: When first introduced, this method could only be called before
35572e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
356e8222dddaf2e3da14380101e818d4254899e0c0dChet Haase     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
35772e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * called at any time. If the ListView's adapter does not extend
35872e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
35972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * instance of {@link WrapperListAdapter}.
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param data Data to associate with this view
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isSelectable true if the footer view can be selected
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addFooterView(View v, Object data, boolean isSelectable) {
36672e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        final FixedViewInfo info = new FixedViewInfo();
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.view = v;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.data = data;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        info.isSelectable = isSelectable;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterViewInfos.add(info);
37120cc605b69a017316112929666255226c184a376Alan Viverette        mAreAllItemsSelectable &= isSelectable;
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        // Wrap the adapter if it wasn't already wrapped.
37472e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette        if (mAdapter != null) {
37572e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            if (!(mAdapter instanceof HeaderViewListAdapter)) {
376744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan                wrapHeaderListAdapterInternal();
37772e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            }
37872e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette
37972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            // In the case of re-adding a footer view, or adding one later on,
38072e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            // we need to notify the observer.
38172e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            if (mDataSetObserver != null) {
38272e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette                mDataSetObserver.onChanged();
38372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette            }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
38872e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Add a fixed view to appear at the bottom of the list. If addFooterView is
38972e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * called more than once, the views will appear in the order they were
39072e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * added. Views added using this call can take focus if they want.
39172e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * <p>
39272e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * Note: When first introduced, this method could only be called before
39372e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
394e8222dddaf2e3da14380101e818d4254899e0c0dChet Haase     * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
39572e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * called at any time. If the ListView's adapter does not extend
39672e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
39772e2f2a94049642454e960f344dc6feed4ec1dc9Alan Viverette     * instance of {@link WrapperListAdapter}.
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to add.
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addFooterView(View v) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addFooterView(v, null, true);
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getFooterViewsCount() {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mFooterViewInfos.size();
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Removes a previously-added footer view.
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param v The view to remove
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * true if the view was removed, false if the view was not a footer view
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean removeFooterView(View v) {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFooterViewInfos.size() > 0) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean result = false;
420247a0f0a16f956c463644f732dacb6c8d0979ba3Adam Powell            if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
42122c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                if (mDataSetObserver != null) {
42222c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                    mDataSetObserver.onChanged();
42322c04a316a482176957fd27285c0fe36e2f3979cMarco Nelissen                }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = true;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeFixedViewInfo(v, mFooterViewInfos);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the adapter currently in use in this ListView. The returned adapter
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * might not be the same adapter passed to {@link #setAdapter(ListAdapter)} but
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * might be a {@link WrapperListAdapter}.
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The adapter currently used to display data in this ListView.
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setAdapter(ListAdapter)
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ListAdapter getAdapter() {
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAdapter;
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
447499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
448499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * through the specified intent.
449499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
450499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
451499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @android.view.RemotableViewMethod
452499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void setRemoteViewsAdapter(Intent intent) {
453499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.setRemoteViewsAdapter(intent);
454499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
455499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
456499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the data behind this ListView.
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * depending on the ListView features currently in use. For instance, adding
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * headers and/or footers will cause the adapter to be wrapped.
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param adapter The ListAdapter which is responsible for maintaining the
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        data backing this list and for producing a view to represent an
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        item in that data set.
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getAdapter()
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAdapter(ListAdapter adapter) {
471df36b0579e1e550de3d66a20362717e49b23235cRomain Guy        if (mAdapter != null && mDataSetObserver != null) {
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.unregisterDataSetObserver(mDataSetObserver);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        resetList();
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRecycler.clear();
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
479744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter = adapter;
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedPosition = INVALID_POSITION;
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOldSelectedRowId = INVALID_ROW_ID;
486f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell
487f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        // AbsListView#setAdapter will update choice mode states.
488f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell        super.setAdapter(adapter);
489f343e1ba7e796120eefa917dbf78348feea98e11Adam Powell
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOldItemCount = mItemCount;
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mItemCount = mAdapter.getCount();
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkFocus();
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataSetObserver = new AdapterDataSetObserver();
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAdapter.registerDataSetObserver(mDataSetObserver);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int position;
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStackFromBottom) {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(mItemCount - 1, false);
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = lookForSelectablePosition(0, true);
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(position);
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(position);
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount == 0) {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Nothing selected
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSelectionChanged();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAreAllItemsSelectable = true;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkFocus();
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Nothing selected
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The list is empty. Clear everything out.
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void resetList() {
5292e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        // The parent's resetList() will remove all views from the layout so we need to
5302e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        // cleanup the state of our footers and headers
5312e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        clearRecycledState(mHeaderViewInfos);
5322e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        clearRecycledState(mFooterViewInfos);
5332e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.resetList();
5352e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayoutMode = LAYOUT_NORMAL;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5392e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy    private void clearRecycledState(ArrayList<FixedViewInfo> infos) {
5402e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        if (infos != null) {
5412e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            final int count = infos.size();
5422e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5432e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            for (int i = 0; i < count; i++) {
5442e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                final View child = infos.get(i).view;
5452e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                final LayoutParams p = (LayoutParams) child.getLayoutParams();
5462e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                if (p != null) {
5472e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                    p.recycledHeaderFooter = false;
5482e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy                }
5492e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy            }
5502e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy        }
5512e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy    }
5522e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the list needs to show the top fading edge
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean showingTopFadingEdge() {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mScrollY + mListPadding.top;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mFirstPosition > 0) || (getChildAt(0).getTop() > listTop);
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the list needs to show the bottom fading edge
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean showingBottomFadingEdge() {
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childCount = getChildCount();
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int lastVisiblePosition = mFirstPosition + childCount - 1;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = mScrollY + getHeight() - mListPadding.bottom;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (lastVisiblePosition < mItemCount - 1)
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         || (bottomOfBottomChild < listBottom);
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rectTopWithinChild = rect.top;
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // offset so rect is in coordinates of the this view
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        rect.offset(child.getLeft(), child.getTop());
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        rect.offset(-child.getScrollX(), -child.getScrollY());
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int height = getHeight();
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listUnfadedTop = getScrollY();
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listUnfadedBottom = listUnfadedTop + height;
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int fadingEdge = getVerticalFadingEdgeLength();
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (showingTopFadingEdge()) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // leave room for top fading edge as long as rect isn't at very top
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mSelectedPosition > 0) || (rectTopWithinChild > fadingEdge)) {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listUnfadedTop += fadingEdge;
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childCount = getChildCount();
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (showingBottomFadingEdge()) {
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // leave room for bottom fading edge as long as rect isn't at very bottom
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mSelectedPosition < mItemCount - 1)
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || (rect.bottom < (bottomOfBottomChild - fadingEdge))) {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listUnfadedBottom -= fadingEdge;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int scrollYDelta = 0;
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rect.bottom > listUnfadedBottom && rect.top > listUnfadedTop) {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to MOVE DOWN to get it in view: move down just enough so
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // that the entire rectangle is in view (or at least the first
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // screen size chunk).
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rect.height() > height) {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // just enough to get screen size chunk on
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta += (rect.top - listUnfadedTop);
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // get entire rect at bottom of screen
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta += (rect.bottom - listUnfadedBottom);
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // make sure we aren't scrolling beyond the end of our children
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int distanceToBottom = bottomOfBottomChild - listUnfadedBottom;
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (rect.top < listUnfadedTop && rect.bottom < listUnfadedBottom) {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to MOVE UP to get it in view: move up just enough so that
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // entire rectangle is in view (or at least the first screen
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // size chunk of it).
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rect.height() > height) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // screen size chunk
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta -= (listUnfadedBottom - rect.bottom);
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // entire rect at top
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                scrollYDelta -= (listUnfadedTop - rect.top);
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // make sure we aren't scrolling any further than the top our children
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int top = getChildAt(0).getTop();
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int deltaToTop = top - listUnfadedTop;
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollYDelta = Math.max(scrollYDelta, deltaToTop);
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean scroll = scrollYDelta != 0;
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scroll) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListItemsBy(-scrollYDelta);
648079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn            positionSelector(INVALID_POSITION, child);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSelectedTop = child.getTop();
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return scroll;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@inheritDoc}
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void fillGap(boolean down) {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = getChildCount();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (down) {
6628c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            int paddingTop = 0;
6638c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
6648c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                paddingTop = getListPaddingTop();
6658c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ? getChildAt(count - 1).getBottom() + mDividerHeight :
6678c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                    paddingTop;
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(mFirstPosition + count, startOffset);
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6718c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            int paddingBottom = 0;
6728c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
6738c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                paddingBottom = getListPaddingBottom();
6748c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int startOffset = count > 0 ? getChildAt(0).getTop() - mDividerHeight :
6768c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell                    getHeight() - paddingBottom;
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(mFirstPosition - 1, startOffset);
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos down to the end of the list view.
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the item associated with pos
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        should be drawn
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected, if it happens to be in the
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         range that we draw.
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillDown(int pos, int nextTop) {
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6968c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        int end = (mBottom - mTop);
6978c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
6988c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            end -= mListPadding.bottom;
6998c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextTop < end && pos < mItemCount) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is this the selected item?
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected = pos == mSelectedPosition;
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextTop = child.getBottom() + mDividerHeight;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selected) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = child;
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos++;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
713b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen        setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from pos up to the top of the list view.
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos The first position to put in the list
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextBottom The location where the bottom of the item associated
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        with pos should be drawn
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillUp(int pos, int nextBottom) {
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = null;
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7308c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        int end = 0;
7318c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
7328c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell            end = mListPadding.top;
7338c3e0fc84f69e9fe704dc20dd6c2bab1ce43fe93Adam Powell        }
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (nextBottom > end && pos >= 0) {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is this the selected item?
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected = pos == mSelectedPosition;
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View child = makeAndAddView(pos, nextBottom, false, mListPadding.left, selected);
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextBottom = child.getTop() - mDividerHeight;
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selected) {
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedView = child;
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos--;
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = pos + 1;
747b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen        setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return selectedView;
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list from top to bottom, starting with mFirstPosition
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextTop The location where the top of the first item should be
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        drawn
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that is currently selected
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromTop(int nextTop) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition < 0) {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFirstPosition = 0;
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fillDown(mFirstPosition, nextTop);
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     * Put mSelectedPosition in the middle of the screen and then build up and
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * down from there. This method forces mSelectedPosition to the center.
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Top of the area in which children can be drawn, as
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        measured in pixels
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Bottom of the area in which children can be drawn,
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        as measured in pixels
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Currently selected view
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromMiddle(int childrenTop, int childrenBottom) {
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int height = childrenBottom - childrenTop;
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int position = reconcileSelectedPosition();
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel = makeAndAddView(position, childrenTop, true,
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left, true);
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = position;
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int selHeight = sel.getMeasuredHeight();
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selHeight <= height) {
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom((height - selHeight) / 2);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fillAboveAndBelow(sel, position);
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Once the selected view as been placed, fill up the visible area above and
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * below it.
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sel The selected view
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The position corresponding to sel
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void fillAboveAndBelow(View sel, int position) {
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(position - 1, sel.getTop() - dividerHeight);
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(position + 1, sel.getBottom() + dividerHeight);
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillDown(position + 1, sel.getBottom() + dividerHeight);
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillUp(position - 1, sel.getTop() - dividerHeight);
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the grid based on positioning the new selection at a specific
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location. The selection may be moved so that it does not intersect the
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * faded edges. The grid is then filled upwards and downwards from there.
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedTop Where the selected item should be
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillFromSelection(int selectedTop, int childrenTop, int childrenBottom) {
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fadingEdgeLength = getVerticalFadingEdgeLength();
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength,
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sel = makeAndAddView(selectedPosition, selectedTop, true, mListPadding.left, true);
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Some of the newly selected item extends below the bottom of the list
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sel.getBottom() > bottomSelectionPixel) {
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available above the selection into which we can scroll
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // upwards
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceAbove = sel.getTop() - topSelectionPixel;
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the bottom of the selected item
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // fully into view
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceBelow = sel.getBottom() - bottomSelectionPixel;
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = Math.min(spaceAbove, spaceBelow);
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now offset the selected item to get it into view
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom(-offset);
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (sel.getTop() < topSelectionPixel) {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space required to bring the top of the selected item fully
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // into view
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceAbove = topSelectionPixel - sel.getTop();
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find space available below the selection into which we can scroll
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // downwards
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int spaceBelow = bottomSelectionPixel - sel.getBottom();
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int offset = Math.min(spaceAbove, spaceBelow);
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Offset the selected item to get it into view
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel.offsetTopAndBottom(offset);
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Fill in views above and below
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fillAboveAndBelow(sel, selectedPosition);
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooHigh(getChildCount());
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            correctTooLow(getChildCount());
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the bottom-most pixel we can draw the selection into
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Bottom pixel were children can be drawn
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedPosition The position that will be selected
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The bottom-most pixel we can draw the selection into
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getBottomSelectionPixel(int childrenBottom, int fadingEdgeLength,
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int selectedPosition) {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottomSelectionPixel = childrenBottom;
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedPosition != mItemCount - 1) {
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomSelectionPixel -= fadingEdgeLength;
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return bottomSelectionPixel;
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calculate the top-most pixel we can draw the selection into
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Top pixel were children can be drawn
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fadingEdgeLength Length of the fading edge in pixels, if present
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedPosition The position that will be selected
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The top-most pixel we can draw the selection into
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getTopSelectionPixel(int childrenTop, int fadingEdgeLength, int selectedPosition) {
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // first pixel we can draw the selection into
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topSelectionPixel = childrenTop;
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedPosition > 0) {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topSelectionPixel += fadingEdgeLength;
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return topSelectionPixel;
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
922499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
923499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Smoothly scroll to the specified adapter position. The view will
924499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * scroll such that the indicated position is displayed.
925499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param position Scroll to this adapter position.
926499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
927499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @android.view.RemotableViewMethod
928499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void smoothScrollToPosition(int position) {
929499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.smoothScrollToPosition(position);
930499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
931499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
932499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
933499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * Smoothly scroll to the specified adapter position offset. The view will
934499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * scroll such that the indicated position is displayed.
935499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * @param offset The amount to offset from the adapter position to scroll to.
936499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
937499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @android.view.RemotableViewMethod
938499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void smoothScrollByOffset(int offset) {
939499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.smoothScrollByOffset(offset);
940499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills the list based on positioning the new selection relative to the old
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * selection. The new selection will be placed at, above, or below the
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location of the new selection depending on how the selection is moving.
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The selection will then be pinned to the visible part of the screen,
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * excluding the edges that are faded. The list is then filled upwards and
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * downwards from there.
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param oldSel The old selected view. Useful for trying to put the new
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        selection in the same place
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newSel The view that is to become selected. Useful for trying to
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        put the new selection in the same place
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param delta Which way we are moving
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenTop Where to start drawing children
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenBottom Last pixel where children can be drawn
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The view that currently has selection
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View moveSelection(View oldSel, View newSel, int delta, int childrenTop,
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childrenBottom) {
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fadingEdgeLength = getVerticalFadingEdgeLength();
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedPosition = mSelectedPosition;
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel;
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int bottomSelectionPixel = getBottomSelectionPixel(childrenTop, fadingEdgeLength,
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selectedPosition);
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (delta > 0) {
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 1: Scrolling down.
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *     Before           After
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   A   |        |   A   |
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   1   |   =>   +-------+
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        |   B   |
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   B   |        |   2   |
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    Try to keep the top of the previously selected item where it was.
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    oldSel = A
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    sel = B
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Put oldSel (A) where it belongs
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            oldSel = makeAndAddView(selectedPosition - 1, oldSel.getTop(), true,
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left, false);
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int dividerHeight = mDividerHeight;
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Now put the new selection (B) below that
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeAndAddView(selectedPosition, oldSel.getBottom() + dividerHeight, true,
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left, true);
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Some of the newly selected item extends below the bottom of the list
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel.getBottom() > bottomSelectionPixel) {
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space available above the selection into which we can scroll upwards
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceAbove = sel.getTop() - topSelectionPixel;
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space required to bring the bottom of the selected item fully into view
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceBelow = sel.getBottom() - bottomSelectionPixel;
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't scroll more than half the height of the list
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int halfVerticalSpace = (childrenBottom - childrenTop) / 2;
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int offset = Math.min(spaceAbove, spaceBelow);
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offset = Math.min(offset, halfVerticalSpace);
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We placed oldSel, so offset that item
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldSel.offsetTopAndBottom(-offset);
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Now offset the selected item to get it into view
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel.offsetTopAndBottom(-offset);
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (delta < 0) {
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 2: Scrolling up.
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *     Before           After
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   A   |        |   A   |
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+   =>   |   1   |
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   B   |        +-------+
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |   2   |        |   B   |
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    +-------+        +-------+
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    |       |        |       |
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    Try to keep the top of the item about to become selected where it was.
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    newSel = A
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *    olSel = B
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (newSel != null) {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try to position the top of newSel (A) where it was before it was selected
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = makeAndAddView(selectedPosition, newSel.getTop(), true, mListPadding.left,
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        true);
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If (A) was not on screen and so did not have a view, position
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // it above the oldSel (B)
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = makeAndAddView(selectedPosition, oldSel.getTop(), false, mListPadding.left,
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        true);
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Some of the newly selected item extends above the top of the list
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel.getTop() < topSelectionPixel) {
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Find space required to bring the top of the selected item fully into view
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceAbove = topSelectionPixel - sel.getTop();
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               // Find space available below the selection into which we can scroll downwards
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int spaceBelow = bottomSelectionPixel - sel.getBottom();
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't scroll more than half the height of the list
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int halfVerticalSpace = (childrenBottom - childrenTop) / 2;
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int offset = Math.min(spaceAbove, spaceBelow);
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offset = Math.min(offset, halfVerticalSpace);
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Offset the selected item to get it into view
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel.offsetTopAndBottom(offset);
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillAboveAndBelow(sel, selectedPosition);
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldTop = oldSel.getTop();
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Case 3: Staying still
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sel = makeAndAddView(selectedPosition, oldTop, true, mListPadding.left, true);
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We're staying still...
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldTop < childrenTop) {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... but the top of the old selection was off screen.
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // (This can happen if the data changes size out from under us)
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int newBottom = sel.getBottom();
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newBottom < childrenTop + 20) {
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Not enough visible -- bring it onscreen
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel.offsetTopAndBottom(childrenTop - sel.getTop());
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill in views above and below
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fillAboveAndBelow(sel, selectedPosition);
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sel;
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11109bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    private class FocusSelector implements Runnable {
11110363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        // the selector is waiting to set selection on the list view
11120363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        private static final int STATE_SET_SELECTION = 1;
11130363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        // the selector set the selection on the list view, waiting for a layoutChildren pass
11140363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        private static final int STATE_WAIT_FOR_LAYOUT = 2;
11150363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        // the selector's selection has been honored and it is waiting to request focus on the
11160363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        // target child.
11170363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        private static final int STATE_REQUEST_FOCUS = 3;
11180363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11190363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        private int mAction;
11209bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        private int mPosition;
11219bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        private int mPositionTop;
11220363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11230363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        FocusSelector setupForSetSelection(int position, int top) {
11249bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            mPosition = position;
11259bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            mPositionTop = top;
11260363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            mAction = STATE_SET_SELECTION;
11279bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            return this;
11289bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
11290363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11309bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        public void run() {
11310363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            if (mAction == STATE_SET_SELECTION) {
11320363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                setSelectionFromTop(mPosition, mPositionTop);
11330363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                mAction = STATE_WAIT_FOR_LAYOUT;
11340363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            } else if (mAction == STATE_REQUEST_FOCUS) {
11350363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                final int childIndex = mPosition - mFirstPosition;
11360363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                final View child = getChildAt(childIndex);
11370363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                if (child != null) {
11380363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                    child.requestFocus();
11390363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                }
11400363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                mAction = -1;
11410363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            }
11420363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        }
11430363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11440363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        @Nullable Runnable setupFocusIfValid(int position) {
11450363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            if (mAction != STATE_WAIT_FOR_LAYOUT || position != mPosition) {
11460363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                return null;
11470363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            }
11480363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            mAction = STATE_REQUEST_FOCUS;
11490363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            return this;
11500363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        }
11510363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11520363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        void onLayoutComplete() {
11530363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            if (mAction == STATE_WAIT_FOR_LAYOUT) {
11540363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                mAction = -1;
11550363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            }
11560363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        }
11570363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar    }
11580363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11590363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar    @Override
11600363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar    protected void onDetachedFromWindow() {
11610363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        if (mFocusSelector != null) {
11620363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            removeCallbacks(mFocusSelector);
11630363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            mFocusSelector = null;
11649bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
11650363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar        super.onDetachedFromWindow();
11669bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    }
11670363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar
11689bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    @Override
11699bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
11709bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        if (getChildCount() > 0) {
11719bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            View focusedChild = getFocusedChild();
11729bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            if (focusedChild != null) {
11739bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int childPosition = mFirstPosition + indexOfChild(focusedChild);
11749bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int childBottom = focusedChild.getBottom();
11759bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int offset = Math.max(0, childBottom - (h - mPaddingTop));
11769bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                final int top = focusedChild.getTop() - offset;
11779bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                if (mFocusSelector == null) {
11789bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                    mFocusSelector = new FocusSelector();
11799bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell                }
11800363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                post(mFocusSelector.setupForSetSelection(childPosition, top));
11819bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell            }
11829bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        }
11839bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell        super.onSizeChanged(w, h, oldw, oldh);
11849bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell    }
11859bf3c128509de5bd66222943a00acfcd1000cd62Adam Powell
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Sets up mListPadding
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11912ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
11922ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidth = 0;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeight = 0;
1198189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        int childState = 0;
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
12012ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED
12022ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette                || heightMode == MeasureSpec.UNSPECIFIED)) {
120321875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            final View child = obtainView(0, mIsScrap);
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12052ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            // Lay out child directly against the parent measure spec so that
12064610eeff9c6c4789705b6550a57333150d39e970Chet Haase            // we can obtain exected minimum width and height.
1207b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski            measureScrapChild(child, 0, widthMeasureSpec, heightSize);
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childWidth = child.getMeasuredWidth();
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeight = child.getMeasuredHeight();
1211189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            childState = combineMeasuredStates(childState, child.getMeasuredState());
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy            if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
12149c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy                    ((LayoutParams) child.getLayoutParams()).viewType)) {
12154771b55d13f45c96a11d9b03be284f94eb4431c8Alan Viverette                mRecycler.addScrapView(child, 0);
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (widthMode == MeasureSpec.UNSPECIFIED) {
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            widthSize = mListPadding.left + mListPadding.right + childWidth +
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getVerticalScrollbarWidth();
1222189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        } else {
12232ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            widthSize |= (childState & MEASURED_STATE_MASK);
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.UNSPECIFIED) {
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = mListPadding.top + mListPadding.bottom + childHeight +
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    getVerticalFadingEdgeLength() * 2;
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (heightMode == MeasureSpec.AT_MOST) {
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: after first layout we should maybe start at the first visible position, not 0
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12362ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        setMeasuredDimension(widthSize, heightSize);
12372ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette
12382ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        mWidthMeasureSpec = widthMeasureSpec;
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1241b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski    private void measureScrapChild(View child, int position, int widthMeasureSpec, int heightHint) {
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LayoutParams p = (LayoutParams) child.getLayoutParams();
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
1244aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
12454df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            child.setLayoutParams(p);
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p.viewType = mAdapter.getItemViewType(position);
124892539d5c75922b430b7f69a14144b6a61045f1f4Alan Viverette        p.isEnabled = mAdapter.isEnabled(position);
12490bf88594c43ced48d862d122e3e84967b3b63658Romain Guy        p.forceAdd = true;
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12512ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left + mListPadding.right, p.width);
12532ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        final int lpHeight = p.height;
12542ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        final int childHeightSpec;
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lpHeight > 0) {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1258d5dbf4b2a09c9cf2d17fa6af3fdf75d1fb774056Adam Powell            childHeightSpec = MeasureSpec.makeSafeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED);
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.measure(childWidthSpec, childHeightSpec);
12612ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette
12622ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        // Since this view was measured directly aginst the parent measure
12632ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        // spec, we must measure it again before reuse.
12642ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette        child.forceLayout();
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True to recycle the views used to measure this ListView in
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         UNSPECIFIED/AT_MOST modes, false otherwise.
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1272bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev    @ViewDebug.ExportedProperty(category = "list")
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean recycleOnMeasure() {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Measures the height of the given range of children (inclusive) and
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * returns the height with this ListView's padding and divider heights
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * included. If maxHeight is provided, the measuring will stop when the
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * current height reaches maxHeight.
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param widthMeasureSpec The width measure spec to be given to a child's
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            {@link View#measure(int, int)}.
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param startPosition The position of the first child to be shown.
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param endPosition The (inclusive) position of the last child to be
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            shown. Specify {@link #NO_POSITION} if the last child should be
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            the last available child from the adapter.
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param maxHeight The maximum height that will be returned (if all the
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            children don't fit in this value, this value will be
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            returned).
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param disallowPartialChildPosition In general, whether the returned
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            height should only contain entire children. This is more
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            powerful--it is the first inclusive position at which partial
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            children will not be allowed. Example: it looks nice to have
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            at least 3 completely visible children, and in portrait this
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            will most likely fit; but in landscape there could be times
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            when even 2 children can not be completely shown, so a value
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            of 2 (remember, inclusive) would be good (assuming
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            startPosition is 0).
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The height of this ListView with the given children.
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
13042ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            int maxHeight, int disallowPartialChildPosition) {
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ListAdapter adapter = mAdapter;
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null) {
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mListPadding.top + mListPadding.bottom;
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Include the padding of the list
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int returnedHeight = mListPadding.top + mListPadding.bottom;
1312fea4013499aaa96dd0e2579988e2b2236dcd4025Alan Viverette        final int dividerHeight = mDividerHeight;
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The previous height value that was less than maxHeight and contained
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // no partial children
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int prevHeightWithoutPartialChild = 0;
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int i;
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mItemCount - 1 since endPosition parameter is inclusive
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final AbsListView.RecycleBin recycleBin = mRecycler;
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean recyle = recycleOnMeasure();
132321875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        final boolean[] isScrap = mIsScrap;
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (i = startPosition; i <= endPosition; ++i) {
132621875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy            child = obtainView(i, isScrap);
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1328b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski            measureScrapChild(child, i, widthMeasureSpec, maxHeight);
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (i > 0) {
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Count the divider for all but one child
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                returnedHeight += dividerHeight;
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Recycle the view before we possibly return from the method
13369c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy            if (recyle && recycleBin.shouldRecycleViewType(
13379c3184cc162ee8c10eabd3f996629a9397a1f551Romain Guy                    ((LayoutParams) child.getLayoutParams()).viewType)) {
1338079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                recycleBin.addScrapView(child, -1);
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            returnedHeight += child.getMeasuredHeight();
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (returnedHeight >= maxHeight) {
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We went over, figure out which height to return.  If returnedHeight > maxHeight,
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // then the i'th position did not fit completely.
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (i > disallowPartialChildPosition) // We've past the min pos
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (prevHeightWithoutPartialChild > 0) // We have a prev height
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && (returnedHeight != maxHeight) // i'th child did not fit completely
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ? prevHeightWithoutPartialChild
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        : maxHeight;
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                prevHeightWithoutPartialChild = returnedHeight;
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // At this point, we went through the range of children, and they each
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // completely fit, so return the returnedHeight
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return returnedHeight;
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int findMotionRow(int y) {
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childCount = getChildCount();
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (childCount > 0) {
136884222e04252720cf681032e865db526ce4a612a4Adam Powell            if (!mStackFromBottom) {
136984222e04252720cf681032e865db526ce4a612a4Adam Powell                for (int i = 0; i < childCount; i++) {
137084222e04252720cf681032e865db526ce4a612a4Adam Powell                    View v = getChildAt(i);
137184222e04252720cf681032e865db526ce4a612a4Adam Powell                    if (y <= v.getBottom()) {
137284222e04252720cf681032e865db526ce4a612a4Adam Powell                        return mFirstPosition + i;
137384222e04252720cf681032e865db526ce4a612a4Adam Powell                    }
137484222e04252720cf681032e865db526ce4a612a4Adam Powell                }
137584222e04252720cf681032e865db526ce4a612a4Adam Powell            } else {
137684222e04252720cf681032e865db526ce4a612a4Adam Powell                for (int i = childCount - 1; i >= 0; i--) {
137784222e04252720cf681032e865db526ce4a612a4Adam Powell                    View v = getChildAt(i);
137884222e04252720cf681032e865db526ce4a612a4Adam Powell                    if (y >= v.getTop()) {
137984222e04252720cf681032e865db526ce4a612a4Adam Powell                        return mFirstPosition + i;
138084222e04252720cf681032e865db526ce4a612a4Adam Powell                    }
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Put a specific item at a specific location on the screen and then build
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * up and down from there.
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The reference view to use as the starting point
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param top Pixel offset from the top of this view to the top of the
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        reference view.
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The selected view, or null if the selected view is outside the
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         visible area.
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View fillSpecific(int position, int top) {
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean tempIsSelected = position == mSelectedPosition;
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View temp = makeAndAddView(position, top, true, mListPadding.left, tempIsSelected);
14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Possibly changed again in fillUp if we add rows above this one.
14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = position;
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View above;
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View below;
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStackFromBottom) {
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(position - 1, temp.getTop() - dividerHeight);
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This will correct for the top of the first view not touching the top of the list
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(position + 1, temp.getBottom() + dividerHeight);
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                correctTooHigh(childCount);
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fillDown(position + 1, temp.getBottom() + dividerHeight);
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This will correct for the bottom of the last view not touching the bottom of the list
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjustViewsUpOrDown();
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fillUp(position - 1, temp.getTop() - dividerHeight);
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int childCount = getChildCount();
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childCount > 0) {
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 correctTooLow(childCount);
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tempIsSelected) {
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return temp;
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (above != null) {
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return above;
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return below;
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check if we have dragged the bottom of the list too high (we have pushed the
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top element off the top of the screen when we did not need to). Correct by sliding
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * everything back down.
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childCount Number of children
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooHigh(int childCount) {
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First see if the last item is visible. If it is not, it is OK for the
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // top of the list to be pushed up.
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lastPosition = mFirstPosition + childCount - 1;
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lastPosition == mItemCount - 1 && childCount > 0) {
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the last child ...
14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View lastChild = getChildAt(childCount - 1);
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its bottom edge
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the bottom edge of the last view is from the bottom of the
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int bottomOffset = end - lastBottom;
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View firstChild = getChildAt(0);
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too high, and 2) Either there are more rows above the
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // first row or the first row is scrolled off the top of the drawable area
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bottomOffset > 0 && (mFirstPosition > 0 || firstTop < mListPadding.top))  {
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition == 0) {
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Don't pull the top too far down
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop);
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Move everything down
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(bottomOffset);
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mFirstPosition > 0) {
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fill the gap that was opened above mFirstPosition with more rows, if
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // possible
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fillUp(mFirstPosition - 1, firstChild.getTop() - mDividerHeight);
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Close up the remaining gap
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    adjustViewsUpOrDown();
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check if we have dragged the bottom of the list too low (we have pushed the
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bottom element off the bottom of the screen when we did not need to). Correct by sliding
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * everything back up.
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childCount Number of children
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void correctTooLow(int childCount) {
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First see if the first item is visible. If it is not, it is OK for the
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bottom of the list to be pushed down.
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFirstPosition == 0 && childCount > 0) {
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the first child ...
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View firstChild = getChildAt(0);
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ... and its top edge
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstTop = firstChild.getTop();
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is top of our drawable area
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int start = mListPadding.top;
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is bottom of our drawable area
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int end = (mBottom - mTop) - mListPadding.bottom;
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is how far the top edge of the first view is from the top of the
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // drawable area
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topOffset = firstTop - start;
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View lastChild = getChildAt(childCount - 1);
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastBottom = lastChild.getBottom();
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastPosition = mFirstPosition + childCount - 1;
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we are 1) Too low, and 2) Either there are more rows below the
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // last row or the last row is scrolled off the bottom of the drawable area
15196198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy            if (topOffset > 0) {
15206198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                if (lastPosition < mItemCount - 1 || lastBottom > end)  {
15216198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    if (lastPosition == mItemCount - 1) {
15226198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Don't pull the bottom too far up
15236198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        topOffset = Math.min(topOffset, lastBottom - end);
15246198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    }
15256198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    // Move everything up
15266198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    offsetChildrenTopAndBottom(-topOffset);
15276198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    if (lastPosition < mItemCount - 1) {
15286198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Fill the gap that was opened below the last position with more rows, if
15296198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // possible
15306198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight);
15316198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        // Close up the remaining gap
15326198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                        adjustViewsUpOrDown();
15336198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    }
15346198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                } else if (lastPosition == mItemCount - 1) {
15356198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy                    adjustViewsUpOrDown();
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void layoutChildren() {
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean blockLayoutRequests = mBlockLayoutRequests;
1544d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette        if (blockLayoutRequests) {
15454df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return;
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1548d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette        mBlockLayoutRequests = true;
1549d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.layoutChildren();
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAdapter == null) {
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1561d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            final int childrenTop = mListPadding.top;
1562d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            final int childrenBottom = mBottom - mTop - mListPadding.bottom;
1563d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            final int childCount = getChildCount();
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1565ead0d4d8282b35a10bf8816cd99a62a8499d9031Romain Guy            int index = 0;
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int delta = 0;
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View sel;
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldSel = null;
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldFirst = null;
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View newSel = null;
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Remember stuff we will need down below
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mNextSelectedPosition - mFirstPosition;
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    newSel = getChildAt(index);
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previously selected view
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index = mSelectedPosition - mFirstPosition;
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index >= 0 && index < childCount) {
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    oldSel = getChildAt(index);
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the previous first child
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldFirst = getChildAt(0);
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mNextSelectedPosition >= 0) {
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delta = mNextSelectedPosition - mSelectedPosition;
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Caution: newSel might be null
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newSel = getChildAt(index + delta);
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean dataChanged = mDataChanged;
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleDataChanged();
16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Handle the empty set by removing all views that are visible
16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // and calling it a day
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount == 0) {
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resetList();
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
1617b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy            } else if (mItemCount != mAdapter.getCount()) {
1618b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy                throw new IllegalStateException("The content of the adapter has changed but "
1619b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy                        + "ListView did not receive a notification. Make sure the content of "
16207d8314db41707a98afb269a78e7bc90ac75d37fcAlan Viverette                        + "your adapter is not modified from a background thread, but only from "
16217d8314db41707a98afb269a78e7bc90ac75d37fcAlan Viverette                        + "the UI thread. Make sure your adapter calls notifyDataSetChanged() "
16227d8314db41707a98afb269a78e7bc90ac75d37fcAlan Viverette                        + "when its content changes. [in ListView(" + getId() + ", " + getClass()
16233940f2df36fbe6a712c88655fc78244977ebd0abOwen Lin                        + ") with Adapter(" + mAdapter.getClass() + ")]");
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(mNextSelectedPosition);
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16283e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
16293e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            View accessibilityFocusLayoutRestoreView = null;
16303e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            int accessibilityFocusPosition = INVALID_POSITION;
16313e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
16323e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Remember which child, if any, had accessibility focus. This must
16333e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // occur before recycling any views, since that will clear
16343e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // accessibility focus.
16353e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            final ViewRootImpl viewRootImpl = getViewRootImpl();
16363e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            if (viewRootImpl != null) {
16373e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
16383e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                if (focusHost != null) {
16393e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    final View focusChild = getAccessibilityFocusedChild(focusHost);
16403e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    if (focusChild != null) {
16413e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        if (!dataChanged || isDirectChildHeaderOrFooter(focusChild)
16423e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                                || focusChild.hasTransientState() || mAdapterHasStableIds) {
16433e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            // The views won't be changing, so try to maintain
16443e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            // focus on the current host and virtual view.
16453e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            accessibilityFocusLayoutRestoreView = focusHost;
16463e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            accessibilityFocusLayoutRestoreNode = viewRootImpl
16473e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                                    .getAccessibilityFocusedVirtualView();
16483e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        }
16493e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
16503e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // If all else fails, maintain focus at the same
16513e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // position.
16523e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        accessibilityFocusPosition = getPositionForView(focusChild);
16533e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    }
16543e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                }
1655b53c5f6b6f84518145c5cbfd3cc1729758fbc7c0Alan Viverette            }
1656b53c5f6b6f84518145c5cbfd3cc1729758fbc7c0Alan Viverette
16573e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            View focusLayoutRestoreDirectChild = null;
16583e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            View focusLayoutRestoreView = null;
16593e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
16603e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Take focus back to us temporarily to avoid the eventual call to
16613e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // clear focus when removing the focused child below from messing
16623e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // things up when ViewAncestor assigns focus back to someone else.
1663d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            final View focusedChild = getFocusedChild();
1664d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            if (focusedChild != null) {
16653e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // TODO: in some cases focusedChild.getParent() == null
16663e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
16673e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // We can remember the focused view to restore after re-layout
16683e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // if the data hasn't changed, or if the focused position is a
16693e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // header or footer.
16702b460d08dc3e670916c334bbc807961bf9d3e8d2Alan Viverette                if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)
16712b460d08dc3e670916c334bbc807961bf9d3e8d2Alan Viverette                        || focusedChild.hasTransientState() || mAdapterHasStableIds) {
16723e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    focusLayoutRestoreDirectChild = focusedChild;
16733e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    // Remember the specific view that had focus.
16743e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    focusLayoutRestoreView = findFocus();
16753e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    if (focusLayoutRestoreView != null) {
16763e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // Tell it we are going to mess with it.
167724df931e9e8c708fc605cd8e76a3ffd9ce5f6c77Yohei Yukawa                        focusLayoutRestoreView.dispatchStartTemporaryDetach();
16783e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    }
16793e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                }
16803e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                requestFocus();
1681d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette            }
1682d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pull all children into the RecycleBin.
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // These views will be reused if possible
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int firstPosition = mFirstPosition;
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final RecycleBin recycleBin = mRecycler;
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dataChanged) {
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < childCount; i++) {
1689079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                    recycleBin.addScrapView(getChildAt(i), firstPosition+i);
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                recycleBin.fillActiveViews(childCount, firstPosition);
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Clear out old views
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            detachAllViewsFromParent();
1697539ee8716b4f81260bab2e9f3dc5d88d81c99985Adam Powell            recycleBin.removeSkippedScrap();
16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (mLayoutMode) {
17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SET_SELECTION:
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newSel != null) {
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom);
17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sel = fillFromMiddle(childrenTop, childrenBottom);
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SYNC:
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillSpecific(mSyncPosition, mSpecificTop);
17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_BOTTOM:
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillUp(mItemCount - 1, childrenBottom);
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_FORCE_TOP:
17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition = 0;
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = fillFromTop(childrenTop);
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                adjustViewsUpOrDown();
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_SPECIFIC:
17200363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                final int selectedPosition = reconcileSelectedPosition();
17210363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                sel = fillSpecific(selectedPosition, mSpecificTop);
17220363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                /**
17230363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                 * When ListView is resized, FocusSelector requests an async selection for the
17240363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                 * previously focused item to make sure it is still visible. If the item is not
17250363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                 * selectable, it won't regain focus so instead we call FocusSelector
17260363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                 * to directly request focus on the view after it is visible.
17270363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                 */
17280363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                if (sel == null && mFocusSelector != null) {
17290363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                    final Runnable focusRunnable = mFocusSelector
17300363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                            .setupFocusIfValid(selectedPosition);
17310363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                    if (focusRunnable != null) {
17320363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                        post(focusRunnable);
17330363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                    }
17340363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                }
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LAYOUT_MOVE_SELECTION:
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (childCount == 0) {
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!mStackFromBottom) {
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int position = lookForSelectablePosition(0, true);
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        setSelectedPositionInt(position);
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillFromTop(childrenTop);
17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int position = lookForSelectablePosition(mItemCount - 1, false);
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        setSelectedPositionInt(position);
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillUp(mItemCount - 1, childrenBottom);
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mSelectedPosition,
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                oldSel == null ? childrenTop : oldSel.getTop());
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (mFirstPosition < mItemCount) {
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(mFirstPosition,
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                oldFirst == null ? childrenTop : oldFirst.getTop());
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sel = fillSpecific(0, childrenTop);
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Flush any cached views that did not get reused above
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recycleBin.scrapActiveViews();
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1767b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            // remove any header/footer that has been temp detached and not re-attached
1768b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            removeUnusedFixedViews(mHeaderViewInfos);
1769b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            removeUnusedFixedViews(mFooterViewInfos);
1770b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sel != null) {
17723e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // The current selected item should get focus if items are
17733e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // focusable.
17743e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
17753e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
17763e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            focusLayoutRestoreView != null &&
17773e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                            focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
17783e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    if (!focusWasTaken) {
17793e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // Selected item didn't take focus, but we still want to
17803e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // make sure something else outside of the selected view
17813e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        // has focus.
17823616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        final View focused = getFocusedChild();
17833616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        if (focused != null) {
17843616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                            focused.clearFocus();
17853616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                        }
1786079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                        positionSelector(INVALID_POSITION, sel);
17873e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    } else {
17883e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        sel.setSelected(false);
17893e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                        mSelectorRect.setEmpty();
17903616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    }
17913616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                } else {
1792079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                    positionSelector(INVALID_POSITION, sel);
17933616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                }
17943616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                mSelectedTop = sel.getTop();
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1796e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                final boolean inTouchMode = mTouchMode == TOUCH_MODE_TAP
1797e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                        || mTouchMode == TOUCH_MODE_DONE_WAITING;
1798e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                if (inTouchMode) {
1799e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // If the user's finger is down, select the motion position.
1800d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette                    final View child = getChildAt(mMotionPosition - mFirstPosition);
1801e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    if (child != null) {
1802d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette                        positionSelector(mMotionPosition, child);
1803d44696c4cfdda1e7e4e10a21b68f54ce5a4a459dAlan Viverette                    }
1804e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                } else if (mSelectorPosition != INVALID_POSITION) {
1805e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // If we had previously positioned the selector somewhere,
1806e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // put it back there. It might not match up with the data,
1807e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // but it's transitioning out so it's not a big deal.
1808e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    final View child = getChildAt(mSelectorPosition - mFirstPosition);
1809e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    if (child != null) {
1810e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                        positionSelector(mSelectorPosition, child);
1811e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    }
18123616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                } else {
1813e3c433aa457138425e514494e4d06590076a1d07Alan Viverette                    // Otherwise, clear selection.
18143616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    mSelectedTop = 0;
18153616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                    mSelectorRect.setEmpty();
18163616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy                }
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18183e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // Even if there is not selected position, we may need to
18193e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                // restore focus (i.e. something focusable in touch mode).
18203e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                if (hasFocus() && focusLayoutRestoreView != null) {
18213e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    focusLayoutRestoreView.requestFocus();
18223e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                }
18233e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            }
18246820751c0ad396328da39adfb3756ffc838c0cc7Alan Viverette
18253e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Attempt to restore accessibility focus, if necessary.
18262e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette            if (viewRootImpl != null) {
18272e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost();
18282e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                if (newAccessibilityFocusedView == null) {
18292e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                    if (accessibilityFocusLayoutRestoreView != null
18302e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) {
18312e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final AccessibilityNodeProvider provider =
18322e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
18332e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        if (accessibilityFocusLayoutRestoreNode != null && provider != null) {
18342e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
18352e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                    accessibilityFocusLayoutRestoreNode.getSourceNodeId());
18362e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            provider.performAction(virtualViewId,
18372e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
18382e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        } else {
18392e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
18402e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        }
18412e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                    } else if (accessibilityFocusPosition != INVALID_POSITION) {
18422e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        // Bound the position within the visible children.
18432e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final int position = MathUtils.constrain(
18442e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                accessibilityFocusPosition - mFirstPosition, 0,
18452e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                                getChildCount() - 1);
18462e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        final View restoreView = getChildAt(position);
18472e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        if (restoreView != null) {
18482e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                            restoreView.requestAccessibilityFocus();
18492e6fc8ca5696367a680656f73c1b9b95648eb6faAlan Viverette                        }
18506820751c0ad396328da39adfb3756ffc838c0cc7Alan Viverette                    }
185130ee76cf05f785bbf819b71954242c835c597ce1alanv                }
185230ee76cf05f785bbf819b71954242c835c597ce1alanv            }
185330ee76cf05f785bbf819b71954242c835c597ce1alanv
18543e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // Tell focus view we are done mucking with it, if it is still in
18553e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            // our view hierarchy.
18563e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            if (focusLayoutRestoreView != null
18573e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                    && focusLayoutRestoreView.getWindowToken() != null) {
185824df931e9e8c708fc605cd8e76a3ffd9ce5f6c77Yohei Yukawa                focusLayoutRestoreView.dispatchFinishTemporaryDetach();
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_NORMAL;
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataChanged = false;
1863161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell            if (mPositionScrollAfterLayout != null) {
1864161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell                post(mPositionScrollAfterLayout);
1865161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell                mPositionScrollAfterLayout = null;
1866161abf3d44feebb8462f7d0cbee81574d666234bAdam Powell            }
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNeedSync = false;
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(mSelectedPosition);
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateScrollIndicators();
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemCount > 0) {
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSelectionChanged();
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
18780363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            if (mFocusSelector != null) {
18790363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar                mFocusSelector.onLayoutComplete();
18800363341f6c2e224d0916bd113988b3b3318dbb55Yigit Boyar            }
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!blockLayoutRequests) {
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBlockLayoutRequests = false;
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1887b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    @Override
1888b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    boolean trackMotionScroll(int deltaY, int incrementalDeltaY) {
1889b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        final boolean result = super.trackMotionScroll(deltaY, incrementalDeltaY);
1890b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        removeUnusedFixedViews(mHeaderViewInfos);
1891b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        removeUnusedFixedViews(mFooterViewInfos);
1892b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        return result;
1893b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    }
1894b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar
1895b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    /**
1896b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar     * Header and Footer views are not scrapped / recycled like other views but they are still
1897b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar     * detached from the ViewGroup. After a layout operation, call this method to remove such views.
1898b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar     *
1899b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar     * @param infoList The info list to be traversed
1900b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar     */
1901b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    private void removeUnusedFixedViews(@Nullable List<FixedViewInfo> infoList) {
1902b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        if (infoList == null) {
1903b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            return;
1904b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        }
1905b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        for (int i = infoList.size() - 1; i >= 0; i--) {
1906b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            final FixedViewInfo fixedViewInfo = infoList.get(i);
1907b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            final View view = fixedViewInfo.view;
1908b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
1909b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            if (view.getParent() == null && lp != null && lp.recycledHeaderFooter) {
1910b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar                removeDetachedView(view, false);
1911b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar                lp.recycledHeaderFooter = false;
1912b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar            }
1913b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar
1914b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        }
1915b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar    }
1916b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19183e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette     * @param child a direct child of this list.
19193e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette     * @return Whether child is a header or footer view.
19203e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette     */
19213e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette    private boolean isDirectChildHeaderOrFooter(View child) {
19223e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        final ArrayList<FixedViewInfo> headers = mHeaderViewInfos;
19233e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        final int numHeaders = headers.size();
19243e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        for (int i = 0; i < numHeaders; i++) {
19253e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            if (child == headers.get(i).view) {
19263e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                return true;
19273e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            }
19283e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        }
19293e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
19303e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        final ArrayList<FixedViewInfo> footers = mFooterViewInfos;
19313e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        final int numFooters = footers.size();
19323e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        for (int i = 0; i < numFooters; i++) {
19333e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            if (child == footers.get(i).view) {
19343e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette                return true;
19353e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette            }
19363e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        }
19373e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
19383e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette        return false;
19393e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette    }
19403e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette
19413e14162fc655e7a0dae61318911f3e29c07d0bf0Alan Viverette    /**
194226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * Obtains the view and adds it to our list of children. The view can be
194326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * made fresh, converted from an unused view, or used as is if it was in
194426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * the recycle bin.
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
194626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param position logical position in the list
194726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param y top or bottom edge of the view to add
194826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param flow {@code true} to align top edge to y, {@code false} to align
194926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *             bottom edge to y
195026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param childrenLeft left edge where children should be positioned
195126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param selected {@code true} if the position is selected, {@code false}
195226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 otherwise
195326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @return the view that was added
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean selected) {
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mDataChanged) {
195826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            // Try to use an existing view for this position.
195926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            final View activeView = mRecycler.getActiveView(position);
196026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            if (activeView != null) {
196126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                // Found it. We're reusing an existing child, so it just needs
196226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                // to be positioned like a scrap view.
196326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                setupChild(activeView, position, y, flow, childrenLeft, selected, true);
196426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                return activeView;
19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
196826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // Make a new view for this position, or convert an unused view if
196926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // possible.
197026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final View child = obtainView(position, mIsScrap);
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
197226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // This needs to be positioned and measured.
197321875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return child;
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
197926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * Adds a view as a child and make sure it is measured (if necessary) and
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * positioned properly.
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
198226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param child the view to add
198326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param position the position of this child
198426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param y the y position relative to which this view will be positioned
198526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param flowDown {@code true} to align top edge to y, {@code false} to
198626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 align bottom edge to y
198726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param childrenLeft left edge where children should be positioned
198826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param selected {@code true} if the position is selected, {@code false}
198926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                 otherwise
199026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     * @param isAttachedToWindow {@code true} if the view is already attached
199126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                           to the window, e.g. whether it was reused, or
199226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette     *                           {@code false} otherwise
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
199526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            boolean selected, boolean isAttachedToWindow) {
19965fade8c69aef621312232ef0647502d7a63990b9Romain Guy        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "setupListItem");
19975fade8c69aef621312232ef0647502d7a63990b9Romain Guy
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean isSelected = selected && shouldShowSelector();
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean updateChildSelected = isSelected != child.isSelected();
20003616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final int mode = mTouchMode;
200126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL
200226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                && mMotionPosition == position;
20033616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        final boolean updateChildPressed = isPressed != child.isPressed();
200426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        final boolean needToMeasure = !isAttachedToWindow || updateChildSelected
200526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                || child.isLayoutRequested();
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
200726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // Respect layout params that are already in the view. Otherwise make
200826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // some up...
20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
2011aebd28f729fa28016d70551d0372ab7fcd56ee1aAdam Powell            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p.viewType = mAdapter.getItemViewType(position);
201492539d5c75922b430b7f69a14144b6a61045f1f4Alan Viverette        p.isEnabled = mAdapter.isEnabled(position);
20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
201626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // Set up view state before attaching the view, since we may need to
201726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // rely on the jumpDrawablesToCurrentState() call that occurs as part
201826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        // of view attachment.
20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (updateChildSelected) {
20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setSelected(isSelected);
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20233616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        if (updateChildPressed) {
20243616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy            child.setPressed(isPressed);
20253616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy        }
20263616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy
20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child instanceof Checkable) {
20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((Checkable) child).setChecked(mCheckStates.get(position));
2030d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn            } else if (getContext().getApplicationInfo().targetSdkVersion
2031d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn                    >= android.os.Build.VERSION_CODES.HONEYCOMB) {
2032d0fa371f276fde32d81c037006941bc93da0bb03Dianne Hackborn                child.setActivated(mCheckStates.get(position));
20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
203626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        if ((isAttachedToWindow && !p.forceAdd) || (p.recycledHeaderFooter
203726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
203826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            attachViewToParent(child, flowDown ? -1 : 0, p);
203926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette
204026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            // If the view was previously attached for a different position,
204126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            // then manually jump the drawables.
204226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            if (isAttachedToWindow
204326489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                    && (((AbsListView.LayoutParams) child.getLayoutParams()).scrappedFromPosition)
204426489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                            != position) {
204526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                child.jumpDrawablesToCurrentState();
204626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            }
204726489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        } else {
204826489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            p.forceAdd = false;
204926489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
205026489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette                p.recycledHeaderFooter = true;
205126489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            }
205226489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette            addViewInLayout(child, flowDown ? -1 : 0, p, true);
20534d827aafadde6b04b7223b527a3390635eb4dc92Yigit Boyar            // add view in layout will reset the RTL properties. We have to re-resolve them
20544d827aafadde6b04b7223b527a3390635eb4dc92Yigit Boyar            child.resolveRtlPropertiesIfNeeded();
205526489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette        }
205626489e1688633ee270ff1469d0df38c90bbdf674Alan Viverette
20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
20582ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            final int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListPadding.left + mListPadding.right, p.width);
20602ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            final int lpHeight = p.height;
20612ea329290cb470cfd8a846c63bc333fdb4f9ff1dAlan Viverette            final int childHeightSpec;
20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lpHeight > 0) {
20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2065d5dbf4b2a09c9cf2d17fa6af3fdf75d1fb774056Adam Powell                childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(),
2066b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski                        MeasureSpec.UNSPECIFIED);
20679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.measure(childWidthSpec, childHeightSpec);
20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupLayoutState(child);
20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int w = child.getMeasuredWidth();
20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int h = child.getMeasuredHeight();
20759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childTop = flowDown ? y : y - h;
20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToMeasure) {
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childRight = childrenLeft + w;
20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childBottom = childTop + h;
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.layout(childrenLeft, childTop, childRight, childBottom);
20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetLeftAndRight(childrenLeft - child.getLeft());
20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.offsetTopAndBottom(childTop - child.getTop());
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCachingStarted && !child.isDrawingCacheEnabled()) {
20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.setDrawingCacheEnabled(true);
20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2089079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn
20905fade8c69aef621312232ef0647502d7a63990b9Romain Guy        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean canAnimate() {
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.canAnimate() && mItemCount > 0;
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the currently selected item. If in touch mode, the item will not be selected
21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but it will still be positioned appropriately. If the specified selection position
21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is less than 0, then the item at position 0 will be selected.
21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Index (starting at 0) of the data item to be selected.
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelection(int position) {
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelectionFromTop(position, 0);
21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Makes the item at the supplied position selected.
2112f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron     *
21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position the position of the item to select
21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setSelectionInt(int position) {
21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setNextSelectedPositionInt(position);
2118f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        boolean awakeScrollbars = false;
2119f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
2120f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        final int selectedPosition = mSelectedPosition;
2121f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
2122f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (selectedPosition >= 0) {
2123f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            if (position == selectedPosition - 1) {
2124f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                awakeScrollbars = true;
2125f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            } else if (position == selectedPosition + 1) {
2126f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                awakeScrollbars = true;
2127f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            }
2128f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
2129f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
21301fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        if (mPositionScroller != null) {
21311fa179ef41c06bd19da70fd9bf95741238791940Adam Powell            mPositionScroller.stop();
21321fa179ef41c06bd19da70fd9bf95741238791940Adam Powell        }
21331fa179ef41c06bd19da70fd9bf95741238791940Adam Powell
21349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layoutChildren();
2135f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron
2136f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (awakeScrollbars) {
2137f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
2138f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        }
21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Find a position that can be selected (i.e., is not a separator).
21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position The starting position to look at.
21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param lookDown Whether to look down for other positions.
21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The next selectable position starting at position and then searching either up or
21479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         down. Returns {@link #INVALID_POSITION} if nothing can be found.
21489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int lookForSelectablePosition(int position, boolean lookDown) {
21519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ListAdapter adapter = mAdapter;
21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null || isInTouchMode()) {
21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return INVALID_POSITION;
21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = adapter.getCount();
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mAreAllItemsSelectable) {
21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lookDown) {
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = Math.max(0, position);
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (position < count && !adapter.isEnabled(position)) {
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    position++;
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                position = Math.min(position, count - 1);
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (position >= 0 && !adapter.isEnabled(position)) {
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    position--;
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2169af9c5ea240746de088549261a505895cbf4882edAlan Viverette        }
2170af9c5ea240746de088549261a505895cbf4882edAlan Viverette
2171af9c5ea240746de088549261a505895cbf4882edAlan Viverette        if (position < 0 || position >= count) {
2172af9c5ea240746de088549261a505895cbf4882edAlan Viverette            return INVALID_POSITION;
2173af9c5ea240746de088549261a505895cbf4882edAlan Viverette        }
2174af9c5ea240746de088549261a505895cbf4882edAlan Viverette
2175af9c5ea240746de088549261a505895cbf4882edAlan Viverette        return position;
2176af9c5ea240746de088549261a505895cbf4882edAlan Viverette    }
21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2178af9c5ea240746de088549261a505895cbf4882edAlan Viverette    /**
2179af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * Find a position that can be selected (i.e., is not a separator). If there
2180af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * are no selectable positions in the specified direction from the starting
2181af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * position, searches in the opposite direction from the starting position
2182af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * to the current position.
2183af9c5ea240746de088549261a505895cbf4882edAlan Viverette     *
2184af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * @param current the current position
2185af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * @param position the starting position
2186af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * @param lookDown whether to look down for other positions
2187af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * @return the next selectable position, or {@link #INVALID_POSITION} if
2188af9c5ea240746de088549261a505895cbf4882edAlan Viverette     *         nothing can be found
2189af9c5ea240746de088549261a505895cbf4882edAlan Viverette     */
2190af9c5ea240746de088549261a505895cbf4882edAlan Viverette    int lookForSelectablePositionAfter(int current, int position, boolean lookDown) {
2191af9c5ea240746de088549261a505895cbf4882edAlan Viverette        final ListAdapter adapter = mAdapter;
2192af9c5ea240746de088549261a505895cbf4882edAlan Viverette        if (adapter == null || isInTouchMode()) {
2193af9c5ea240746de088549261a505895cbf4882edAlan Viverette            return INVALID_POSITION;
2194af9c5ea240746de088549261a505895cbf4882edAlan Viverette        }
2195af9c5ea240746de088549261a505895cbf4882edAlan Viverette
2196af9c5ea240746de088549261a505895cbf4882edAlan Viverette        // First check after the starting position in the specified direction.
2197af9c5ea240746de088549261a505895cbf4882edAlan Viverette        final int after = lookForSelectablePosition(position, lookDown);
2198af9c5ea240746de088549261a505895cbf4882edAlan Viverette        if (after != INVALID_POSITION) {
2199af9c5ea240746de088549261a505895cbf4882edAlan Viverette            return after;
2200af9c5ea240746de088549261a505895cbf4882edAlan Viverette        }
2201af9c5ea240746de088549261a505895cbf4882edAlan Viverette
2202af9c5ea240746de088549261a505895cbf4882edAlan Viverette        // Then check between the starting position and the current position.
2203af9c5ea240746de088549261a505895cbf4882edAlan Viverette        final int count = adapter.getCount();
2204af9c5ea240746de088549261a505895cbf4882edAlan Viverette        current = MathUtils.constrain(current, -1, count - 1);
2205af9c5ea240746de088549261a505895cbf4882edAlan Viverette        if (lookDown) {
2206af9c5ea240746de088549261a505895cbf4882edAlan Viverette            position = Math.min(position - 1, count - 1);
2207af9c5ea240746de088549261a505895cbf4882edAlan Viverette            while ((position > current) && !adapter.isEnabled(position)) {
2208af9c5ea240746de088549261a505895cbf4882edAlan Viverette                position--;
2209af9c5ea240746de088549261a505895cbf4882edAlan Viverette            }
2210af9c5ea240746de088549261a505895cbf4882edAlan Viverette            if (position <= current) {
22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2214af9c5ea240746de088549261a505895cbf4882edAlan Viverette            position = Math.max(0, position + 1);
2215af9c5ea240746de088549261a505895cbf4882edAlan Viverette            while ((position < current) && !adapter.isEnabled(position)) {
2216af9c5ea240746de088549261a505895cbf4882edAlan Viverette                position++;
2217af9c5ea240746de088549261a505895cbf4882edAlan Viverette            }
2218af9c5ea240746de088549261a505895cbf4882edAlan Viverette            if (position >= current) {
22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2222af9c5ea240746de088549261a505895cbf4882edAlan Viverette
2223af9c5ea240746de088549261a505895cbf4882edAlan Viverette        return position;
22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * setSelectionAfterHeaderView set the selection to be the first list item
22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * after the header views.
22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setSelectionAfterHeaderView() {
2231744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan        final int count = getHeaderViewsCount();
22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNextSelectedPosition = 0;
22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
22359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAdapter != null) {
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(count);
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNextSelectedPosition = count;
22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayoutMode = LAYOUT_SET_SELECTION;
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Dispatch in the normal way
22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = super.dispatchKeyEvent(event);
22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!handled) {
22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If we didn't handle it...
22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View focused = getFocusedChild();
22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focused != null && event.getAction() == KeyEvent.ACTION_DOWN) {
22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... and our focused child didn't handle it
22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // ... give it to ourselves so we can scroll if necessary
22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = onKeyDown(event.getKeyCode(), event);
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
22609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, repeatCount, event);
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return commonKey(keyCode, 1, event);
22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean commonKey(int keyCode, int count, KeyEvent event) {
227831986b5b696c399b356c8819cb581441027bef36Adam Powell        if (mAdapter == null || !isAttachedToWindow()) {
22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDataChanged) {
22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layoutChildren();
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int action = event.getAction();
2288aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        if (KeyEvent.isConfirmKey(keyCode)
228926268f93ce110173ca7e0d904ca877c4b40d1944George Mount                && event.hasNoModifiers() && action != KeyEvent.ACTION_UP) {
2290aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            handled = resurrectSelectionIfNeeded();
2291aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
2292aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright                keyPressed();
2293aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright                handled = true;
2294aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright            }
2295aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        }
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2297aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright
2298aa1a94daaa59e98303fdeb1c3066b60a58755dffMichael Wright        if (!handled && action != KeyEvent.ACTION_UP) {
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (keyCode) {
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_UP:
23014e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23028d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded();
23038d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    if (!handled) {
23044e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        while (count-- > 0) {
23058d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            if (arrowScroll(FOCUS_UP)) {
23068d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                                handled = true;
23078d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            } else {
23088d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                                break;
23098d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            }
23104e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        }
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
23124e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
23138d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_DOWN:
23184e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23198d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded();
23208d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    if (!handled) {
23214e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        while (count-- > 0) {
23228d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            if (arrowScroll(FOCUS_DOWN)) {
23238d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                                handled = true;
23248d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            } else {
23258d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                                break;
23268d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                            }
23274e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        }
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
23294e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
23308d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_LEFT:
23354e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23364e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    handled = handleHorizontalFocusWithinListItem(View.FOCUS_LEFT);
23374e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
23394e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_RIGHT:
23414e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23424e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    handled = handleHorizontalFocusWithinListItem(View.FOCUS_RIGHT);
23434e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
23454e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23464e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case KeyEvent.KEYCODE_PAGE_UP:
23474e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23488d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
23494e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
23508d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
23514e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23524e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
23534e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23544e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case KeyEvent.KEYCODE_PAGE_DOWN:
23554e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23568d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
23574e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
23588d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
23594e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23604e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
23614e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23624e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case KeyEvent.KEYCODE_MOVE_HOME:
23634e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23648d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_UP);
23654e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23664e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
23674e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23684e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case KeyEvent.KEYCODE_MOVE_END:
23694e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                if (event.hasNoModifiers()) {
23708d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                    handled = resurrectSelectionIfNeeded() || fullScroll(FOCUS_DOWN);
23714e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23724e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
23734e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
23744e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            case KeyEvent.KEYCODE_TAB:
2375760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                // This creates an asymmetry in TAB navigation order. At some
2376760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                // point in the future we may decide that it's preferable to
2377760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                // force the list selection to the top or bottom when receiving
2378760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                // TAB focus from another widget, but for now this is adequate.
2379760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                if (event.hasNoModifiers()) {
2380760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                    handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_DOWN);
2381760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
2382760a2d845ac632985d5b62b5364caa441bd92ae2Alan Viverette                    handled = resurrectSelectionIfNeeded() || arrowScroll(FOCUS_UP);
23834e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
23844e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                break;
23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23888d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        if (handled) {
23898d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            return true;
23909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23928d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        if (sendToTextFilter(keyCode, count, event)) {
23939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
23948d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        }
23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23968d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown        switch (action) {
23978d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_DOWN:
23988d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyDown(keyCode, event);
23999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24008d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_UP:
24018d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyUp(keyCode, event);
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24038d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            case KeyEvent.ACTION_MULTIPLE:
24048d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return super.onKeyMultiple(keyCode, count, event);
24058d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown
24068d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown            default: // shouldn't happen
24078d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown                return false;
24089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls up or down by the number of items currently present on screen.
24139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
24149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
24159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
24169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean pageScroll(int direction) {
2418af9c5ea240746de088549261a505895cbf4882edAlan Viverette        final int nextPage;
2419af9c5ea240746de088549261a505895cbf4882edAlan Viverette        final boolean down;
24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
24229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1);
2423af9c5ea240746de088549261a505895cbf4882edAlan Viverette            down = false;
24249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
24259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1);
24269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            down = true;
2427af9c5ea240746de088549261a505895cbf4882edAlan Viverette        } else {
2428af9c5ea240746de088549261a505895cbf4882edAlan Viverette            return false;
24299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextPage >= 0) {
2432af9c5ea240746de088549261a505895cbf4882edAlan Viverette            final int position = lookForSelectablePositionAfter(mSelectedPosition, nextPage, down);
24339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position >= 0) {
24349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLayoutMode = LAYOUT_SPECIFIC;
24359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSpecificTop = mPaddingTop + getVerticalFadingEdgeLength();
24369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2437af9c5ea240746de088549261a505895cbf4882edAlan Viverette                if (down && (position > (mItemCount - getChildCount()))) {
24389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_BOTTOM;
24399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2441af9c5ea240746de088549261a505895cbf4882edAlan Viverette                if (!down && (position < getChildCount())) {
24429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_TOP;
24439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelectionInt(position);
24469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invokeOnItemScrollListener();
2447f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                if (!awakenScrollBars()) {
2448f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                    invalidate();
2449f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                }
24509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
24529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
24569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2459af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * Go to the last or first item if possible (not worrying about panning
2460af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * across or navigating within the internal focus of the currently selected
2461af9c5ea240746de088549261a505895cbf4882edAlan Viverette     * item.)
24629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
24639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
24649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
24659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
24669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean fullScroll(int direction) {
24679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean moved = false;
24689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == FOCUS_UP) {
24699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition != 0) {
2470af9c5ea240746de088549261a505895cbf4882edAlan Viverette                final int position = lookForSelectablePositionAfter(mSelectedPosition, 0, true);
24719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position >= 0) {
24729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_TOP;
24739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(position);
24749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    invokeOnItemScrollListener();
24759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                moved = true;
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (direction == FOCUS_DOWN) {
2479af9c5ea240746de088549261a505895cbf4882edAlan Viverette            final int lastItem = (mItemCount - 1);
2480af9c5ea240746de088549261a505895cbf4882edAlan Viverette            if (mSelectedPosition < lastItem) {
2481af9c5ea240746de088549261a505895cbf4882edAlan Viverette                final int position = lookForSelectablePositionAfter(
2482af9c5ea240746de088549261a505895cbf4882edAlan Viverette                        mSelectedPosition, lastItem, false);
24839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position >= 0) {
24849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLayoutMode = LAYOUT_FORCE_BOTTOM;
24859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setSelectionInt(position);
24869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    invokeOnItemScrollListener();
24879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                moved = true;
24899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2492f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron        if (moved && !awakenScrollBars()) {
2493f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            awakenScrollBars();
24949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invalidate();
24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return moved;
24989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * To avoid horizontal focus searches changing the selected item, we
25029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * manually focus search within the selected item (as applicable), and
25039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * prevent focus from jumping to something within another item.
25049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction one of {View.FOCUS_LEFT, View.FOCUS_RIGHT}
25059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether this consumes the key event.
25069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean handleHorizontalFocusWithinListItem(int direction) {
25089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT)  {
2509304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy            throw new IllegalArgumentException("direction must be one of"
2510304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                    + " {View.FOCUS_LEFT, View.FOCUS_RIGHT}");
25119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemsCanFocus && numChildren > 0 && mSelectedPosition != INVALID_POSITION) {
25159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View selectedView = getSelectedView();
2516304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy            if (selectedView != null && selectedView.hasFocus() &&
2517304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                    selectedView instanceof ViewGroup) {
2518304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy
25199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View currentFocus = selectedView.findFocus();
25209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View nextFocus = FocusFinder.getInstance().findNextFocus(
2521304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                        (ViewGroup) selectedView, currentFocus, direction);
25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (nextFocus != null) {
25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // do the math to get interesting rect in next focus' coordinates
2524827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    Rect focusedRect = mTempRect;
2525827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    if (currentFocus != null) {
2526827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                        currentFocus.getFocusedRect(focusedRect);
2527827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                        offsetDescendantRectToMyCoords(currentFocus, focusedRect);
2528827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                        offsetRectIntoDescendantCoords(nextFocus, focusedRect);
2529827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    } else {
2530827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                        focusedRect = null;
2531827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    }
2532827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    if (nextFocus.requestFocus(direction, focusedRect)) {
25339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return true;
25349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
25359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are blocking the key from being handled (by returning true)
25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // if the global result is going to be some other view within this
25389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // list.  this is to acheive the overall goal of having
25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // horizontal d-pad navigation remain in the current item.
2540304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                final View globalNextFocus = FocusFinder.getInstance().findNextFocus(
2541304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy                        (ViewGroup) getRootView(), currentFocus, direction);
25429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (globalNextFocus != null) {
25439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return isViewAncestorOf(globalNextFocus, this);
25449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
25489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scrolls to the next or previous item if possible.
25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN}
25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether selection was moved
25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean arrowScroll(int direction) {
25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
25599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInLayout = true;
25609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean handled = arrowScrollImpl(direction);
25619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (handled) {
25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
25639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return handled;
25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInLayout = false;
25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25712a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     * Used by {@link #arrowScrollImpl(int)} to help determine the next selected position
257249fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim     * to move to. This return a position in the direction given if the selected item
257349fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim     * is fully visible.
25742a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     *
257549fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim     * @param selectedView Current selected view to move from
25762a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     * @param selectedPos Current selected position to move from
25772a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     * @param direction Direction to move in
25782a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     * @return Desired selected position after moving in the given direction
25792a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell     */
258049fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim    private final int nextSelectedPositionForDirection(
258149fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            View selectedView, int selectedPos, int direction) {
25822a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        int nextSelected;
258349fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim
25842a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        if (direction == View.FOCUS_DOWN) {
258549fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            final int listBottom = getHeight() - mListPadding.bottom;
258649fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            if (selectedView != null && selectedView.getBottom() <= listBottom) {
258749fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                nextSelected = selectedPos != INVALID_POSITION && selectedPos >= mFirstPosition ?
258849fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                        selectedPos + 1 :
258949fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                        mFirstPosition;
259049fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            } else {
259149fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                return INVALID_POSITION;
259249fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            }
25932a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        } else {
259449fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            final int listTop = mListPadding.top;
259549fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            if (selectedView != null && selectedView.getTop() >= listTop) {
259649fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                final int lastPos = mFirstPosition + getChildCount() - 1;
259749fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                nextSelected = selectedPos != INVALID_POSITION && selectedPos <= lastPos ?
259849fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                        selectedPos - 1 :
259949fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                        lastPos;
260049fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            } else {
260149fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim                return INVALID_POSITION;
260249fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim            }
26032a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        }
26042a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell
26052a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        if (nextSelected < 0 || nextSelected >= mAdapter.getCount()) {
26062a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell            return INVALID_POSITION;
26072a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        }
26082a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell        return lookForSelectablePosition(nextSelected, direction == View.FOCUS_DOWN);
26092a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell    }
26102a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell
26112a93911b87f7aac6d0dcceabc5983e81befeeda5Adam Powell    /**
26129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Handle an arrow scroll going up or down.  Take into account whether items are selectable,
26139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * whether there are focusable items etc.
26149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
26159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction Either {@link android.view.View#FOCUS_UP} or {@link android.view.View#FOCUS_DOWN}.
26169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether any scrolling, selection or focus change occured.
26179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
26189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean arrowScrollImpl(int direction) {
26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (getChildCount() <= 0) {
26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View selectedView = getSelectedView();
2624079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        int selectedPos = mSelectedPosition;
26259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
262649fc4dcd4c0d88b74084d6b2a2d843ad17b8a1ebJaewan Kim        int nextSelectedPosition = nextSelectedPositionForDirection(selectedView, selectedPos, direction);
26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int amountToScroll = amountToScroll(direction, nextSelectedPosition);
26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if we are moving focus, we may OVERRIDE the default behavior
26309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrowScrollFocusResult focusResult = mItemsCanFocus ? arrowScrollFocused(direction) : null;
26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (focusResult != null) {
26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextSelectedPosition = focusResult.getSelectedPosition();
26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            amountToScroll = focusResult.getAmountToScroll();
26349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean needToRedraw = focusResult != null;
26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextSelectedPosition != INVALID_POSITION) {
26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handleNewSelectionChange(selectedView, direction, nextSelectedPosition, focusResult != null);
26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(nextSelectedPosition);
26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setNextSelectedPositionInt(nextSelectedPosition);
26419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selectedView = getSelectedView();
2642079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn            selectedPos = nextSelectedPosition;
26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mItemsCanFocus && focusResult == null) {
26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // there was no new view found to take focus, make sure we
26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // don't leave focus with the old selection
26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View focused = getFocusedChild();
26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (focused != null) {
26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    focused.clearFocus();
26499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            needToRedraw = true;
26529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkSelectionChanged();
26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (amountToScroll > 0) {
26569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListItemsBy((direction == View.FOCUS_UP) ? amountToScroll : -amountToScroll);
26579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            needToRedraw = true;
26589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if we didn't find a new focusable, make sure any existing focused
26619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // item that was panned off screen gives up focus.
26629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemsCanFocus && (focusResult == null)
26639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && selectedView != null && selectedView.hasFocus()) {
26649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View focused = selectedView.findFocus();
2665827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto            if (focused != null) {
2666827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) {
2667827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                    focused.clearFocus();
2668827bb445d1402c8e7af1dabd3312d651b2522e5bKenji Sugimoto                }
26699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if  the current selection is panned off, we need to remove the selection
26739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nextSelectedPosition == INVALID_POSITION && selectedView != null
26749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && !isViewAncestorOf(selectedView, this)) {
26759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selectedView = null;
26769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            hideSelector();
26779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // but we don't want to set the ressurect position (that would make subsequent
26799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // unhandled key events bring back the item we just scrolled off!)
26809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResurrectToPosition = INVALID_POSITION;
26819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needToRedraw) {
26849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selectedView != null) {
2685de399397947c5379c61a1003c017b96accbbf545Alan Viverette                positionSelectorLikeFocus(selectedPos, selectedView);
26869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSelectedTop = selectedView.getTop();
26879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2688f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            if (!awakenScrollBars()) {
2689f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron                invalidate();
2690f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron            }
26919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            invokeOnItemScrollListener();
26929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
26939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
26969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
26999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When selection changes, it is possible that the previously selected or the
27009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * next selected item will change its size.  If so, we need to offset some folks,
27019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and re-layout the items as appropriate.
27029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
27039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param selectedView The currently selected view (before changing selection).
27049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   should be <code>null</code> if there was no previous selection.
27059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction Either {@link android.view.View#FOCUS_UP} or
27069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
27079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newSelectedPosition The position of the next selection.
27089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocusAssigned whether new focus was assigned.  This matters because
27099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        when something has focus, we don't want to show selection (ugh).
27109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleNewSelectionChange(View selectedView, int direction, int newSelectedPosition,
27129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean newFocusAssigned) {
27139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newSelectedPosition == INVALID_POSITION) {
27149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("newSelectedPosition needs to be valid");
27159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // whether or not we are moving down or up, we want to preserve the
27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // top of whatever view is on top:
27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // - moving down: the view that had selection
27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // - moving up: the view that is getting selection
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View topView;
27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View bottomView;
27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int topViewIndex, bottomViewIndex;
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean topSelected = false;
27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int selectedIndex = mSelectedPosition - mFirstPosition;
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int nextSelectedIndex = newSelectedPosition - mFirstPosition;
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_UP) {
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topViewIndex = nextSelectedIndex;
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomViewIndex = selectedIndex;
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView = getChildAt(topViewIndex);
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView = selectedView;
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topSelected = true;
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topViewIndex = selectedIndex;
27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomViewIndex = nextSelectedIndex;
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView = selectedView;
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView = getChildAt(bottomViewIndex);
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // start with top view: is it changing size?
27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (topView != null) {
27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            topView.setSelected(!newFocusAssigned && topSelected);
27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureAndAdjustDown(topView, topViewIndex, numChildren);
27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // is the bottom view changing size?
27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (bottomView != null) {
27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottomView.setSelected(!newFocusAssigned && !topSelected);
27519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            measureAndAdjustDown(bottomView, bottomViewIndex, numChildren);
27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Re-measure a child, and if its height changes, lay it out preserving its
27579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top, and adjust the children below it appropriately.
27589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child
27599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childIndex The view group index of the child.
27609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numChildren The number of children in the view group.
27619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void measureAndAdjustDown(View child, int childIndex, int numChildren) {
27639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int oldHeight = child.getHeight();
27649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        measureItem(child);
27659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (child.getMeasuredHeight() != oldHeight) {
27669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // lay out the view, preserving its top
27679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            relayoutMeasuredItem(child);
27689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // adjust views below appropriately
27709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int heightDelta = child.getMeasuredHeight() - oldHeight;
27719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = childIndex + 1; i < numChildren; i++) {
27729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getChildAt(i).offsetTopAndBottom(heightDelta);
27739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
27789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Measure a particular list child.
27799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: unify with setUpChild.
27809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child.
27819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
27829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void measureItem(View child) {
27839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ViewGroup.LayoutParams p = child.getLayoutParams();
27849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
27859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p = new ViewGroup.LayoutParams(
2786980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy                    ViewGroup.LayoutParams.MATCH_PARENT,
27879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ViewGroup.LayoutParams.WRAP_CONTENT);
27889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
27919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListPadding.left + mListPadding.right, p.width);
27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lpHeight = p.height;
27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeightSpec;
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lpHeight > 0) {
27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2797d5dbf4b2a09c9cf2d17fa6af3fdf75d1fb774056Adam Powell            childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(),
2798b6824bf58a0cd34395993fa204217e8e246de6fbFilip Gruszczynski                    MeasureSpec.UNSPECIFIED);
27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.measure(childWidthSpec, childHeightSpec);
28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Layout a child that has been measured, preserving its top position.
28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: unify with setUpChild.
28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The child.
28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void relayoutMeasuredItem(View child) {
28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int w = child.getMeasuredWidth();
28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int h = child.getMeasuredHeight();
28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childLeft = mListPadding.left;
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childRight = childLeft + w;
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childTop = child.getTop();
28149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childBottom = childTop + h;
28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.layout(childLeft, childTop, childRight, childBottom);
28169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
28199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to preview next items when arrow srolling.
28209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
28219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getArrowScrollPreviewLength() {
28229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Math.max(MIN_SCROLL_PREVIEW_PIXELS, getVerticalFadingEdgeLength());
28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
28269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine how much we need to scroll in order to get the next selected view
28279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * visible, with a fading edge showing below as applicable.  The amount is
28289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * capped at {@link #getMaxScrollAmount()} .
28299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
28309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param nextSelectedPosition The position of the next selection, or
28339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link #INVALID_POSITION} if there is no next selectable position
28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to scroll. Note: this is always positive!  Direction
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         needs to be taken into account when actually scrolling.
28369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int amountToScroll(int direction, int nextSelectedPosition) {
28389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = getHeight() - mListPadding.bottom;
28399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mListPadding.top;
28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28411ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho        int numChildren = getChildCount();
28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_DOWN) {
28449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int indexToMakeVisible = numChildren - 1;
28459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION) {
28469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
28479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28481ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho            while (numChildren <= indexToMakeVisible) {
28491ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                // Child to view is not attached yet.
28501ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                addViewBelow(getChildAt(numChildren - 1), mFirstPosition + numChildren - 1);
28511ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                numChildren++;
28521ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho            }
28539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
28549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
28559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int goalBottom = listBottom;
28579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (positionToMakeVisible < mItemCount - 1) {
28589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goalBottom -= getArrowScrollPreviewLength();
28599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (viewToMakeVisible.getBottom() <= goalBottom) {
28629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item is fully visible.
28639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION
28679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && (goalBottom - viewToMakeVisible.getTop()) >= getMaxScrollAmount()) {
28689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item already has enough of it visible, changing selection is good enough
28699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
28709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amountToScroll = (viewToMakeVisible.getBottom() - goalBottom);
28739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mFirstPosition + numChildren) == mItemCount) {
28759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // last is last in list -> make sure we don't scroll past it
28769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int max = getChildAt(numChildren - 1).getBottom() - listBottom;
28779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = Math.min(amountToScroll, max);
28789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Math.min(amountToScroll, getMaxScrollAmount());
28819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
28829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int indexToMakeVisible = 0;
28839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION) {
28849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
28859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28861ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho            while (indexToMakeVisible < 0) {
28871ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                // Child to view is not attached yet.
28881ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                addViewAbove(getChildAt(0), mFirstPosition);
28891ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                mFirstPosition--;
28901ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
28911ad11b9c6c7b555c27b917f26ecc08446f589284Justin Ho            }
28929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
28939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
28949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int goalTop = listTop;
28959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (positionToMakeVisible > 0) {
28969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goalTop += getArrowScrollPreviewLength();
28979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (viewToMakeVisible.getTop() >= goalTop) {
28999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item is fully visible.
29009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
29019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextSelectedPosition != INVALID_POSITION &&
29049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (viewToMakeVisible.getBottom() - goalTop) >= getMaxScrollAmount()) {
29059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // item already has enough of it visible, changing selection is good enough
29069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
29079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amountToScroll = (goalTop - viewToMakeVisible.getTop());
29109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mFirstPosition == 0) {
29119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // first is first in list -> make sure we don't scroll past it
29129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int max = listTop - getChildAt(0).getTop();
29139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = Math.min(amountToScroll,  max);
29149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Math.min(amountToScroll, getMaxScrollAmount());
29169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Holds results of focus aware arrow scrolling.
29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private class ArrowScrollFocusResult {
29239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mSelectedPosition;
29249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mAmountToScroll;
29259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * How {@link android.widget.ListView#arrowScrollFocused} returns its values.
29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void populate(int selectedPosition, int amountToScroll) {
29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSelectedPosition = selectedPosition;
29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAmountToScroll = amountToScroll;
29329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getSelectedPosition() {
29359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSelectedPosition;
29369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getAmountToScroll() {
29399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAmountToScroll;
29409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
29459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
29469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The position of the next selectable position of the views that
29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         are currently visible, taking into account the fact that there might
29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         be no selection.  Returns {@link #INVALID_POSITION} if there is no
29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         selectable view on screen in the given direction.
29509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int lookForSelectablePositionOnScreen(int direction) {
29529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int firstPosition = mFirstPosition;
29539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_DOWN) {
29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int startPos = (mSelectedPosition != INVALID_POSITION) ?
29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSelectedPosition + 1 :
29569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    firstPosition;
29579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos >= mAdapter.getCount()) {
29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
29599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos < firstPosition) {
29619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startPos = firstPosition;
29629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int lastVisiblePos = getLastVisiblePosition();
29659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ListAdapter adapter = getAdapter();
29669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int pos = startPos; pos <= lastVisiblePos; pos++) {
29679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (adapter.isEnabled(pos)
29689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
29699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return pos;
29709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
29739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int last = firstPosition + getChildCount() - 1;
29749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int startPos = (mSelectedPosition != INVALID_POSITION) ?
29759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSelectedPosition - 1 :
29769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    firstPosition + getChildCount() - 1;
29775d9d03a0234faa3cffd11502f973057045cafe82Dianne Hackborn            if (startPos < 0 || startPos >= mAdapter.getCount()) {
29789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return INVALID_POSITION;
29799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (startPos > last) {
29819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startPos = last;
29829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ListAdapter adapter = getAdapter();
29859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int pos = startPos; pos >= firstPosition; pos--) {
29869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (adapter.isEnabled(pos)
29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return pos;
29899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_POSITION;
29939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Do an arrow scroll based on focus searching.  If a new view is
29979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * given focus, return the selection delta and amount to scroll via
29989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * an {@link ArrowScrollFocusResult}, otherwise, return null.
29999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
30009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
30019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
30029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The result if focus has changed, or <code>null</code>.
30039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrowScrollFocusResult arrowScrollFocused(final int direction) {
30059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View selectedView = getSelectedView();
30069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View newFocus;
30079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectedView != null && selectedView.hasFocus()) {
30089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View oldFocus = selectedView.findFocus();
30099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction);
30109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
30119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == View.FOCUS_DOWN) {
30129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final boolean topFadingEdgeShowing = (mFirstPosition > 0);
30139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int listTop = mListPadding.top +
30149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (topFadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
30159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int ySearchPoint =
30169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (selectedView != null && selectedView.getTop() > listTop) ?
30179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                selectedView.getTop() :
30189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                listTop;
30199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTempRect.set(0, ySearchPoint, 0, ySearchPoint);
30209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
30219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final boolean bottomFadingEdgeShowing =
30229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (mFirstPosition + getChildCount() - 1) < mItemCount;
30239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int listBottom = getHeight() - mListPadding.bottom -
30249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (bottomFadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
30259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int ySearchPoint =
30269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (selectedView != null && selectedView.getBottom() < listBottom) ?
30279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                selectedView.getBottom() :
30289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                listBottom;
30299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTempRect.set(0, ySearchPoint, 0, ySearchPoint);
30309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newFocus = FocusFinder.getInstance().findNextFocusFromRect(this, mTempRect, direction);
30329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newFocus != null) {
30359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int positionOfNewFocus = positionOfNewFocus(newFocus);
30369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if the focus change is in a different new position, make sure
30389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we aren't jumping over another selectable position
30399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSelectedPosition != INVALID_POSITION && positionOfNewFocus != mSelectedPosition) {
30409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int selectablePosition = lookForSelectablePositionOnScreen(direction);
30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (selectablePosition != INVALID_POSITION &&
30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((direction == View.FOCUS_DOWN && selectablePosition < positionOfNewFocus) ||
30439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (direction == View.FOCUS_UP && selectablePosition > positionOfNewFocus))) {
30449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return null;
30459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
30469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int focusScroll = amountToScrollToNewFocus(direction, newFocus, positionOfNewFocus);
30499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int maxScrollAmount = getMaxScrollAmount();
30519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (focusScroll < maxScrollAmount) {
30529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // not moving too far, safe to give next view focus
30539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newFocus.requestFocus(direction);
30549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArrowScrollFocusResult.populate(positionOfNewFocus, focusScroll);
30559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mArrowScrollFocusResult;
30569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (distanceToView(newFocus) < maxScrollAmount){
30579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Case to consider:
30589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // too far to get entire next focusable on screen, but by going
30599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // max scroll amount, we are getting it at least partially in view,
30609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // so give it focus and scroll the max ammount.
30619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newFocus.requestFocus(direction);
30629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArrowScrollFocusResult.populate(positionOfNewFocus, maxScrollAmount);
30639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mArrowScrollFocusResult;
30649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
30679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocus The view that would have focus.
30719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the position that contains newFocus
30729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int positionOfNewFocus(View newFocus) {
30749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numChildren = getChildCount();
30759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numChildren; i++) {
30769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View child = getChildAt(i);
30779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isViewAncestorOf(newFocus, child)) {
30789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mFirstPosition + i;
30799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw new IllegalArgumentException("newFocus is not a child of any of the"
30829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + " children of the list!");
30839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return true if child is an ancestor of parent, (or equal to the parent).
30879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isViewAncestorOf(View child, View parent) {
30899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (child == parent) {
30909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
30919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ViewParent theParent = child.getParent();
30949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (theParent instanceof ViewGroup) && isViewAncestorOf((View) theParent, parent);
30959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine how much we need to scroll in order to get newFocus in view.
30999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction either {@link android.view.View#FOCUS_UP} or
31009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        {@link android.view.View#FOCUS_DOWN}.
31019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newFocus The view that would take focus.
31029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param positionOfNewFocus The position of the list item containing newFocus
31039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to scroll.  Note: this is always positive!  Direction
31049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   needs to be taken into account when actually scrolling.
31059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int amountToScrollToNewFocus(int direction, View newFocus, int positionOfNewFocus) {
31079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int amountToScroll = 0;
31089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        newFocus.getDrawingRect(mTempRect);
31099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetDescendantRectToMyCoords(newFocus, mTempRect);
31109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction == View.FOCUS_UP) {
31119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTempRect.top < mListPadding.top) {
31129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = mListPadding.top - mTempRect.top;
31139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (positionOfNewFocus > 0) {
31149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    amountToScroll += getArrowScrollPreviewLength();
31159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
31189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int listBottom = getHeight() - mListPadding.bottom;
31199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTempRect.bottom > listBottom) {
31209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amountToScroll = mTempRect.bottom - listBottom;
31219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (positionOfNewFocus < mItemCount - 1) {
31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    amountToScroll += getArrowScrollPreviewLength();
31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return amountToScroll;
31279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determine the distance to the nearest edge of a view in a particular
3131fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * direction.
3132fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *
31339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param descendant A descendant of this list.
31349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The distance, or 0 if the nearest edge is already on screen.
31359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int distanceToView(View descendant) {
31379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int distance = 0;
31389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        descendant.getDrawingRect(mTempRect);
31399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetDescendantRectToMyCoords(descendant, mTempRect);
31409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = mBottom - mTop - mListPadding.bottom;
31419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTempRect.bottom < mListPadding.top) {
31429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            distance = mListPadding.top - mTempRect.bottom;
31439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mTempRect.top > listBottom) {
31449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            distance = mTempRect.top - listBottom;
31459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return distance;
31479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Scroll the children by amount, adding a view at the end and removing
31529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * views that fall off as necessary.
31539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
31549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param amount The amount (positive or negative) to scroll.
31559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void scrollListItemsBy(int amount) {
31579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offsetChildrenTopAndBottom(amount);
31589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listBottom = getHeight() - mListPadding.bottom;
31609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int listTop = mListPadding.top;
3161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final AbsListView.RecycleBin recycleBin = mRecycler;
31629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (amount < 0) {
31649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // shifted items up
31659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may need to pan views into the bottom space
31679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numChildren = getChildCount();
31689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View last = getChildAt(numChildren - 1);
31699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (last.getBottom() < listBottom) {
31709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int lastVisiblePosition = mFirstPosition + numChildren - 1;
31719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lastVisiblePosition < mItemCount - 1) {
31729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    last = addViewBelow(last, lastVisiblePosition);
31739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    numChildren++;
31749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
31759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
31769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may have brought in the last child of the list that is skinnier
31809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // than the fading edge, thereby leaving space at the end.  need
31819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to shift back
31829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (last.getBottom() < listBottom) {
31839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(listBottom - last.getBottom());
31849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // top views may be panned off screen
31879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View first = getChildAt(0);
31889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (first.getBottom() < listTop) {
3189c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();
3190c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
3191079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                    recycleBin.addScrapView(first, mFirstPosition);
3192c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
3193158d6b70ac2f0c8fd7dafe0f865112090fb31699Mattias Niklewski                detachViewFromParent(first);
31949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                first = getChildAt(0);
31959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition++;
31969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // shifted items down
31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View first = getChildAt(0);
32009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may need to pan views into top
32029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((first.getTop() > listTop) && (mFirstPosition > 0)) {
32039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                first = addViewAbove(first, mFirstPosition);
32049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFirstPosition--;
32059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // may have brought the very first child of the list in too far and
32089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to shift it back
32099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (first.getTop() > listTop) {
32109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetChildrenTopAndBottom(listTop - first.getTop());
32119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastIndex = getChildCount() - 1;
32149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View last = getChildAt(lastIndex);
32159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // bottom view may be panned off screen
32179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (last.getTop() > listBottom) {
3218c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();
3219c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
3220079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                    recycleBin.addScrapView(last, mFirstPosition+lastIndex);
3221c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
3222158d6b70ac2f0c8fd7dafe0f865112090fb31699Mattias Niklewski                detachViewFromParent(last);
32239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                last = getChildAt(--lastIndex);
32249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32269afbf9ceb7ddad0e4aee28c6c6393800338af6f9Yigit Boyar        recycleBin.fullyDetachScrapViews();
3227b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        removeUnusedFixedViews(mHeaderViewInfos);
3228b742b87a6b098ff5c354e421c0a89fb32346c244Yigit Boyar        removeUnusedFixedViews(mFooterViewInfos);
32299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View addViewAbove(View theView, int position) {
32329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int abovePosition = position - 1;
323321875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        View view = obtainView(abovePosition, mIsScrap);
32349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int edgeOfNewChild = theView.getTop() - mDividerHeight;
323521875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left,
323621875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy                false, mIsScrap[0]);
32379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view;
32389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View addViewBelow(View theView, int position) {
32419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int belowPosition = position + 1;
324221875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        View view = obtainView(belowPosition, mIsScrap);
32439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int edgeOfNewChild = theView.getBottom() + mDividerHeight;
324421875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy        setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left,
324521875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy                false, mIsScrap[0]);
32469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view;
32479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
32509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Indicates that the views created by the ListAdapter can contain focusable
32519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * items.
32529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
32539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param itemsCanFocus true if items can get focus, false otherwise
32549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setItemsCanFocus(boolean itemsCanFocus) {
32569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemsCanFocus = itemsCanFocus;
32579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!itemsCanFocus) {
32589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
32599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
32639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the views created by the ListAdapter can contain focusable
32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * items.
32659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getItemsCanFocus() {
32679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItemsCanFocus;
32689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
327124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    public boolean isOpaque() {
32727840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase        boolean retValue = (mCachingActive && mIsCacheColorOpaque && mDividerIsOpaque &&
32738f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                hasOpaqueScrollbars()) || super.isOpaque();
32747840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase        if (retValue) {
32757840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            // only return true if the list items cover the entire area of the view
32763ba8f5d675831647e45d0ce11507c85dfb5f753bAdam Powell            final int listTop = mListPadding != null ? mListPadding.top : mPaddingTop;
32777840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            View first = getChildAt(0);
32787840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            if (first == null || first.getTop() > listTop) {
32797840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase                return false;
32807840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            }
32813ba8f5d675831647e45d0ce11507c85dfb5f753bAdam Powell            final int listBottom = getHeight() -
32823ba8f5d675831647e45d0ce11507c85dfb5f753bAdam Powell                    (mListPadding != null ? mListPadding.bottom : mPaddingBottom);
32837840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            View last = getChildAt(getChildCount() - 1);
32847840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            if (last == null || last.getBottom() < listBottom) {
32857840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase                return false;
32867840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase            }
32877840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase        }
32887840055f76f2ba1a0052aee09e578cf9314f5364Chet Haase        return retValue;
328924443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    }
329024443ea3992e372e47daa50266b0f2ec38cac388Romain Guy
329124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    @Override
329224443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    public void setCacheColorHint(int color) {
32938f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        final boolean opaque = (color >>> 24) == 0xFF;
32948f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        mIsCacheColorOpaque = opaque;
32958f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        if (opaque) {
3296a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            if (mDividerPaint == null) {
3297a02903fbee6725563da4472bd120f844e9d5518cRomain Guy                mDividerPaint = new Paint();
3298a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            }
32998f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy            mDividerPaint.setColor(color);
33008f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy        }
330124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy        super.setCacheColorHint(color);
330224443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    }
3303637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3304637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    void drawOverscrollHeader(Canvas canvas, Drawable drawable, Rect bounds) {
3305637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final int height = drawable.getMinimumHeight();
3306637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3307637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.save();
3308637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.clipRect(bounds);
3309637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3310637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final int span = bounds.bottom - bounds.top;
3311637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (span < height) {
3312637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            bounds.top = bounds.bottom - height;
3313637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
3314637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3315637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        drawable.setBounds(bounds);
3316637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        drawable.draw(canvas);
3317637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3318637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.restore();
3319637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3320637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3321637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    void drawOverscrollFooter(Canvas canvas, Drawable drawable, Rect bounds) {
3322637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final int height = drawable.getMinimumHeight();
3323637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3324637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.save();
3325637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.clipRect(bounds);
3326637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3327637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final int span = bounds.bottom - bounds.top;
3328637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (span < height) {
3329637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            bounds.bottom = bounds.top + height;
3330637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
3331637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3332637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        drawable.setBounds(bounds);
3333637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        drawable.draw(canvas);
3334637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3335637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        canvas.restore();
3336637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3337637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
333824443ea3992e372e47daa50266b0f2ec38cac388Romain Guy    @Override
33399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchDraw(Canvas canvas) {
33400211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        if (mCachingStarted) {
33410211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy            mCachingActive = true;
33420211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        }
33430211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy
33449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Draw the dividers
33459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int dividerHeight = mDividerHeight;
3346637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final Drawable overscrollHeader = mOverScrollHeader;
3347637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final Drawable overscrollFooter = mOverScrollFooter;
3348637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final boolean drawOverscrollHeader = overscrollHeader != null;
3349637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        final boolean drawOverscrollFooter = overscrollFooter != null;
3350bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell        final boolean drawDividers = dividerHeight > 0 && mDivider != null;
33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3352637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (drawDividers || drawOverscrollHeader || drawOverscrollFooter) {
33539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Only modify the top and bottom in the loop, we set the left and right here
33549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Rect bounds = mTempRect;
33559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.left = mPaddingLeft;
33569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.right = mRight - mLeft - mPaddingRight;
33579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int count = getChildCount();
3359744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            final int headerCount = getHeaderViewsCount();
3360bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell            final int itemCount = mItemCount;
3361b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette            final int footerLimit = (itemCount - mFooterViewInfos.size());
33629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean headerDividers = mHeaderDividersEnabled;
33639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean footerDividers = mFooterDividersEnabled;
33649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int first = mFirstPosition;
33652bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy            final boolean areAllItemsSelectable = mAreAllItemsSelectable;
33662bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy            final ListAdapter adapter = mAdapter;
3367e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // If the list is opaque *and* the background is not, we want to
3368e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // fill a rect where the dividers would be for non-selectable items
3369e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // If the list is opaque and the background is also opaque, we don't
3370e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            // need to draw anything since the background will do it for us
3371179de8a37cb886e61264d2b7efd5bd4f29a5b381Romain Guy            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
3372e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy
3373e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy            if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) {
3374a02903fbee6725563da4472bd120f844e9d5518cRomain Guy                mDividerPaint = new Paint();
3375e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy                mDividerPaint.setColor(getCacheColorHint());
3376a02903fbee6725563da4472bd120f844e9d5518cRomain Guy            }
33778f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy            final Paint paint = mDividerPaint;
33789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33799456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell            int effectivePaddingTop = 0;
33809456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell            int effectivePaddingBottom = 0;
33819456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell            if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
33829456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell                effectivePaddingTop = mListPadding.top;
33839456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell                effectivePaddingBottom = mListPadding.bottom;
33849456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell            }
33859456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell
33869456655f93f34a11f4b4696212f2649eed0c35dbAdam Powell            final int listBottom = mBottom - mTop - effectivePaddingBottom + mScrollY;
33879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mStackFromBottom) {
3388637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                int bottom = 0;
33890b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell
3390637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                // Draw top divider or header for overscroll
3391637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                final int scrollY = mScrollY;
3392637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                if (count > 0 && scrollY < 0) {
3393637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    if (drawOverscrollHeader) {
3394637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.bottom = 0;
3395637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.top = scrollY;
3396637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        drawOverscrollHeader(canvas, overscrollHeader, bounds);
3397637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    } else if (drawDividers) {
3398637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.bottom = 0;
3399637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.top = -dividerHeight;
3400637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        drawDivider(canvas, bounds, -1);
3401637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    }
3402637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                }
3403637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
34049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < count; i++) {
3405b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final int itemIndex = (first + i);
3406b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final boolean isHeader = (itemIndex < headerCount);
3407b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final boolean isFooter = (itemIndex >= footerLimit);
3408b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
3409b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                        final View child = getChildAt(i);
34109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        bottom = child.getBottom();
3411b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                        final boolean isLastItem = (i == (count - 1));
3412b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette
3413b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                        if (drawDividers && (bottom < listBottom)
3414b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                                && !(drawOverscrollFooter && isLastItem)) {
3415b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                            final int nextIndex = (itemIndex + 1);
341620cc605b69a017316112929666255226c184a376Alan Viverette                            // Draw dividers between enabled items, headers
341720cc605b69a017316112929666255226c184a376Alan Viverette                            // and/or footers when enabled and requested, and
341820cc605b69a017316112929666255226c184a376Alan Viverette                            // after the last enabled item.
341920cc605b69a017316112929666255226c184a376Alan Viverette                            if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
342020cc605b69a017316112929666255226c184a376Alan Viverette                                    && (nextIndex >= headerCount)) && (isLastItem
342120cc605b69a017316112929666255226c184a376Alan Viverette                                    || adapter.isEnabled(nextIndex) && (footerDividers || !isFooter
342220cc605b69a017316112929666255226c184a376Alan Viverette                                            && (nextIndex < footerLimit)))) {
3423637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                bounds.top = bottom;
3424637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                bounds.bottom = bottom + dividerHeight;
3425637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                drawDivider(canvas, bounds, i);
3426637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                            } else if (fillForMissingDividers) {
3427637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                bounds.top = bottom;
3428637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                bounds.bottom = bottom + dividerHeight;
3429637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                                canvas.drawRect(bounds, paint);
3430637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                            }
34319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
34329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
34339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3434637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3435637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                final int overFooterBottom = mBottom + mScrollY;
3436637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                if (drawOverscrollFooter && first + count == itemCount &&
3437637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        overFooterBottom > bottom) {
3438637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    bounds.top = bottom;
3439637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    bounds.bottom = overFooterBottom;
3440637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    drawOverscrollFooter(canvas, overscrollFooter, bounds);
3441637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                }
34429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
34439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int top;
34449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3445bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                final int scrollY = mScrollY;
3446bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
3447637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                if (count > 0 && drawOverscrollHeader) {
3448637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    bounds.top = scrollY;
3449637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    bounds.bottom = getChildAt(0).getTop();
3450637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    drawOverscrollHeader(canvas, overscrollHeader, bounds);
3451637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                }
3452637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3453637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                final int start = drawOverscrollHeader ? 1 : 0;
3454637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                for (int i = start; i < count; i++) {
3455b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final int itemIndex = (first + i);
3456b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final boolean isHeader = (itemIndex < headerCount);
3457b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    final boolean isFooter = (itemIndex >= footerLimit);
3458b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                    if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
3459b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                        final View child = getChildAt(i);
34609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        top = child.getTop();
3461b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                        if (drawDividers && (top > effectivePaddingTop)) {
3462b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                            final boolean isFirstItem = (i == start);
3463b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                            final int previousIndex = (itemIndex - 1);
346420cc605b69a017316112929666255226c184a376Alan Viverette                            // Draw dividers between enabled items, headers
346520cc605b69a017316112929666255226c184a376Alan Viverette                            // and/or footers when enabled and requested, and
346620cc605b69a017316112929666255226c184a376Alan Viverette                            // before the first enabled item.
346720cc605b69a017316112929666255226c184a376Alan Viverette                            if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
346820cc605b69a017316112929666255226c184a376Alan Viverette                                    && (previousIndex >= headerCount)) && (isFirstItem ||
346920cc605b69a017316112929666255226c184a376Alan Viverette                                    adapter.isEnabled(previousIndex) && (footerDividers || !isFooter
347020cc605b69a017316112929666255226c184a376Alan Viverette                                            && (previousIndex < footerLimit)))) {
34718f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = top - dividerHeight;
34728f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = top;
3473b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                                // Give the method the child ABOVE the divider,
3474b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                                // so we subtract one from our child position.
3475b9fc4b879bab5640038fb09b40133611f91d7274Alan Viverette                                // Give -1 when there is no child above the
34768f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                // divider.
34778f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                drawDivider(canvas, bounds, i - 1);
3478e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy                            } else if (fillForMissingDividers) {
34798f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.top = top - dividerHeight;
34808f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                bounds.bottom = top;
34818f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                                canvas.drawRect(bounds, paint);
34828f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy                            }
34839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
34849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
34859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3486bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
3487179de8a37cb886e61264d2b7efd5bd4f29a5b381Romain Guy                if (count > 0 && scrollY > 0) {
3488637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    if (drawOverscrollFooter) {
3489637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        final int absListBottom = mBottom;
3490637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.top = absListBottom;
3491637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.bottom = absListBottom + scrollY;
3492637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        drawOverscrollFooter(canvas, overscrollFooter, bounds);
3493637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    } else if (drawDividers) {
3494637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.top = listBottom;
3495637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        bounds.bottom = listBottom + dividerHeight;
3496637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                        drawDivider(canvas, bounds, -1);
3497637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell                    }
3498bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell                }
34999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
35009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Draw the indicators (these should be drawn above the dividers) and children
35039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.dispatchDraw(canvas);
35049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35060211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy    @Override
35070211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
35080211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        boolean more = super.drawChild(canvas, child, drawingTime);
35090211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        if (mCachingActive && child.mCachingFailed) {
35100211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy            mCachingActive = false;
35110211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        }
35120211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy        return more;
35130211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy    }
35140211a0a10d20ec99bd78905ea9cd2960f7beb4c8Romain Guy
35159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draws a divider for the given child in the given bounds.
35179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The canvas to draw to.
35199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bounds The bounds of the divider.
35209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childIndex The index of child (of the View) above the divider.
35219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            This will be -1 if there is no child above the divider to be
35229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            drawn.
35239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void drawDivider(Canvas canvas, Rect bounds, int childIndex) {
35259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This widget draws the same divider for all children
35269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Drawable divider = mDivider;
35279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
352895930e13faac8c17dabfaa1478089baa772f091bRomain Guy        divider.setBounds(bounds);
35299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        divider.draw(canvas);
35309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the drawable that will be drawn between each item in the list.
35349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the current drawable drawn between list elements
35367b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * @attr ref R.styleable#ListView_divider
35379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35387b2f86488cb28568074a5a97b84a66b862473409Alan Viverette    @Nullable
35399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getDivider() {
35409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDivider;
35419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35447b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * Sets the drawable that will be drawn between each item in the list.
35457b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * <p>
35467b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * <strong>Note:</strong> If the drawable does not have an intrinsic
35477b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * height, you should also call {@link #setDividerHeight(int)}.
35489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35497b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * @param divider the drawable to use
35507b2f86488cb28568074a5a97b84a66b862473409Alan Viverette     * @attr ref R.styleable#ListView_divider
35519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35527b2f86488cb28568074a5a97b84a66b862473409Alan Viverette    public void setDivider(@Nullable Drawable divider) {
35539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (divider != null) {
35549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDividerHeight = divider.getIntrinsicHeight();
35559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
35569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDividerHeight = 0;
35579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDivider = divider;
355924443ea3992e372e47daa50266b0f2ec38cac388Romain Guy        mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE;
3560eeb55e673feca137bd0106ca31f9b68509a4ae36Romain Guy        requestLayout();
3561eeb55e673feca137bd0106ca31f9b68509a4ae36Romain Guy        invalidate();
35629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Returns the height of the divider that will be drawn between each item in the list.
35669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDividerHeight() {
35689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDividerHeight;
35699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the height of the divider that will be drawn between each item in the list. Calling
35739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
35749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param height The new height of the divider in pixels.
35769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDividerHeight(int height) {
35789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDividerHeight = height;
3579eeb55e673feca137bd0106ca31f9b68509a4ae36Romain Guy        requestLayout();
3580eeb55e673feca137bd0106ca31f9b68509a4ae36Romain Guy        invalidate();
35819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables the drawing of the divider for header views.
35859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param headerDividersEnabled True to draw the headers, false otherwise.
35879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
35889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setFooterDividersEnabled(boolean)
35895542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @see #areHeaderDividersEnabled()
35909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #addHeaderView(android.view.View)
35919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setHeaderDividersEnabled(boolean headerDividersEnabled) {
35939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderDividersEnabled = headerDividersEnabled;
35949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
35959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35985542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @return Whether the drawing of the divider for header views is enabled
35995542103589696e2945b5fe5e251292873e3af897Alan Viverette     *
36005542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @see #setHeaderDividersEnabled(boolean)
36015542103589696e2945b5fe5e251292873e3af897Alan Viverette     */
36025542103589696e2945b5fe5e251292873e3af897Alan Viverette    public boolean areHeaderDividersEnabled() {
36035542103589696e2945b5fe5e251292873e3af897Alan Viverette        return mHeaderDividersEnabled;
36045542103589696e2945b5fe5e251292873e3af897Alan Viverette    }
36055542103589696e2945b5fe5e251292873e3af897Alan Viverette
36065542103589696e2945b5fe5e251292873e3af897Alan Viverette    /**
36079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables the drawing of the divider for footer views.
36089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
36099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param footerDividersEnabled True to draw the footers, false otherwise.
36109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
36119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setHeaderDividersEnabled(boolean)
36125542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @see #areFooterDividersEnabled()
36139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #addFooterView(android.view.View)
36149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
36159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFooterDividersEnabled(boolean footerDividersEnabled) {
36169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFooterDividersEnabled = footerDividersEnabled;
36179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
36189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
36195542103589696e2945b5fe5e251292873e3af897Alan Viverette
36205542103589696e2945b5fe5e251292873e3af897Alan Viverette    /**
36215542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @return Whether the drawing of the divider for footer views is enabled
36225542103589696e2945b5fe5e251292873e3af897Alan Viverette     *
36235542103589696e2945b5fe5e251292873e3af897Alan Viverette     * @see #setFooterDividersEnabled(boolean)
36245542103589696e2945b5fe5e251292873e3af897Alan Viverette     */
36255542103589696e2945b5fe5e251292873e3af897Alan Viverette    public boolean areFooterDividersEnabled() {
36265542103589696e2945b5fe5e251292873e3af897Alan Viverette        return mFooterDividersEnabled;
36275542103589696e2945b5fe5e251292873e3af897Alan Viverette    }
3628bfb5d4b93bb739a012ecec604473838c1343c88aAdam Powell
3629637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    /**
3630637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * Sets the drawable that will be drawn above all other list content.
3631637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * This area can become visible when the user overscrolls the list.
3632637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     *
3633637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * @param header The drawable to use
3634637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     */
3635637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    public void setOverscrollHeader(Drawable header) {
3636637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        mOverScrollHeader = header;
3637637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        if (mScrollY < 0) {
3638637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell            invalidate();
3639637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        }
3640637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3641637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3642637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    /**
3643637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * @return The drawable that will be drawn above all other list content
3644637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     */
3645637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    public Drawable getOverscrollHeader() {
3646637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        return mOverScrollHeader;
3647637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3648637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3649637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    /**
3650637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * Sets the drawable that will be drawn below all other list content.
3651637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * This area can become visible when the user overscrolls the list,
3652637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * or when the list's content does not fully fill the container area.
3653637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     *
3654637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * @param footer The drawable to use
3655637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     */
3656637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    public void setOverscrollFooter(Drawable footer) {
3657637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        mOverScrollFooter = footer;
3658637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        invalidate();
3659637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3660637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
3661637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    /**
3662637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     * @return The drawable that will be drawn below all other list content
3663637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell     */
3664637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    public Drawable getOverscrollFooter() {
3665637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell        return mOverScrollFooter;
3666637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell    }
3667637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell
36689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
36699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
36709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
36719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3672e1bf486846ce7589727ad84440bd9a2d42751055Adam Powell        final ListAdapter adapter = mAdapter;
36739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int closetChildIndex = -1;
3674dcce1216b0066f3f9ed1b01a485684e8617e7ea4Adam Powell        int closestChildTop = 0;
3675e1bf486846ce7589727ad84440bd9a2d42751055Adam Powell        if (adapter != null && gainFocus && previouslyFocusedRect != null) {
36769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previouslyFocusedRect.offset(mScrollX, mScrollY);
36779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3678d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            // Don't cache the result of getChildCount or mFirstPosition here,
3679d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            // it could change in layoutChildren.
3680d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            if (adapter.getCount() < getChildCount() + mFirstPosition) {
3681c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell                mLayoutMode = LAYOUT_NORMAL;
3682c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell                layoutChildren();
3683c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell            }
3684c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell
36859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // figure out which item should be selected based on previously
36869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // focused rect
36879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Rect otherRect = mTempRect;
36889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int minDistance = Integer.MAX_VALUE;
36899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int childCount = getChildCount();
3690d7507834e73f32b4c82839036dc3897a1587e668Adam Powell            final int firstPosition = mFirstPosition;
36919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < childCount; i++) {
36939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // only consider selectable views
36949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!adapter.isEnabled(firstPosition + i)) {
36959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
36969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
36979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                View other = getChildAt(i);
36999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                other.getDrawingRect(otherRect);
37009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offsetDescendantRectToMyCoords(other, otherRect);
37019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int distance = getDistance(previouslyFocusedRect, otherRect, direction);
37029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (distance < minDistance) {
37049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    minDistance = distance;
37059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    closetChildIndex = i;
3706dcce1216b0066f3f9ed1b01a485684e8617e7ea4Adam Powell                    closestChildTop = other.getTop();
37079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
37089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (closetChildIndex >= 0) {
3712dcce1216b0066f3f9ed1b01a485684e8617e7ea4Adam Powell            setSelectionFromTop(closetChildIndex + mFirstPosition, closestChildTop);
37139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
37149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
37159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
37179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
37209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (non-Javadoc)
37219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
37229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Children specified in XML are assumed to be header views. After we have
37239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parsed them move them out of the children list and into mHeaderViews.
37249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
37269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFinishInflate() {
37279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onFinishInflate();
37289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = getChildCount();
37309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) {
37319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; ++i) {
37329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                addHeaderView(getChildAt(i));
37339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeAllViews();
37359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
37379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
37399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.View#findViewById(int)
37409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * First look in our children, then in any header and footer views that may be scrolled off.
37419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
37437b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    protected View findViewTraversal(@IdRes int id) {
37449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
37459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v = super.findViewTraversal(id);
37469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (v == null) {
37479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
37489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
37499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
37509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = findViewInHeadersOrFooters(mFooterViewInfos, id);
37529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
37539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
37549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
37579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
37589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
37609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
37619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Look in the passed in list of headers or footers for the view.
37629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
37649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where != null) {
37659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int len = where.size();
37669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View v;
37679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < len; i++) {
37699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                v = where.get(i).view;
37709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!v.isRootNamespace()) {
37729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v = v.findViewById(id);
37739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (v != null) {
37759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return v;
37769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
37779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
37789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
37819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
37829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
37844e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * @see android.view.View#findViewWithTag(Object)
37859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * First look in our children, then in any header and footer views that may be scrolled off.
37869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
37889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected View findViewWithTagTraversal(Object tag) {
37899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
37909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v = super.findViewWithTagTraversal(tag);
37919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (v == null) {
37924e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            v = findViewWithTagInHeadersOrFooters(mHeaderViewInfos, tag);
37939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
37949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
37959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37974e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            v = findViewWithTagInHeadersOrFooters(mFooterViewInfos, tag);
37989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (v != null) {
37999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return v;
38009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
38039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
38049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* (non-Javadoc)
38069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
38079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Look in the passed in list of headers or footers for the view with the tag.
38089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
38094e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
38109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where != null) {
38119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int len = where.size();
38129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View v;
38139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < len; i++) {
38159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                v = where.get(i).view;
38169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!v.isRootNamespace()) {
38189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v = v.findViewWithTag(tag);
38199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (v != null) {
38219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return v;
38229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
38239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
38249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
38279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
38289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38294e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    /**
38304e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * @hide
38314e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * @see android.view.View#findViewByPredicate(Predicate)
38324e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * First look in our children, then in any header and footer views that may be scrolled off.
38334e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     */
38344e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    @Override
38354dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
38364e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        View v;
38374dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown        v = super.findViewByPredicateTraversal(predicate, childToSkip);
38384e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        if (v == null) {
38394dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown            v = findViewByPredicateInHeadersOrFooters(mHeaderViewInfos, predicate, childToSkip);
38404e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            if (v != null) {
38414e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                return v;
38424e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            }
38434e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38444dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown            v = findViewByPredicateInHeadersOrFooters(mFooterViewInfos, predicate, childToSkip);
38454e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            if (v != null) {
38464e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                return v;
38474e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            }
38484e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
38494e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        return v;
38504e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    }
38514e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38524e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    /* (non-Javadoc)
38534e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     *
38544e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * Look in the passed in list of headers or footers for the first view that matches
38554e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     * the predicate.
38564e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown     */
38574e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    View findViewByPredicateInHeadersOrFooters(ArrayList<FixedViewInfo> where,
38584dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown            Predicate<View> predicate, View childToSkip) {
38594e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        if (where != null) {
38604e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            int len = where.size();
38614e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            View v;
38624e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38634e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            for (int i = 0; i < len; i++) {
38644e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                v = where.get(i).view;
38654e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38664dfbec2665bd5f567d7321f2e88a39e1ab45fdf8Jeff Brown                if (v != childToSkip && !v.isRootNamespace()) {
38674e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    v = v.findViewByPredicate(predicate);
38684e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38694e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    if (v != null) {
38704e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                        return v;
38714e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                    }
38724e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown                }
38734e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown            }
38744e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        }
38754e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown        return null;
38764e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown    }
38774e6319b73c85082e18d1c532b86336ddd1f8cfaaJeff Brown
38789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3879fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * Returns the set of checked items ids. The result is only valid if the
38808f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     * choice mode has not been set to {@link #CHOICE_MODE_NONE}.
3881fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *
3882fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     * @return A new array which contains the id of each checked item in the
3883fd3ddfa6f0559eb29eea179690144a7357c34b3dGilles Debunne     *         list.
38848f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell     *
3885463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell     * @deprecated Use {@link #getCheckedItemIds()} instead.
3886ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy     */
38878350f7dbc3a62211b2891f35911e4073d24c4cc5Adam Powell    @Deprecated
3888ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy    public long[] getCheckItemIds() {
3889463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Use new behavior that correctly handles stable ID mapping.
3890463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        if (mAdapter != null && mAdapter.hasStableIds()) {
3891463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            return getCheckedItemIds();
3892463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        }
3893463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3894463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Old behavior was buggy, but would sort of work for adapters without stable IDs.
3895463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        // Fall back to it to support legacy apps.
3896463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null && mAdapter != null) {
3897463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final SparseBooleanArray states = mCheckStates;
3898463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final int count = states.size();
3899463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final long[] ids = new long[count];
3900463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            final ListAdapter adapter = mAdapter;
3901463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3902463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            int checkedCount = 0;
3903463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            for (int i = 0; i < count; i++) {
3904463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                if (states.valueAt(i)) {
3905463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                    ids[checkedCount++] = adapter.getItemId(states.keyAt(i));
3906463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                }
3907463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            }
3908463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3909463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            // Trim array if needed. mCheckStates may contain false values
3910463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            // resulting in checkedCount being smaller than count.
3911463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            if (checkedCount == count) {
3912463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                return ids;
3913463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            } else {
3914463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                final long[] result = new long[checkedCount];
3915463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                System.arraycopy(ids, 0, result, 0, checkedCount);
3916463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell
3917463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell                return result;
3918463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell            }
3919463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        }
3920463ceff8a44ec2bf67b0394be7f7e70613a55478Adam Powell        return new long[0];
39218f1bfe1a7cef702fd74e5405443e9fdb7c5e7556Adam Powell    }
39228a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
39238a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
3924441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette    int getHeightForPosition(int position) {
3925441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final int height = super.getHeightForPosition(position);
3926441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        if (shouldAdjustHeightForDivider(position)) {
3927441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            return height + mDividerHeight;
3928441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        }
3929441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        return height;
3930441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette    }
3931441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette
3932441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette    private boolean shouldAdjustHeightForDivider(int itemIndex) {
3933441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final int dividerHeight = mDividerHeight;
3934441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final Drawable overscrollHeader = mOverScrollHeader;
3935441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final Drawable overscrollFooter = mOverScrollFooter;
3936441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final boolean drawOverscrollHeader = overscrollHeader != null;
3937441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final boolean drawOverscrollFooter = overscrollFooter != null;
3938441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        final boolean drawDividers = dividerHeight > 0 && mDivider != null;
3939441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette
3940441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        if (drawDividers) {
3941441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
3942441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final int itemCount = mItemCount;
3943744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            final int headerCount = getHeaderViewsCount();
3944441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final int footerLimit = (itemCount - mFooterViewInfos.size());
3945441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final boolean isHeader = (itemIndex < headerCount);
3946441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final boolean isFooter = (itemIndex >= footerLimit);
3947441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final boolean headerDividers = mHeaderDividersEnabled;
3948441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            final boolean footerDividers = mFooterDividersEnabled;
3949441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
3950441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                final ListAdapter adapter = mAdapter;
3951441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                if (!mStackFromBottom) {
3952441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    final boolean isLastItem = (itemIndex == (itemCount - 1));
3953441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    if (!drawOverscrollFooter || !isLastItem) {
3954441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        final int nextIndex = itemIndex + 1;
3955441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // Draw dividers between enabled items, headers
3956441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // and/or footers when enabled and requested, and
3957441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // after the last enabled item.
3958441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
3959441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                && (nextIndex >= headerCount)) && (isLastItem
3960441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                || adapter.isEnabled(nextIndex) && (footerDividers || !isFooter
3961441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                                && (nextIndex < footerLimit)))) {
3962441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                            return true;
3963441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        } else if (fillForMissingDividers) {
3964441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                            return true;
3965441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        }
3966441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    }
3967441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                } else {
3968441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    final int start = drawOverscrollHeader ? 1 : 0;
3969441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    final boolean isFirstItem = (itemIndex == start);
3970441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    if (!isFirstItem) {
3971441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        final int previousIndex = (itemIndex - 1);
3972441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // Draw dividers between enabled items, headers
3973441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // and/or footers when enabled and requested, and
3974441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        // before the first enabled item.
3975441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
3976441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                && (previousIndex >= headerCount)) && (isFirstItem ||
3977441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                adapter.isEnabled(previousIndex) && (footerDividers || !isFooter
3978441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                                        && (previousIndex < footerLimit)))) {
3979441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                            return true;
3980441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        } else if (fillForMissingDividers) {
3981441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                            return true;
3982441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                        }
3983441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                    }
3984441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette                }
3985441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette            }
3986441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        }
3987441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette
3988441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette        return false;
3989441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette    }
3990441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette
3991441b437b72dd92c1267c4f2cce5f28337e51cd2cAlan Viverette    @Override
3992a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
3993a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return ListView.class.getName();
39948a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
39958a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
3996a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    /** @hide */
39978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
3998a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
3999a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette        super.onInitializeAccessibilityNodeInfoInternal(info);
40005b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
400177c180a5137348022fce388930a9781863f83e74Alan Viverette        final int rowsCount = getCount();
400276769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final int selectionMode = getSelectionModeForAccessibility();
400377c180a5137348022fce388930a9781863f83e74Alan Viverette        final CollectionInfo collectionInfo = CollectionInfo.obtain(
400477c180a5137348022fce388930a9781863f83e74Alan Viverette                rowsCount, 1, false, selectionMode);
40055b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        info.setCollectionInfo(collectionInfo);
400623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
400723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        if (rowsCount > 0) {
400823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            info.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION);
400923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
401023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    }
401123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
401223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    /** @hide */
401323f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    @Override
401423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
401523f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        if (super.performAccessibilityActionInternal(action, arguments)) {
401623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            return true;
401723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
401823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
401923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        switch (action) {
402023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            case R.id.accessibilityActionScrollToPosition: {
402123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                final int row = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_ROW_INT, -1);
402223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                final int position = Math.min(row, getCount() - 1);
402323f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                if (row >= 0) {
402423f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    // The accessibility service gets data asynchronously, so
402523f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    // we'll be a little lenient by clamping the last position.
402623f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    smoothScrollToPosition(position);
402723f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                    return true;
402823f4432437b2ab742971055b7eb79b346894f24bAlan Viverette                }
402923f4432437b2ab742971055b7eb79b346894f24bAlan Viverette            } break;
403023f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        }
403123f4432437b2ab742971055b7eb79b346894f24bAlan Viverette
403223f4432437b2ab742971055b7eb79b346894f24bAlan Viverette        return false;
40335b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    }
40345b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
40355b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    @Override
40365b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette    public void onInitializeAccessibilityNodeInfoForItem(
40375b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette            View view, int position, AccessibilityNodeInfo info) {
40385b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
40395b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette
40405b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
40415f9eb8984480b03eb6a2b069b9b522d4d22c2183Steven Dao        final boolean isHeading = lp != null && lp.viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
404276769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final boolean isSelected = isItemChecked(position);
404376769ae02e713f50816ee67ff618b748d95050a8Alan Viverette        final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
404477c180a5137348022fce388930a9781863f83e74Alan Viverette                position, 1, 0, 1, isHeading, isSelected);
40455b2081dc41cccd76780a2cb4e9a973505c13446cAlan Viverette        info.setCollectionItemInfo(itemInfo);
40468a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
404794a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
404894a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    /** @hide */
404994a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    @Override
405094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
405194a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        super.encodeProperties(encoder);
405294a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
405394a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        encoder.addProperty("recycleOnMeasure", recycleOnMeasure());
405494a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    }
4055744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan
4056744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    /** @hide */
4057744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
4058744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            ArrayList<ListView.FixedViewInfo> headerViewInfos,
4059744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            ArrayList<ListView.FixedViewInfo> footerViewInfos,
4060744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            ListAdapter adapter) {
4061744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan        return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
4062744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    }
4063744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan
4064744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    /** @hide */
4065744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    protected void wrapHeaderListAdapterInternal() {
4066744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan        mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
4067744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    }
4068744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan
4069744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    /** @hide */
4070744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    protected void dispatchDataSetObserverOnChangedInternal() {
4071744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan        if (mDataSetObserver != null) {
4072744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan            mDataSetObserver.onChanged();
4073744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan        }
4074744be16ffa030cb62de13f633c124fc0e72d0181Michael Kwan    }
40759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4076