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