ListView.java revision 0b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116
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 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 2324443ea3992e372e47daa50266b0f2ec38cac388Romain Guyimport android.graphics.PixelFormat; 248f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guyimport android.graphics.Paint; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.ColorDrawable; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseBooleanArray; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.FocusFinder; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewDebug; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewParent; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SoundEffectConstants; 3975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.accessibility.AccessibilityEvent; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.google.android.collect.Lists; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.R; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation Notes: 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Some terminology: 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * index - index of the items that are currently visible 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position - index of the items in the cursor 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that shows items in a vertically scrolling list. The items 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * come from the {@link ListAdapter} associated with this view. 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_entries 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_divider 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_dividerHeight 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_choiceMode 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_headerDividersEnabled 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#ListView_footerDividersEnabled 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ListView extends AbsListView { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Used to indicate a no preference for a position type. 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int NO_POSITION = -1; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Normal list that does not indicate choices 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CHOICE_MODE_NONE = 0; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The list allows up to one choice 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CHOICE_MODE_SINGLE = 1; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The list allows multiple choices 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CHOICE_MODE_MULTIPLE = 2; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When arrow scrolling, ListView will never scroll more than this factor 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * times the height of the list. 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final float MAX_SCROLL_FACTOR = 0.33f; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When arrow scrolling, need a certain amount of pixels to preview next 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * items. This is usually the fading edge, but if that is small enough, 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * we want to make sure we preview at least this many pixels. 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MIN_SCROLL_PREVIEW_PIXELS = 2; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A class that represents a fixed view in a list, for example a header at the top 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or a footer at the bottom. 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class FixedViewInfo { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The view to add to the list */ 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public View view; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */ 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Object data; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** <code>true</code> if the fixed view should be selectable in the list */ 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isSelectable; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList(); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable mDivider; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mDividerHeight; 11924443ea3992e372e47daa50266b0f2ec38cac388Romain Guy 12024443ea3992e372e47daa50266b0f2ec38cac388Romain Guy private boolean mIsCacheColorOpaque; 12124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy private boolean mDividerIsOpaque; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mClipDivider; 12324443ea3992e372e47daa50266b0f2ec38cac388Romain Guy 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mHeaderDividersEnabled; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mFooterDividersEnabled; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mAreAllItemsSelectable = true; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mItemsCanFocus = false; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mChoiceMode = CHOICE_MODE_NONE; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SparseBooleanArray mCheckStates; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // used for temporary calculations. 136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private final Rect mTempRect = new Rect(); 137a02903fbee6725563da4472bd120f844e9d5518cRomain Guy private Paint mDividerPaint; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the single allocated result per list view; kinda cheesey but avoids 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allocating these thingies too often. 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrowScrollFocusResult mArrowScrollFocusResult = new ArrowScrollFocusResult(); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ListView(Context context) { 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ListView(Context context, AttributeSet attrs) { 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, com.android.internal.R.attr.listViewStyle); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ListView(Context context, AttributeSet attrs, int defStyle) { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.styleable.ListView, defStyle, 0); 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence[] entries = a.getTextArray( 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.styleable.ListView_entries); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entries != null) { 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setAdapter(new ArrayAdapter<CharSequence>(context, 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.layout.simple_list_item_1, entries)); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (d != null) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If a divider is specified use its intrinsic height for divider height 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDivider(d); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use the height specified, zero being the default 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = a.getDimensionPixelSize( 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.styleable.ListView_dividerHeight, 0); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dividerHeight != 0) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDividerHeight(dividerHeight); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 177536fb04c1c419d5dd3816112ab5af7baee7cd549Romain Guy setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE)); 178536fb04c1c419d5dd3816112ab5af7baee7cd549Romain Guy 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project a.recycle(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The maximum amount a list view will scroll in response to 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an arrow event. 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getMaxScrollAmount() { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop)); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Make sure views are touching the top or bottom edge, as appropriate for 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * our gravity 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void adjustViewsUpOrDown() { 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childCount = getChildCount(); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int delta; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (childCount > 0) { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Uh-oh -- we came up short. Slide all views up to make them 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // align with the top 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child = getChildAt(0); 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta = child.getTop() - mListPadding.top; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition != 0) { 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It's OK to have some space above the first item if it is 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // part of the vertical spacing 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta -= mDividerHeight; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (delta < 0) { 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We only are looking to see if we are too low, not too high 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta = 0; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we are too high, slide all views down to align with bottom 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child = getChildAt(childCount - 1); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta = child.getBottom() - (getHeight() - mListPadding.bottom); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition + childCount < mItemCount) { 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It's OK to have some space below the last item if it is 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // part of the vertical spacing 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta += mDividerHeight; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (delta > 0) { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta = 0; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (delta != 0) { 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetChildrenTopAndBottom(-delta); 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a fixed view to appear at the top of the list. If addHeaderView is 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * called more than once, the views will appear in the order they were 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * added. Views added using this call can take focus if they want. 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * NOTE: Call this before calling setAdapter. This is so ListView can wrap 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the supplied cursor with one that that will also account for header 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * views. 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to add. 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param data Data to associate with this view 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param isSelectable whether the item is selectable 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addHeaderView(View v, Object data, boolean isSelectable) { 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter != null) { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cannot add header view to list -- setAdapter has already been called."); 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FixedViewInfo info = new FixedViewInfo(); 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.view = v; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.data = data; 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.isSelectable = isSelectable; 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHeaderViewInfos.add(info); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a fixed view to appear at the top of the list. If addHeaderView is 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * called more than once, the views will appear in the order they were 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * added. Views added using this call can take focus if they want. 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * NOTE: Call this before calling setAdapter. This is so ListView can wrap 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the supplied cursor with one that that will also account for header 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * views. 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to add. 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addHeaderView(View v) { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addHeaderView(v, null, true); 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getHeaderViewsCount() { 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mHeaderViewInfos.size(); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Removes a previously-added header view. 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to remove 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the view was removed, false if the view was not a header 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * view 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean removeHeaderView(View v) { 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mHeaderViewInfos.size() > 0) { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean result = false; 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (((HeaderViewListAdapter) mAdapter).removeHeader(v)) { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataSetObserver.onChanged(); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = true; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeFixedViewInfo(v, mHeaderViewInfos); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) { 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = where.size(); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < len; ++i) { 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FixedViewInfo info = where.get(i); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (info.view == v) { 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project where.remove(i); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a fixed view to appear at the bottom of the list. If addFooterView is 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * called more than once, the views will appear in the order they were 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * added. Views added using this call can take focus if they want. 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * NOTE: Call this before calling setAdapter. This is so ListView can wrap 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the supplied cursor with one that that will also account for header 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * views. 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to add. 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param data Data to associate with this view 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param isSelectable true if the footer view can be selected 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addFooterView(View v, Object data, boolean isSelectable) { 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FixedViewInfo info = new FixedViewInfo(); 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.view = v; 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.data = data; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info.isSelectable = isSelectable; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFooterViewInfos.add(info); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in the case of re-adding a footer view, or adding one later on, 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need to notify the observer 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataSetObserver != null) { 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataSetObserver.onChanged(); 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a fixed view to appear at the bottom of the list. If addFooterView is called more 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * than once, the views will appear in the order they were added. Views added using 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this call can take focus if they want. 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplied 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor with one that that will also account for header views. 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to add. 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addFooterView(View v) { 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addFooterView(v, null, true); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getFooterViewsCount() { 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mFooterViewInfos.size(); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Removes a previously-added footer view. 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param v The view to remove 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * true if the view was removed, false if the view was not a footer view 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean removeFooterView(View v) { 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFooterViewInfos.size() > 0) { 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean result = false; 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (((HeaderViewListAdapter) mAdapter).removeFooter(v)) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataSetObserver.onChanged(); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = true; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeFixedViewInfo(v, mFooterViewInfos); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the adapter currently in use in this ListView. The returned adapter 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * might not be the same adapter passed to {@link #setAdapter(ListAdapter)} but 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * might be a {@link WrapperListAdapter}. 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The adapter currently used to display data in this ListView. 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setAdapter(ListAdapter) 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ListAdapter getAdapter() { 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mAdapter; 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the data behind this ListView. 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * depending on the ListView features currently in use. For instance, adding 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * headers and/or footers will cause the adapter to be wrapped. 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param adapter The ListAdapter which is responsible for maintaining the 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data backing this list and for producing a view to represent an 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * item in that data set. 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getAdapter() 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setAdapter(ListAdapter adapter) { 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (null != mAdapter) { 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAdapter.unregisterDataSetObserver(mDataSetObserver); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetList(); 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRecycler.clear(); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAdapter = adapter; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOldSelectedPosition = INVALID_POSITION; 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOldSelectedRowId = INVALID_ROW_ID; 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter != null) { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOldItemCount = mItemCount; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mItemCount = mAdapter.getCount(); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkFocus(); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataSetObserver = new AdapterDataSetObserver(); 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAdapter.registerDataSetObserver(mDataSetObserver); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int position; 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mStackFromBottom) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = lookForSelectablePosition(mItemCount - 1, false); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = lookForSelectablePosition(0, true); 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectedPositionInt(position); 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setNextSelectedPositionInt(position); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemCount == 0) { 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Nothing selected 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkSelectionChanged(); 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAreAllItemsSelectable = true; 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkFocus(); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Nothing selected 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkSelectionChanged(); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCheckStates != null) { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.clear(); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The list is empty. Clear everything out. 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void resetList() { 4732e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy // The parent's resetList() will remove all views from the layout so we need to 4742e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy // cleanup the state of our footers and headers 4752e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy clearRecycledState(mHeaderViewInfos); 4762e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy clearRecycledState(mFooterViewInfos); 4772e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.resetList(); 4792e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_NORMAL; 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4832e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy private void clearRecycledState(ArrayList<FixedViewInfo> infos) { 4842e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy if (infos != null) { 4852e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy final int count = infos.size(); 4862e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy 4872e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy for (int i = 0; i < count; i++) { 4882e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy final View child = infos.get(i).view; 4892e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy final LayoutParams p = (LayoutParams) child.getLayoutParams(); 4902e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy if (p != null) { 4912e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy p.recycledHeaderFooter = false; 4922e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy } 4932e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy } 4942e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy } 4952e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy } 4962e447d46d9936c325fe5209262564fc3c5e795a2Romain Guy 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the list needs to show the top fading edge 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean showingTopFadingEdge() { 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listTop = mScrollY + mListPadding.top; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mFirstPosition > 0) || (getChildAt(0).getTop() > listTop); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the list needs to show the bottom fading edge 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean showingBottomFadingEdge() { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childCount = getChildCount(); 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int bottomOfBottomChild = getChildAt(childCount - 1).getBottom(); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int lastVisiblePosition = mFirstPosition + childCount - 1; 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = mScrollY + getHeight() - mListPadding.bottom; 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (lastVisiblePosition < mItemCount - 1) 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (bottomOfBottomChild < listBottom); 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int rectTopWithinChild = rect.top; 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // offset so rect is in coordinates of the this view 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rect.offset(child.getLeft(), child.getTop()); 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rect.offset(-child.getScrollX(), -child.getScrollY()); 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int height = getHeight(); 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int listUnfadedTop = getScrollY(); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int listUnfadedBottom = listUnfadedTop + height; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int fadingEdge = getVerticalFadingEdgeLength(); 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (showingTopFadingEdge()) { 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // leave room for top fading edge as long as rect isn't at very top 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((mSelectedPosition > 0) || (rectTopWithinChild > fadingEdge)) { 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project listUnfadedTop += fadingEdge; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childCount = getChildCount(); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottomOfBottomChild = getChildAt(childCount - 1).getBottom(); 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (showingBottomFadingEdge()) { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // leave room for bottom fading edge as long as rect isn't at very bottom 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((mSelectedPosition < mItemCount - 1) 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (rect.bottom < (bottomOfBottomChild - fadingEdge))) { 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project listUnfadedBottom -= fadingEdge; 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int scrollYDelta = 0; 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rect.bottom > listUnfadedBottom && rect.top > listUnfadedTop) { 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to MOVE DOWN to get it in view: move down just enough so 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // that the entire rectangle is in view (or at least the first 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // screen size chunk). 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rect.height() > height) { 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // just enough to get screen size chunk on 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta += (rect.top - listUnfadedTop); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get entire rect at bottom of screen 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta += (rect.bottom - listUnfadedBottom); 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure we aren't scrolling beyond the end of our children 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int distanceToBottom = bottomOfBottomChild - listUnfadedBottom; 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta = Math.min(scrollYDelta, distanceToBottom); 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (rect.top < listUnfadedTop && rect.bottom < listUnfadedBottom) { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to MOVE UP to get it in view: move up just enough so that 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // entire rectangle is in view (or at least the first screen 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // size chunk of it). 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rect.height() > height) { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // screen size chunk 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta -= (listUnfadedBottom - rect.bottom); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // entire rect at top 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta -= (listUnfadedTop - rect.top); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure we aren't scrolling any further than the top our children 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = getChildAt(0).getTop(); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int deltaToTop = top - listUnfadedTop; 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollYDelta = Math.max(scrollYDelta, deltaToTop); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean scroll = scrollYDelta != 0; 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (scroll) { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollListItemsBy(-scrollYDelta); 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project positionSelector(child); 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSelectedTop = child.getTop(); 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return scroll; 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@inheritDoc} 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void fillGap(boolean down) { 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = getChildCount(); 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (down) { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int startOffset = count > 0 ? getChildAt(count - 1).getBottom() + mDividerHeight : 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getListPaddingTop(); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillDown(mFirstPosition + count, startOffset); 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooHigh(getChildCount()); 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int startOffset = count > 0 ? getChildAt(0).getTop() - mDividerHeight : 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHeight() - getListPaddingBottom(); 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(mFirstPosition - 1, startOffset); 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooLow(getChildCount()); 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills the list from pos down to the end of the list view. 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pos The first position to put in the list 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nextTop The location where the top of the item associated with pos 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * should be drawn 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The view that is currently selected, if it happens to be in the 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * range that we draw. 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillDown(int pos, int nextTop) { 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View selectedView = null; 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = (mBottom - mTop) - mListPadding.bottom; 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (nextTop < end && pos < mItemCount) { 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is this the selected item? 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean selected = pos == mSelectedPosition; 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected); 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextTop = child.getBottom() + mDividerHeight; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selected) { 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView = child; 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos++; 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return selectedView; 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills the list from pos up to the top of the list view. 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pos The first position to put in the list 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nextBottom The location where the bottom of the item associated 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with pos should be drawn 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The view that is currently selected 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillUp(int pos, int nextBottom) { 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View selectedView = null; 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = mListPadding.top; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (nextBottom > end && pos >= 0) { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is this the selected item? 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean selected = pos == mSelectedPosition; 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child = makeAndAddView(pos, nextBottom, false, mListPadding.left, selected); 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextBottom = child.getTop() - mDividerHeight; 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selected) { 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView = child; 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos--; 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = pos + 1; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return selectedView; 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills the list from top to bottom, starting with mFirstPosition 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nextTop The location where the top of the first item should be 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * drawn 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The view that is currently selected 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillFromTop(int nextTop) { 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = Math.min(mFirstPosition, mSelectedPosition); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = Math.min(mFirstPosition, mItemCount - 1); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition < 0) { 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = 0; 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fillDown(mFirstPosition, nextTop); 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Put mSelectedPosition in the middle of the screen and then build up and 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * down from there. This method forces mSelectedPosition to the center. 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenTop Top of the area in which children can be drawn, as 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * measured in pixels 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenBottom Bottom of the area in which children can be drawn, 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * as measured in pixels 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Currently selected view 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillFromMiddle(int childrenTop, int childrenBottom) { 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int height = childrenBottom - childrenTop; 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int position = reconcileSelectedPosition(); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View sel = makeAndAddView(position, childrenTop, true, 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left, true); 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = position; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int selHeight = sel.getMeasuredHeight(); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selHeight <= height) { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom((height - selHeight) / 2); 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillAboveAndBelow(sel, position); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooHigh(getChildCount()); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooLow(getChildCount()); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sel; 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Once the selected view as been placed, fill up the visible area above and 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * below it. 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sel The selected view 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The position corresponding to sel 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void fillAboveAndBelow(View sel, int position) { 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = mDividerHeight; 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(position - 1, sel.getTop() - dividerHeight); 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillDown(position + 1, sel.getBottom() + dividerHeight); 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillDown(position + 1, sel.getBottom() + dividerHeight); 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(position - 1, sel.getTop() - dividerHeight); 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills the grid based on positioning the new selection at a specific 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * location. The selection may be moved so that it does not intersect the 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * faded edges. The grid is then filled upwards and downwards from there. 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectedTop Where the selected item should be 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenTop Where to start drawing children 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenBottom Last pixel where children can be drawn 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The view that currently has selection 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillFromSelection(int selectedTop, int childrenTop, int childrenBottom) { 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fadingEdgeLength = getVerticalFadingEdgeLength(); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int selectedPosition = mSelectedPosition; 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View sel; 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength, 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedPosition); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength, 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedPosition); 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = makeAndAddView(selectedPosition, selectedTop, true, mListPadding.left, true); 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Some of the newly selected item extends below the bottom of the list 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sel.getBottom() > bottomSelectionPixel) { 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space available above the selection into which we can scroll 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // upwards 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spaceAbove = sel.getTop() - topSelectionPixel; 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space required to bring the bottom of the selected item 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // fully into view 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spaceBelow = sel.getBottom() - bottomSelectionPixel; 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int offset = Math.min(spaceAbove, spaceBelow); 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now offset the selected item to get it into view 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom(-offset); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (sel.getTop() < topSelectionPixel) { 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space required to bring the top of the selected item fully 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // into view 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spaceAbove = topSelectionPixel - sel.getTop(); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space available below the selection into which we can scroll 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // downwards 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spaceBelow = bottomSelectionPixel - sel.getBottom(); 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int offset = Math.min(spaceAbove, spaceBelow); 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Offset the selected item to get it into view 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom(offset); 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fill in views above and below 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillAboveAndBelow(sel, selectedPosition); 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooHigh(getChildCount()); 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooLow(getChildCount()); 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sel; 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calculate the bottom-most pixel we can draw the selection into 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenBottom Bottom pixel were children can be drawn 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param fadingEdgeLength Length of the fading edge in pixels, if present 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectedPosition The position that will be selected 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The bottom-most pixel we can draw the selection into 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getBottomSelectionPixel(int childrenBottom, int fadingEdgeLength, 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int selectedPosition) { 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottomSelectionPixel = childrenBottom; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selectedPosition != mItemCount - 1) { 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomSelectionPixel -= fadingEdgeLength; 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bottomSelectionPixel; 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calculate the top-most pixel we can draw the selection into 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenTop Top pixel were children can be drawn 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param fadingEdgeLength Length of the fading edge in pixels, if present 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectedPosition The position that will be selected 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The top-most pixel we can draw the selection into 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getTopSelectionPixel(int childrenTop, int fadingEdgeLength, int selectedPosition) { 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // first pixel we can draw the selection into 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int topSelectionPixel = childrenTop; 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selectedPosition > 0) { 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topSelectionPixel += fadingEdgeLength; 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return topSelectionPixel; 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills the list based on positioning the new selection relative to the old 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * selection. The new selection will be placed at, above, or below the 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * location of the new selection depending on how the selection is moving. 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The selection will then be pinned to the visible part of the screen, 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * excluding the edges that are faded. The list is then filled upwards and 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * downwards from there. 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param oldSel The old selected view. Useful for trying to put the new 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * selection in the same place 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param newSel The view that is to become selected. Useful for trying to 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * put the new selection in the same place 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param delta Which way we are moving 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenTop Where to start drawing children 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenBottom Last pixel where children can be drawn 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The view that currently has selection 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View moveSelection(View oldSel, View newSel, int delta, int childrenTop, 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childrenBottom) { 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fadingEdgeLength = getVerticalFadingEdgeLength(); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int selectedPosition = mSelectedPosition; 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View sel; 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength, 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedPosition); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int bottomSelectionPixel = getBottomSelectionPixel(childrenTop, fadingEdgeLength, 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedPosition); 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (delta > 0) { 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Case 1: Scrolling down. 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Before After 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | | | | 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ +-------+ 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | A | | A | 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | 1 | => +-------+ 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ | B | 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | B | | 2 | 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ +-------+ 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | | | | 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Try to keep the top of the previously selected item where it was. 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * oldSel = A 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sel = B 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Put oldSel (A) where it belongs 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldSel = makeAndAddView(selectedPosition - 1, oldSel.getTop(), true, 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left, false); 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = mDividerHeight; 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now put the new selection (B) below that 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = makeAndAddView(selectedPosition, oldSel.getBottom() + dividerHeight, true, 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left, true); 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Some of the newly selected item extends below the bottom of the list 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sel.getBottom() > bottomSelectionPixel) { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space available above the selection into which we can scroll upwards 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spaceAbove = sel.getTop() - topSelectionPixel; 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space required to bring the bottom of the selected item fully into view 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spaceBelow = sel.getBottom() - bottomSelectionPixel; 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't scroll more than half the height of the list 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int halfVerticalSpace = (childrenBottom - childrenTop) / 2; 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int offset = Math.min(spaceAbove, spaceBelow); 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = Math.min(offset, halfVerticalSpace); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We placed oldSel, so offset that item 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldSel.offsetTopAndBottom(-offset); 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now offset the selected item to get it into view 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom(-offset); 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fill in views above and below 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight); 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight); 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (delta < 0) { 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Case 2: Scrolling up. 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Before After 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | | | | 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ +-------+ 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | A | | A | 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ => | 1 | 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | B | +-------+ 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | 2 | | B | 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * +-------+ +-------+ 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * | | | | 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Try to keep the top of the item about to become selected where it was. 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * newSel = A 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * olSel = B 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newSel != null) { 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try to position the top of newSel (A) where it was before it was selected 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = makeAndAddView(selectedPosition, newSel.getTop(), true, mListPadding.left, 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project true); 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If (A) was not on screen and so did not have a view, position 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it above the oldSel (B) 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = makeAndAddView(selectedPosition, oldSel.getTop(), false, mListPadding.left, 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project true); 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Some of the newly selected item extends above the top of the list 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sel.getTop() < topSelectionPixel) { 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space required to bring the top of the selected item fully into view 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spaceAbove = topSelectionPixel - sel.getTop(); 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find space available below the selection into which we can scroll downwards 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spaceBelow = bottomSelectionPixel - sel.getBottom(); 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't scroll more than half the height of the list 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int halfVerticalSpace = (childrenBottom - childrenTop) / 2; 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int offset = Math.min(spaceAbove, spaceBelow); 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = Math.min(offset, halfVerticalSpace); 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Offset the selected item to get it into view 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom(offset); 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fill in views above and below 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillAboveAndBelow(sel, selectedPosition); 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldTop = oldSel.getTop(); 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Case 3: Staying still 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = makeAndAddView(selectedPosition, oldTop, true, mListPadding.left, true); 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We're staying still... 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldTop < childrenTop) { 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ... but the top of the old selection was off screen. 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // (This can happen if the data changes size out from under us) 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newBottom = sel.getBottom(); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newBottom < childrenTop + 20) { 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Not enough visible -- bring it onscreen 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel.offsetTopAndBottom(childrenTop - sel.getTop()); 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fill in views above and below 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillAboveAndBelow(sel, selectedPosition); 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sel; 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Sets up mListPadding 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onMeasure(widthMeasureSpec, heightMeasureSpec); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int widthMode = MeasureSpec.getMode(widthMeasureSpec); 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int heightMode = MeasureSpec.getMode(heightMeasureSpec); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int widthSize = MeasureSpec.getSize(widthMeasureSpec); 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int heightSize = MeasureSpec.getSize(heightMeasureSpec); 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childWidth = 0; 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childHeight = 0; 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED || 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project heightMode == MeasureSpec.UNSPECIFIED)) { 103621875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy final View child = obtainView(0, mIsScrap); 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project measureScrapChild(child, 0, widthMeasureSpec); 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childWidth = child.getMeasuredWidth(); 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeight = child.getMeasuredHeight(); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (recycleOnMeasure()) { 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRecycler.addScrapView(child); 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (widthMode == MeasureSpec.UNSPECIFIED) { 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project widthSize = mListPadding.left + mListPadding.right + childWidth + 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getVerticalScrollbarWidth(); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (heightMode == MeasureSpec.UNSPECIFIED) { 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project heightSize = mListPadding.top + mListPadding.bottom + childHeight + 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getVerticalFadingEdgeLength() * 2; 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (heightMode == MeasureSpec.AT_MOST) { 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: after first layout we should maybe start at the first visible position, not 0 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(widthSize, heightSize); 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidthMeasureSpec = widthMeasureSpec; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void measureScrapChild(View child, int position, int widthMeasureSpec) { 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutParams p = (LayoutParams) child.getLayoutParams(); 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (p == null) { 1070980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup.LayoutParams.WRAP_CONTENT, 0); 10724df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project child.setLayoutParams(p); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project p.viewType = mAdapter.getItemViewType(position); 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left + mListPadding.right, p.width); 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lpHeight = p.height; 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childHeightSpec; 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lpHeight > 0) { 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.measure(childWidthSpec, childHeightSpec); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return True to recycle the views used to measure this ListView in 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UNSPECIFIED/AT_MOST modes, false otherwise. 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1093986003d46add147714ce7e16c9fefa8c18042fc8Romain Guy @ViewDebug.ExportedProperty 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean recycleOnMeasure() { 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Measures the height of the given range of children (inclusive) and 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns the height with this ListView's padding and divider heights 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * included. If maxHeight is provided, the measuring will stop when the 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * current height reaches maxHeight. 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param widthMeasureSpec The width measure spec to be given to a child's 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link View#measure(int, int)}. 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startPosition The position of the first child to be shown. 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param endPosition The (inclusive) position of the last child to be 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * shown. Specify {@link #NO_POSITION} if the last child should be 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the last available child from the adapter. 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxHeight The maximum height that will be returned (if all the 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * children don't fit in this value, this value will be 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returned). 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param disallowPartialChildPosition In general, whether the returned 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * height should only contain entire children. This is more 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * powerful--it is the first inclusive position at which partial 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * children will not be allowed. Example: it looks nice to have 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at least 3 completely visible children, and in portrait this 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will most likely fit; but in landscape there could be times 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when even 2 children can not be completely shown, so a value 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of 2 (remember, inclusive) would be good (assuming 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * startPosition is 0). 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The height of this ListView with the given children. 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition, 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int maxHeight, int disallowPartialChildPosition) { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ListAdapter adapter = mAdapter; 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter == null) { 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mListPadding.top + mListPadding.bottom; 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Include the padding of the list 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int returnedHeight = mListPadding.top + mListPadding.bottom; 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = ((mDividerHeight > 0) && mDivider != null) ? mDividerHeight : 0; 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The previous height value that was less than maxHeight and contained 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // no partial children 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int prevHeightWithoutPartialChild = 0; 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i; 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child; 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mItemCount - 1 since endPosition parameter is inclusive 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition; 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final AbsListView.RecycleBin recycleBin = mRecycler; 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean recyle = recycleOnMeasure(); 114521875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy final boolean[] isScrap = mIsScrap; 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = startPosition; i <= endPosition; ++i) { 114821875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy child = obtainView(i, isScrap); 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project measureScrapChild(child, i, widthMeasureSpec); 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i > 0) { 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Count the divider for all but one child 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project returnedHeight += dividerHeight; 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Recycle the view before we possibly return from the method 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (recyle) { 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recycleBin.addScrapView(child); 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project returnedHeight += child.getMeasuredHeight(); 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnedHeight >= maxHeight) { 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We went over, figure out which height to return. If returnedHeight > maxHeight, 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // then the i'th position did not fit completely. 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1) 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (i > disallowPartialChildPosition) // We've past the min pos 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (prevHeightWithoutPartialChild > 0) // We have a prev height 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (returnedHeight != maxHeight) // i'th child did not fit completely 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? prevHeightWithoutPartialChild 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : maxHeight; 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) { 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prevHeightWithoutPartialChild = returnedHeight; 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // At this point, we went through the range of children, and they each 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // completely fit, so return the returnedHeight 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return returnedHeight; 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int findMotionRow(int y) { 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childCount = getChildCount(); 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (childCount > 0) { 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < childCount; i++) { 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View v = getChildAt(i); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (y <= v.getBottom()) { 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mFirstPosition + i; 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mFirstPosition + childCount - 1; 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Put a specific item at a specific location on the screen and then build 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * up and down from there. 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The reference view to use as the starting point 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param top Pixel offset from the top of this view to the top of the 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * reference view. 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The selected view, or null if the selected view is outside the 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * visible area. 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View fillSpecific(int position, int top) { 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean tempIsSelected = position == mSelectedPosition; 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View temp = makeAndAddView(position, top, true, mListPadding.left, tempIsSelected); 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Possibly changed again in fillUp if we add rows above this one. 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = position; 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View above; 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View below; 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = mDividerHeight; 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = fillUp(position - 1, temp.getTop() - dividerHeight); 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This will correct for the top of the first view not touching the top of the list 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = fillDown(position + 1, temp.getBottom() + dividerHeight); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childCount = getChildCount(); 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (childCount > 0) { 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooHigh(childCount); 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = fillDown(position + 1, temp.getBottom() + dividerHeight); 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This will correct for the bottom of the last view not touching the bottom of the list 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = fillUp(position - 1, temp.getTop() - dividerHeight); 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childCount = getChildCount(); 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (childCount > 0) { 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project correctTooLow(childCount); 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (tempIsSelected) { 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return temp; 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (above != null) { 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return above; 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return below; 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Check if we have dragged the bottom of the list too high (we have pushed the 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top element off the top of the screen when we did not need to). Correct by sliding 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * everything back down. 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childCount Number of children 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void correctTooHigh(int childCount) { 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First see if the last item is visible. If it is not, it is OK for the 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // top of the list to be pushed up. 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastPosition = mFirstPosition + childCount - 1; 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lastPosition == mItemCount - 1 && childCount > 0) { 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get the last child ... 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View lastChild = getChildAt(childCount - 1); 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ... and its bottom edge 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int lastBottom = lastChild.getBottom(); 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is bottom of our drawable area 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int end = (mBottom - mTop) - mListPadding.bottom; 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is how far the bottom edge of the last view is from the bottom of the 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // drawable area 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottomOffset = end - lastBottom; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View firstChild = getChildAt(0); 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int firstTop = firstChild.getTop(); 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure we are 1) Too high, and 2) Either there are more rows above the 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // first row or the first row is scrolled off the top of the drawable area 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bottomOffset > 0 && (mFirstPosition > 0 || firstTop < mListPadding.top)) { 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition == 0) { 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't pull the top too far down 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop); 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Move everything down 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetChildrenTopAndBottom(bottomOffset); 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition > 0) { 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fill the gap that was opened above mFirstPosition with more rows, if 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // possible 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillUp(mFirstPosition - 1, firstChild.getTop() - mDividerHeight); 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Close up the remaining gap 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Check if we have dragged the bottom of the list too low (we have pushed the 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bottom element off the bottom of the screen when we did not need to). Correct by sliding 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * everything back up. 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childCount Number of children 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void correctTooLow(int childCount) { 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First see if the first item is visible. If it is not, it is OK for the 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bottom of the list to be pushed down. 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition == 0 && childCount > 0) { 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get the first child ... 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View firstChild = getChildAt(0); 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ... and its top edge 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int firstTop = firstChild.getTop(); 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is top of our drawable area 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int start = mListPadding.top; 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is bottom of our drawable area 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int end = (mBottom - mTop) - mListPadding.bottom; 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is how far the top edge of the first view is from the top of the 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // drawable area 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int topOffset = firstTop - start; 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View lastChild = getChildAt(childCount - 1); 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int lastBottom = lastChild.getBottom(); 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastPosition = mFirstPosition + childCount - 1; 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure we are 1) Too low, and 2) Either there are more rows below the 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last row or the last row is scrolled off the bottom of the drawable area 13326198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy if (topOffset > 0) { 13336198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy if (lastPosition < mItemCount - 1 || lastBottom > end) { 13346198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy if (lastPosition == mItemCount - 1) { 13356198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy // Don't pull the bottom too far up 13366198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy topOffset = Math.min(topOffset, lastBottom - end); 13376198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy } 13386198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy // Move everything up 13396198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy offsetChildrenTopAndBottom(-topOffset); 13406198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy if (lastPosition < mItemCount - 1) { 13416198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy // Fill the gap that was opened below the last position with more rows, if 13426198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy // possible 13436198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight); 13446198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy // Close up the remaining gap 13456198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy adjustViewsUpOrDown(); 13466198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy } 13476198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy } else if (lastPosition == mItemCount - 1) { 13486198ae8468668bf7374535c2eeeab8de7f8e7e99Romain Guy adjustViewsUpOrDown(); 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void layoutChildren() { 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean blockLayoutRequests = mBlockLayoutRequests; 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!blockLayoutRequests) { 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBlockLayoutRequests = true; 13594df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project } else { 13604df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project return; 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.layoutChildren(); 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter == null) { 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetList(); 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childrenTop = mListPadding.top; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childrenBottom = mBottom - mTop - mListPadding.bottom; 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childCount = getChildCount(); 1378ead0d4d8282b35a10bf8816cd99a62a8499d9031Romain Guy int index = 0; 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int delta = 0; 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View sel; 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View oldSel = null; 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View oldFirst = null; 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View newSel = null; 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View focusLayoutRestoreView = null; 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Remember stuff we will need down below 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mLayoutMode) { 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SET_SELECTION: 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index = mNextSelectedPosition - mFirstPosition; 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index >= 0 && index < childCount) { 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newSel = getChildAt(index); 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_FORCE_TOP: 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_FORCE_BOTTOM: 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SPECIFIC: 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SYNC: 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_MOVE_SELECTION: 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Remember the previously selected view 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index = mSelectedPosition - mFirstPosition; 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index >= 0 && index < childCount) { 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldSel = getChildAt(index); 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Remember the previous first child 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldFirst = getChildAt(0); 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNextSelectedPosition >= 0) { 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delta = mNextSelectedPosition - mSelectedPosition; 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Caution: newSel might be null 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newSel = getChildAt(index + delta); 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean dataChanged = mDataChanged; 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dataChanged) { 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handleDataChanged(); 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Handle the empty set by removing all views that are visible 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and calling it a day 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemCount == 0) { 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetList(); 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1432b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy } else if (mItemCount != mAdapter.getCount()) { 1433b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy throw new IllegalStateException("The content of the adapter has changed but " 1434b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy + "ListView did not receive a notification. Make sure the content of " 1435b45f124a041adf81b3ac8b8dec6b396e751e92d7Romain Guy + "your adapter is not modified from a background thread, but only " 14363940f2df36fbe6a712c88655fc78244977ebd0abOwen Lin + "from the UI thread. [in ListView(" + getId() + ", " + getClass() 14373940f2df36fbe6a712c88655fc78244977ebd0abOwen Lin + ") with Adapter(" + mAdapter.getClass() + ")]"); 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectedPositionInt(mNextSelectedPosition); 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Pull all children into the RecycleBin. 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // These views will be reused if possible 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int firstPosition = mFirstPosition; 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final RecycleBin recycleBin = mRecycler; 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // reset the focus restoration 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View focusLayoutRestoreDirectChild = null; 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't put header or footer views into the Recycler. Those are 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // already cached in mHeaderViews; 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dataChanged) { 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < childCount; i++) { 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recycleBin.addScrapView(getChildAt(i)); 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ViewDebug.TRACE_RECYCLER) { 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewDebug.trace(getChildAt(i), 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i); 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recycleBin.fillActiveViews(childCount, firstPosition); 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // take focus back to us temporarily to avoid the eventual 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // call to clear focus when removing the focused child below 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // from messing things up when ViewRoot assigns focus back 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to someone else 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View focusedChild = getFocusedChild(); 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focusedChild != null) { 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: in some cases focusedChild.getParent() == null 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we can remember the focused view to restore after relayout if the 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // data hasn't changed, or if the focused position is a header or footer 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) { 14764df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project focusLayoutRestoreDirectChild = focusedChild; 14774df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project // remember the specific view that had focus 14784df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project focusLayoutRestoreView = findFocus(); 14794df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (focusLayoutRestoreView != null) { 14804df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project // tell it we are going to mess with it 14814df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project focusLayoutRestoreView.onStartTemporaryDetach(); 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestFocus(); 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Clear out old views 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //removeAllViewsInLayout(); 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project detachAllViewsFromParent(); 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mLayoutMode) { 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SET_SELECTION: 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newSel != null) { 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom); 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillFromMiddle(childrenTop, childrenBottom); 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SYNC: 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillSpecific(mSyncPosition, mSpecificTop); 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_FORCE_BOTTOM: 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillUp(mItemCount - 1, childrenBottom); 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_FORCE_TOP: 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition = 0; 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillFromTop(childrenTop); 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustViewsUpOrDown(); 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_SPECIFIC: 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop); 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case LAYOUT_MOVE_SELECTION: 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom); 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (childCount == 0) { 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int position = lookForSelectablePosition(0, true); 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectedPositionInt(position); 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillFromTop(childrenTop); 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int position = lookForSelectablePosition(mItemCount - 1, false); 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectedPositionInt(position); 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillUp(mItemCount - 1, childrenBottom); 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillSpecific(mSelectedPosition, 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldSel == null ? childrenTop : oldSel.getTop()); 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mFirstPosition < mItemCount) { 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillSpecific(mFirstPosition, 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldFirst == null ? childrenTop : oldFirst.getTop()); 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sel = fillSpecific(0, childrenTop); 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Flush any cached views that did not get reused above 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recycleBin.scrapActiveViews(); 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sel != null) { 15463616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // the current selected item should get focus if items 15473616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // are focusable 15483616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) { 15493616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild && 15503616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy focusLayoutRestoreView.requestFocus()) || sel.requestFocus(); 15513616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (!focusWasTaken) { 15523616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // selected item didn't take focus, fine, but still want 15533616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // to make sure something else outside of the selected view 15543616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // has focus 15553616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy final View focused = getFocusedChild(); 15563616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (focused != null) { 15573616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy focused.clearFocus(); 15583616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 15593616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy positionSelector(sel); 15603616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } else { 15613616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy sel.setSelected(false); 15623616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy mSelectorRect.setEmpty(); 15633616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 15643616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } else { 15653616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy positionSelector(sel); 15663616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 15673616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy mSelectedTop = sel.getTop(); 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15693616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) { 15703616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy View child = getChildAt(mMotionPosition - mFirstPosition); 1571b4c547a56caebb5900c132ec9d5ce953f89de14fRomain Guy if (child != null) positionSelector(child); 15723616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } else { 15733616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy mSelectedTop = 0; 15743616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy mSelectorRect.setEmpty(); 15753616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 15763616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy 15773616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // even if there is not selected position, we may need to restore 15783616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy // focus (i.e. something focusable in touch mode) 15793616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (hasFocus() && focusLayoutRestoreView != null) { 15803616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy focusLayoutRestoreView.requestFocus(); 15813616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // tell focus view we are done mucking with it, if it is still in 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // our view hierarchy. 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focusLayoutRestoreView != null 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && focusLayoutRestoreView.getWindowToken() != null) { 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project focusLayoutRestoreView.onFinishTemporaryDetach(); 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_NORMAL; 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataChanged = false; 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNeedSync = false; 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setNextSelectedPositionInt(mSelectedPosition); 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateScrollIndicators(); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemCount > 0) { 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkSelectionChanged(); 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!blockLayoutRequests) { 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBlockLayoutRequests = false; 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param child a direct child of this list. 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether child is a header or footer view. 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean isDirectChildHeaderOrFooter(View child) { 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<FixedViewInfo> headers = mHeaderViewInfos; 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numHeaders = headers.size(); 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numHeaders; i++) { 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child == headers.get(i).view) { 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<FixedViewInfo> footers = mFooterViewInfos; 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numFooters = footers.size(); 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numFooters; i++) { 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child == footers.get(i).view) { 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Obtain the view and add it to our list of children. The view can be made 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * fresh, converted from an unused view, or used as is if it was in the 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * recycle bin. 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position Logical position in the list 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y Top or bottom edge of the view to add 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flow If flow is true, align top edge to y. If false, align bottom 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * edge to y. 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenLeft Left edge where children should be positioned 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selected Is this position selected? 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return View that was added 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean selected) { 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child; 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mDataChanged) { 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try to use an exsiting view for this position 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child = mRecycler.getActiveView(position); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child != null) { 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ViewDebug.TRACE_RECYCLER) { 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewDebug.trace(child, ViewDebug.RecyclerTraceType.RECYCLE_FROM_ACTIVE_HEAP, 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position, getChildCount()); 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Found it -- we're using an existing child 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This just needs to be positioned 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setupChild(child, position, y, flow, childrenLeft, selected, true); 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return child; 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make a new view for this position, or convert an unused view if possible 166921875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy child = obtainView(position, mIsScrap); 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This needs to be positioned and measured 167221875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return child; 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a view as a child and make sure it is measured (if necessary) and 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * positioned properly. 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param child The view to add 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The position of this child 16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y position relative to which this view will be positioned 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flowDown If true, align top edge to y. If false, align bottom 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * edge to y. 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childrenLeft Left edge where children should be positioned 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selected Is this position selected? 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param recycled Has this view been pulled from the recycle bin? If so it 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * does not need to be remeasured. 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft, 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean selected, boolean recycled) { 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean isSelected = selected && shouldShowSelector(); 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean updateChildSelected = isSelected != child.isSelected(); 16953616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy final int mode = mTouchMode; 16963616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL && 16973616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy mMotionPosition == position; 16983616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy final boolean updateChildPressed = isPressed != child.isPressed(); 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested(); 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Respect layout params that are already in the view. Otherwise make some up... 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // noinspection unchecked 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (p == null) { 1705980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup.LayoutParams.WRAP_CONTENT, 0); 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project p.viewType = mAdapter.getItemViewType(position); 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1710c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (recycled || (p.recycledHeaderFooter && 1711c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) { 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attachViewToParent(child, flowDown ? -1 : 0, p); 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17144df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { 17154df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project p.recycledHeaderFooter = true; 17164df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project } 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addViewInLayout(child, flowDown ? -1 : 0, p, true); 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (updateChildSelected) { 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.setSelected(isSelected); 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17243616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy if (updateChildPressed) { 17253616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy child.setPressed(isPressed); 17263616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy } 17273616a412cbd620168fd87ce83978d83a9c0621c6Romain Guy 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) { 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child instanceof Checkable) { 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((Checkable) child).setChecked(mCheckStates.get(position)); 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToMeasure) { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left + mListPadding.right, p.width); 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lpHeight = p.height; 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childHeightSpec; 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lpHeight > 0) { 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.measure(childWidthSpec, childHeightSpec); 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cleanupLayoutState(child); 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int w = child.getMeasuredWidth(); 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int h = child.getMeasuredHeight(); 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childTop = flowDown ? y : y - h; 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToMeasure) { 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childRight = childrenLeft + w; 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childBottom = childTop + h; 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.layout(childrenLeft, childTop, childRight, childBottom); 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.offsetLeftAndRight(childrenLeft - child.getLeft()); 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.offsetTopAndBottom(childTop - child.getTop()); 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCachingStarted && !child.isDrawingCacheEnabled()) { 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.setDrawingCacheEnabled(true); 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean canAnimate() { 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.canAnimate() && mItemCount > 0; 17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the currently selected item. If in touch mode, the item will not be selected 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * but it will still be positioned appropriately. If the specified selection position 17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is less than 0, then the item at position 0 will be selected. 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position Index (starting at 0) of the data item to be selected. 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setSelection(int position) { 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectionFromTop(position, 0); 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the selected item and positions the selection y pixels from the top edge 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of the ListView. (If in touch mode, the item will not be selected but it will 17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * still be positioned appropriately.) 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position Index (starting at 0) of the data item to be selected. 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The distance from the top edge of the ListView (plus padding) that the 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * item will be positioned. 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setSelectionFromTop(int position, int y) { 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter == null) { 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isInTouchMode()) { 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = lookForSelectablePosition(position, true); 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position >= 0) { 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setNextSelectedPositionInt(position); 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mResurrectToPosition = position; 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position >= 0) { 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_SPECIFIC; 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpecificTop = mListPadding.top + y; 18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNeedSync) { 18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSyncPosition = position; 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSyncRowId = mAdapter.getItemId(position); 18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Makes the item at the supplied position selected. 1822f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron * 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position the position of the item to select 18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void setSelectionInt(int position) { 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setNextSelectedPositionInt(position); 1828f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron boolean awakeScrollbars = false; 1829f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron 1830f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron final int selectedPosition = mSelectedPosition; 1831f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron 1832f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (selectedPosition >= 0) { 1833f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (position == selectedPosition - 1) { 1834f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron awakeScrollbars = true; 1835f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } else if (position == selectedPosition + 1) { 1836f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron awakeScrollbars = true; 1837f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } 1838f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } 1839f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project layoutChildren(); 1841f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron 1842f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (awakeScrollbars) { 1843f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron awakenScrollBars(); 1844f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } 18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Find a position that can be selected (i.e., is not a separator). 18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The starting position to look at. 18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param lookDown Whether to look down for other positions. 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The next selectable position starting at position and then searching either up or 18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * down. Returns {@link #INVALID_POSITION} if nothing can be found. 18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lookForSelectablePosition(int position, boolean lookDown) { 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ListAdapter adapter = mAdapter; 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter == null || isInTouchMode()) { 18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = adapter.getCount(); 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mAreAllItemsSelectable) { 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lookDown) { 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = Math.max(0, position); 18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (position < count && !adapter.isEnabled(position)) { 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position++; 18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = Math.min(position, count - 1); 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (position >= 0 && !adapter.isEnabled(position)) { 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position--; 18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position < 0 || position >= count) { 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return position; 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position < 0 || position >= count) { 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return position; 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 188875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov @Override 188975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 189075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov boolean populated = super.dispatchPopulateAccessibilityEvent(event); 189175986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov 1892d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani // If the item count is less than 15 then subtract disabled items from the count and 1893d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani // position. Otherwise ignore disabled items. 189475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov if (!populated) { 189575986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov int itemCount = 0; 189675986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov int currentItemIndex = getSelectedItemPosition(); 189775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov 189875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov ListAdapter adapter = getAdapter(); 189975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov if (adapter != null) { 1900d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani final int count = adapter.getCount(); 1901d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani if (count < 15) { 1902d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani for (int i = 0; i < count; i++) { 1903d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani if (adapter.isEnabled(i)) { 1904d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani itemCount++; 1905d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani } else if (i <= currentItemIndex) { 1906d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani currentItemIndex--; 1907d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani } 190875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov } 1909d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani } else { 1910d296fafab597a6597d9eb276abe6f6eb049e9f12Amith Yamasani itemCount = count; 191175986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov } 191275986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov } 191375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov 191475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov event.setItemCount(itemCount); 191575986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov event.setCurrentItemIndex(currentItemIndex); 191675986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov } 191775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov 191875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov return populated; 191975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov } 192075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov 19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * setSelectionAfterHeaderView set the selection to be the first list item 19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * after the header views. 19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setSelectionAfterHeaderView() { 19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = mHeaderViewInfos.size(); 19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count > 0) { 19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNextSelectedPosition = 0; 19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter != null) { 19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelection(count); 19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNextSelectedPosition = count; 19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_SET_SELECTION; 19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean dispatchKeyEvent(KeyEvent event) { 19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Dispatch in the normal way 19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean handled = super.dispatchKeyEvent(event); 19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!handled) { 19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we didn't handle it... 19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View focused = getFocusedChild(); 19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focused != null && event.getAction() == KeyEvent.ACTION_DOWN) { 19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ... and our focused child didn't handle it 19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ... give it to ourselves so we can scroll if necessary 19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = onKeyDown(event.getKeyCode(), event); 19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handled; 19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return commonKey(keyCode, 1, event); 19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return commonKey(keyCode, repeatCount, event); 19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyUp(int keyCode, KeyEvent event) { 19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return commonKey(keyCode, 1, event); 19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean commonKey(int keyCode, int count, KeyEvent event) { 19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAdapter == null) { 19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataChanged) { 19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project layoutChildren(); 19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean handled = false; 19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int action = event.getAction(); 19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (action != KeyEvent.ACTION_UP) { 19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSelectedPosition < 0) { 19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (keyCode) { 19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_UP: 19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_DOWN: 19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_CENTER: 19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_ENTER: 19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_SPACE: 19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (resurrectSelection()) { 19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (keyCode) { 19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_UP: 19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!event.isAltPressed()) { 20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (count > 0) { 20019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = arrowScroll(FOCUS_UP); 20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count--; 20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = fullScroll(FOCUS_UP); 20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_DOWN: 20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!event.isAltPressed()) { 20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (count > 0) { 20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = arrowScroll(FOCUS_DOWN); 20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count--; 20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = fullScroll(FOCUS_DOWN); 20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_LEFT: 20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = handleHorizontalFocusWithinListItem(View.FOCUS_LEFT); 20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_RIGHT: 20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = handleHorizontalFocusWithinListItem(View.FOCUS_RIGHT); 20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_DPAD_CENTER: 20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_ENTER: 20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemCount > 0 && event.getRepeatCount() == 0) { 20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyPressed(); 20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = true; 20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.KEYCODE_SPACE: 20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopup == null || !mPopup.isShowing()) { 20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!event.isShiftPressed()) { 20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pageScroll(FOCUS_DOWN); 20399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 20409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pageScroll(FOCUS_UP); 20419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = true; 20439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 20459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!handled) { 20499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = sendToTextFilter(keyCode, count, event); 20509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (handled) { 20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (action) { 20569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.ACTION_DOWN: 20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyDown(keyCode, event); 20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.ACTION_UP: 20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyUp(keyCode, event); 20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case KeyEvent.ACTION_MULTIPLE: 20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyMultiple(keyCode, count, event); 20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: // shouldn't happen 20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 20679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Scrolls up or down by the number of items currently present on screen. 20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} 20759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether selection was moved 20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean pageScroll(int direction) { 20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextPage = -1; 20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean down = false; 20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == FOCUS_UP) { 20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1); 20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (direction == FOCUS_DOWN) { 20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1); 20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project down = true; 20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextPage >= 0) { 20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int position = lookForSelectablePosition(nextPage, down); 20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position >= 0) { 20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_SPECIFIC; 20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpecificTop = mPaddingTop + getVerticalFadingEdgeLength(); 20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (down && position > mItemCount - getChildCount()) { 20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_FORCE_BOTTOM; 20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!down && position < getChildCount()) { 20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_FORCE_TOP; 21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectionInt(position); 21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 2104f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (!awakenScrollBars()) { 2105f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron invalidate(); 2106f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } 21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Go to the last or first item if possible (not worrying about panning across or navigating 21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * within the internal focus of the currently selected item.) 21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} 21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether selection was moved 21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean fullScroll(int direction) { 21249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean moved = false; 21259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == FOCUS_UP) { 21269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSelectedPosition != 0) { 21279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int position = lookForSelectablePosition(0, true); 21289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position >= 0) { 21299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_FORCE_TOP; 21309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectionInt(position); 21319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 21329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project moved = true; 21349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (direction == FOCUS_DOWN) { 21369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSelectedPosition < mItemCount - 1) { 21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int position = lookForSelectablePosition(mItemCount - 1, true); 21389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (position >= 0) { 21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutMode = LAYOUT_FORCE_BOTTOM; 21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectionInt(position); 21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project moved = true; 21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2147f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (moved && !awakenScrollBars()) { 2148f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron awakenScrollBars(); 21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return moved; 21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * To avoid horizontal focus searches changing the selected item, we 21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * manually focus search within the selected item (as applicable), and 21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * prevent focus from jumping to something within another item. 21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction one of {View.FOCUS_LEFT, View.FOCUS_RIGHT} 21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether this consumes the key event. 21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean handleHorizontalFocusWithinListItem(int direction) { 21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT) { 2164304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy throw new IllegalArgumentException("direction must be one of" 2165304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy + " {View.FOCUS_LEFT, View.FOCUS_RIGHT}"); 21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numChildren = getChildCount(); 21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemsCanFocus && numChildren > 0 && mSelectedPosition != INVALID_POSITION) { 21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View selectedView = getSelectedView(); 2171304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy if (selectedView != null && selectedView.hasFocus() && 2172304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy selectedView instanceof ViewGroup) { 2173304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy 21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View currentFocus = selectedView.findFocus(); 21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View nextFocus = FocusFinder.getInstance().findNextFocus( 2176304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy (ViewGroup) selectedView, currentFocus, direction); 21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextFocus != null) { 21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // do the math to get interesting rect in next focus' coordinates 21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project currentFocus.getFocusedRect(mTempRect); 21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetDescendantRectToMyCoords(currentFocus, mTempRect); 21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetRectIntoDescendantCoords(nextFocus, mTempRect); 21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextFocus.requestFocus(direction, mTempRect)) { 21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we are blocking the key from being handled (by returning true) 21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if the global result is going to be some other view within this 21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // list. this is to acheive the overall goal of having 21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // horizontal d-pad navigation remain in the current item. 2190304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy final View globalNextFocus = FocusFinder.getInstance().findNextFocus( 2191304eefa6a33da9b75b4075cc7eb170cf4ced4cdbRomain Guy (ViewGroup) getRootView(), currentFocus, direction); 21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (globalNextFocus != null) { 21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return isViewAncestorOf(globalNextFocus, this); 21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Scrolls to the next or previous item if possible. 22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} 22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether selection was moved 22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean arrowScroll(int direction) { 22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInLayout = true; 22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean handled = arrowScrollImpl(direction); 22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (handled) { 22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handled; 22159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 22169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInLayout = false; 22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handle an arrow scroll going up or down. Take into account whether items are selectable, 22229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * whether there are focusable items etc. 22239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction Either {@link android.view.View#FOCUS_UP} or {@link android.view.View#FOCUS_DOWN}. 22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether any scrolling, selection or focus change occured. 22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean arrowScrollImpl(int direction) { 22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getChildCount() <= 0) { 22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View selectedView = getSelectedView(); 22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextSelectedPosition = lookForSelectablePositionOnScreen(direction); 22359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int amountToScroll = amountToScroll(direction, nextSelectedPosition); 22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we are moving focus, we may OVERRIDE the default behavior 22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrowScrollFocusResult focusResult = mItemsCanFocus ? arrowScrollFocused(direction) : null; 22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focusResult != null) { 22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSelectedPosition = focusResult.getSelectedPosition(); 22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll = focusResult.getAmountToScroll(); 22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needToRedraw = focusResult != null; 22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition != INVALID_POSITION) { 22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handleNewSelectionChange(selectedView, direction, nextSelectedPosition, focusResult != null); 22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelectedPositionInt(nextSelectedPosition); 22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setNextSelectedPositionInt(nextSelectedPosition); 22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView = getSelectedView(); 22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemsCanFocus && focusResult == null) { 22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // there was no new view found to take focus, make sure we 22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // don't leave focus with the old selection 22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View focused = getFocusedChild(); 22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focused != null) { 22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project focused.clearFocus(); 22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project needToRedraw = true; 22599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkSelectionChanged(); 22609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (amountToScroll > 0) { 22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollListItemsBy((direction == View.FOCUS_UP) ? amountToScroll : -amountToScroll); 22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project needToRedraw = true; 22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we didn't find a new focusable, make sure any existing focused 22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // item that was panned off screen gives up focus. 22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemsCanFocus && (focusResult == null) 22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && selectedView != null && selectedView.hasFocus()) { 22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View focused = selectedView.findFocus(); 22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (distanceToView(focused) > 0) { 22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project focused.clearFocus(); 22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if the current selection is panned off, we need to remove the selection 22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition == INVALID_POSITION && selectedView != null 22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && !isViewAncestorOf(selectedView, this)) { 22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView = null; 22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hideSelector(); 22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // but we don't want to set the ressurect position (that would make subsequent 22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unhandled key events bring back the item we just scrolled off!) 22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mResurrectToPosition = INVALID_POSITION; 22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToRedraw) { 22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selectedView != null) { 22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project positionSelector(selectedView); 22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSelectedTop = selectedView.getTop(); 22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2293f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron if (!awakenScrollBars()) { 2294f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron invalidate(); 2295f116bf8884b5b58aae261d148003811aa4a7c6e9Mike Cleron } 22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invokeOnItemScrollListener(); 22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When selection changes, it is possible that the previously selected or the 23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * next selected item will change its size. If so, we need to offset some folks, 23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and re-layout the items as appropriate. 23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectedView The currently selected view (before changing selection). 23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * should be <code>null</code> if there was no previous selection. 23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction Either {@link android.view.View#FOCUS_UP} or 23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.view.View#FOCUS_DOWN}. 23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param newSelectedPosition The position of the next selection. 23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param newFocusAssigned whether new focus was assigned. This matters because 23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when something has focus, we don't want to show selection (ugh). 23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void handleNewSelectionChange(View selectedView, int direction, int newSelectedPosition, 23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean newFocusAssigned) { 23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newSelectedPosition == INVALID_POSITION) { 23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("newSelectedPosition needs to be valid"); 23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // whether or not we are moving down or up, we want to preserve the 23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // top of whatever view is on top: 23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // - moving down: the view that had selection 23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // - moving up: the view that is getting selection 23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View topView; 23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View bottomView; 23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int topViewIndex, bottomViewIndex; 23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean topSelected = false; 23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int selectedIndex = mSelectedPosition - mFirstPosition; 23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int nextSelectedIndex = newSelectedPosition - mFirstPosition; 23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == View.FOCUS_UP) { 23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topViewIndex = nextSelectedIndex; 23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomViewIndex = selectedIndex; 23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topView = getChildAt(topViewIndex); 23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomView = selectedView; 23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topSelected = true; 23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topViewIndex = selectedIndex; 23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomViewIndex = nextSelectedIndex; 23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topView = selectedView; 23429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomView = getChildAt(bottomViewIndex); 23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numChildren = getChildCount(); 23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // start with top view: is it changing size? 23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (topView != null) { 23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project topView.setSelected(!newFocusAssigned && topSelected); 23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project measureAndAdjustDown(topView, topViewIndex, numChildren); 23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is the bottom view changing size? 23549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bottomView != null) { 23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottomView.setSelected(!newFocusAssigned && !topSelected); 23569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project measureAndAdjustDown(bottomView, bottomViewIndex, numChildren); 23579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Re-measure a child, and if its height changes, lay it out preserving its 23629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top, and adjust the children below it appropriately. 23639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param child The child 23649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childIndex The view group index of the child. 23659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numChildren The number of children in the view group. 23669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void measureAndAdjustDown(View child, int childIndex, int numChildren) { 23689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldHeight = child.getHeight(); 23699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project measureItem(child); 23709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child.getMeasuredHeight() != oldHeight) { 23719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // lay out the view, preserving its top 23729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project relayoutMeasuredItem(child); 23739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // adjust views below appropriately 23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int heightDelta = child.getMeasuredHeight() - oldHeight; 23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = childIndex + 1; i < numChildren; i++) { 23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChildAt(i).offsetTopAndBottom(heightDelta); 23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Measure a particular list child. 23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: unify with setUpChild. 23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param child The child. 23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void measureItem(View child) { 23889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup.LayoutParams p = child.getLayoutParams(); 23899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (p == null) { 23909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project p = new ViewGroup.LayoutParams( 2391980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy ViewGroup.LayoutParams.MATCH_PARENT, 23929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup.LayoutParams.WRAP_CONTENT); 23939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, 23969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListPadding.left + mListPadding.right, p.width); 23979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lpHeight = p.height; 23989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childHeightSpec; 23999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lpHeight > 0) { 24009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 24019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.measure(childWidthSpec, childHeightSpec); 24059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 24089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Layout a child that has been measured, preserving its top position. 24099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: unify with setUpChild. 24109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param child The child. 24119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 24129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void relayoutMeasuredItem(View child) { 24139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int w = child.getMeasuredWidth(); 24149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int h = child.getMeasuredHeight(); 24159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childLeft = mListPadding.left; 24169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childRight = childLeft + w; 24179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childTop = child.getTop(); 24189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childBottom = childTop + h; 24199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project child.layout(childLeft, childTop, childRight, childBottom); 24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 24239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The amount to preview next items when arrow srolling. 24249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 24259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getArrowScrollPreviewLength() { 24269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Math.max(MIN_SCROLL_PREVIEW_PIXELS, getVerticalFadingEdgeLength()); 24279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 24309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determine how much we need to scroll in order to get the next selected view 24319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * visible, with a fading edge showing below as applicable. The amount is 24329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * capped at {@link #getMaxScrollAmount()} . 24339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 24349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link android.view.View#FOCUS_UP} or 24359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.view.View#FOCUS_DOWN}. 24369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nextSelectedPosition The position of the next selection, or 24379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #INVALID_POSITION} if there is no next selectable position 24389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The amount to scroll. Note: this is always positive! Direction 24399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * needs to be taken into account when actually scrolling. 24409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 24419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int amountToScroll(int direction, int nextSelectedPosition) { 24429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = getHeight() - mListPadding.bottom; 24439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listTop = mListPadding.top; 24449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numChildren = getChildCount(); 24469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == View.FOCUS_DOWN) { 24489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int indexToMakeVisible = numChildren - 1; 24499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition != INVALID_POSITION) { 24509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project indexToMakeVisible = nextSelectedPosition - mFirstPosition; 24519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int positionToMakeVisible = mFirstPosition + indexToMakeVisible; 24549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View viewToMakeVisible = getChildAt(indexToMakeVisible); 24559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int goalBottom = listBottom; 24579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (positionToMakeVisible < mItemCount - 1) { 24589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goalBottom -= getArrowScrollPreviewLength(); 24599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (viewToMakeVisible.getBottom() <= goalBottom) { 24629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // item is fully visible. 24639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 24649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition != INVALID_POSITION 24679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (goalBottom - viewToMakeVisible.getTop()) >= getMaxScrollAmount()) { 24689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // item already has enough of it visible, changing selection is good enough 24699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 24709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int amountToScroll = (viewToMakeVisible.getBottom() - goalBottom); 24739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((mFirstPosition + numChildren) == mItemCount) { 24759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last is last in list -> make sure we don't scroll past it 24769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int max = getChildAt(numChildren - 1).getBottom() - listBottom; 24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll = Math.min(amountToScroll, max); 24789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Math.min(amountToScroll, getMaxScrollAmount()); 24819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 24829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int indexToMakeVisible = 0; 24839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition != INVALID_POSITION) { 24849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project indexToMakeVisible = nextSelectedPosition - mFirstPosition; 24859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int positionToMakeVisible = mFirstPosition + indexToMakeVisible; 24879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View viewToMakeVisible = getChildAt(indexToMakeVisible); 24889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int goalTop = listTop; 24899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (positionToMakeVisible > 0) { 24909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goalTop += getArrowScrollPreviewLength(); 24919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (viewToMakeVisible.getTop() >= goalTop) { 24939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // item is fully visible. 24949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextSelectedPosition != INVALID_POSITION && 24989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (viewToMakeVisible.getBottom() - goalTop) >= getMaxScrollAmount()) { 24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // item already has enough of it visible, changing selection is good enough 25009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 25019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int amountToScroll = (goalTop - viewToMakeVisible.getTop()); 25049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFirstPosition == 0) { 25059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // first is first in list -> make sure we don't scroll past it 25069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int max = listTop - getChildAt(0).getTop(); 25079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll = Math.min(amountToScroll, max); 25089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Math.min(amountToScroll, getMaxScrollAmount()); 25109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Holds results of focus aware arrow scrolling. 25159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private class ArrowScrollFocusResult { 25179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSelectedPosition; 25189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mAmountToScroll; 25199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 25219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How {@link android.widget.ListView#arrowScrollFocused} returns its values. 25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void populate(int selectedPosition, int amountToScroll) { 25249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSelectedPosition = selectedPosition; 25259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAmountToScroll = amountToScroll; 25269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSelectedPosition() { 25299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSelectedPosition; 25309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getAmountToScroll() { 25339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mAmountToScroll; 25349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 25389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link android.view.View#FOCUS_UP} or 25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.view.View#FOCUS_DOWN}. 25409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The position of the next selectable position of the views that 25419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are currently visible, taking into account the fact that there might 25429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be no selection. Returns {@link #INVALID_POSITION} if there is no 25439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * selectable view on screen in the given direction. 25449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int lookForSelectablePositionOnScreen(int direction) { 25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int firstPosition = mFirstPosition; 25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == View.FOCUS_DOWN) { 25489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int startPos = (mSelectedPosition != INVALID_POSITION) ? 25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSelectedPosition + 1 : 25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project firstPosition; 25519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startPos >= mAdapter.getCount()) { 25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startPos < firstPosition) { 25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project startPos = firstPosition; 25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int lastVisiblePos = getLastVisiblePosition(); 25599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ListAdapter adapter = getAdapter(); 25609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int pos = startPos; pos <= lastVisiblePos; pos++) { 25619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter.isEnabled(pos) 25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) { 25639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pos; 25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int last = firstPosition + getChildCount() - 1; 25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int startPos = (mSelectedPosition != INVALID_POSITION) ? 25699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSelectedPosition - 1 : 25709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project firstPosition + getChildCount() - 1; 25719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startPos < 0) { 25729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 25739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startPos > last) { 25759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project startPos = last; 25769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ListAdapter adapter = getAdapter(); 25799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int pos = startPos; pos >= firstPosition; pos--) { 25809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter.isEnabled(pos) 25819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) { 25829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pos; 25839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 25879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 25909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Do an arrow scroll based on focus searching. If a new view is 25919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given focus, return the selection delta and amount to scroll via 25929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an {@link ArrowScrollFocusResult}, otherwise, return null. 25939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 25949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link android.view.View#FOCUS_UP} or 25959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.view.View#FOCUS_DOWN}. 25969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The result if focus has changed, or <code>null</code>. 25979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 25989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrowScrollFocusResult arrowScrollFocused(final int direction) { 25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View selectedView = getSelectedView(); 26009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View newFocus; 26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selectedView != null && selectedView.hasFocus()) { 26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View oldFocus = selectedView.findFocus(); 26039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction); 26049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 26059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == View.FOCUS_DOWN) { 26069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean topFadingEdgeShowing = (mFirstPosition > 0); 26079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listTop = mListPadding.top + 26089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (topFadingEdgeShowing ? getArrowScrollPreviewLength() : 0); 26099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int ySearchPoint = 26109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (selectedView != null && selectedView.getTop() > listTop) ? 26119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView.getTop() : 26129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project listTop; 26139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTempRect.set(0, ySearchPoint, 0, ySearchPoint); 26149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 26159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean bottomFadingEdgeShowing = 26169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (mFirstPosition + getChildCount() - 1) < mItemCount; 26179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = getHeight() - mListPadding.bottom - 26189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (bottomFadingEdgeShowing ? getArrowScrollPreviewLength() : 0); 26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int ySearchPoint = 26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (selectedView != null && selectedView.getBottom() < listBottom) ? 26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectedView.getBottom() : 26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project listBottom; 26239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTempRect.set(0, ySearchPoint, 0, ySearchPoint); 26249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newFocus = FocusFinder.getInstance().findNextFocusFromRect(this, mTempRect, direction); 26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newFocus != null) { 26299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int positionOfNewFocus = positionOfNewFocus(newFocus); 26309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if the focus change is in a different new position, make sure 26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we aren't jumping over another selectable position 26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSelectedPosition != INVALID_POSITION && positionOfNewFocus != mSelectedPosition) { 26349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int selectablePosition = lookForSelectablePositionOnScreen(direction); 26359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selectablePosition != INVALID_POSITION && 26369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((direction == View.FOCUS_DOWN && selectablePosition < positionOfNewFocus) || 26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (direction == View.FOCUS_UP && selectablePosition > positionOfNewFocus))) { 26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int focusScroll = amountToScrollToNewFocus(direction, newFocus, positionOfNewFocus); 26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int maxScrollAmount = getMaxScrollAmount(); 26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (focusScroll < maxScrollAmount) { 26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not moving too far, safe to give next view focus 26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newFocus.requestFocus(direction); 26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArrowScrollFocusResult.populate(positionOfNewFocus, focusScroll); 26499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mArrowScrollFocusResult; 26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (distanceToView(newFocus) < maxScrollAmount){ 26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Case to consider: 26529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // too far to get entire next focusable on screen, but by going 26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // max scroll amount, we are getting it at least partially in view, 26549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // so give it focus and scroll the max ammount. 26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newFocus.requestFocus(direction); 26569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArrowScrollFocusResult.populate(positionOfNewFocus, maxScrollAmount); 26579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mArrowScrollFocusResult; 26589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 26619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 26649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param newFocus The view that would have focus. 26659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the position that contains newFocus 26669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 26679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int positionOfNewFocus(View newFocus) { 26689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numChildren = getChildCount(); 26699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numChildren; i++) { 26709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View child = getChildAt(i); 26719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isViewAncestorOf(newFocus, child)) { 26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mFirstPosition + i; 26739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("newFocus is not a child of any of the" 26769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " children of the list!"); 26779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 26809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return true if child is an ancestor of parent, (or equal to the parent). 26819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 26829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean isViewAncestorOf(View child, View parent) { 26839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (child == parent) { 26849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 26859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ViewParent theParent = child.getParent(); 26889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (theParent instanceof ViewGroup) && isViewAncestorOf((View) theParent, parent); 26899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 26929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determine how much we need to scroll in order to get newFocus in view. 26939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param direction either {@link android.view.View#FOCUS_UP} or 26949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.view.View#FOCUS_DOWN}. 26959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param newFocus The view that would take focus. 26969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param positionOfNewFocus The position of the list item containing newFocus 26979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The amount to scroll. Note: this is always positive! Direction 26989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * needs to be taken into account when actually scrolling. 26999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 27009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int amountToScrollToNewFocus(int direction, View newFocus, int positionOfNewFocus) { 27019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int amountToScroll = 0; 27029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newFocus.getDrawingRect(mTempRect); 27039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetDescendantRectToMyCoords(newFocus, mTempRect); 27049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == View.FOCUS_UP) { 27059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTempRect.top < mListPadding.top) { 27069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll = mListPadding.top - mTempRect.top; 27079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (positionOfNewFocus > 0) { 27089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll += getArrowScrollPreviewLength(); 27099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 27129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = getHeight() - mListPadding.bottom; 27139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTempRect.bottom > listBottom) { 27149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll = mTempRect.bottom - listBottom; 27159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (positionOfNewFocus < mItemCount - 1) { 27169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project amountToScroll += getArrowScrollPreviewLength(); 27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return amountToScroll; 27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determine the distance to the nearest edge of a view in a particular 27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * direciton. 27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param descendant A descendant of this list. 27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The distance, or 0 if the nearest edge is already on screen. 27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int distanceToView(View descendant) { 27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int distance = 0; 27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project descendant.getDrawingRect(mTempRect); 27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetDescendantRectToMyCoords(descendant, mTempRect); 27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = mBottom - mTop - mListPadding.bottom; 27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTempRect.bottom < mListPadding.top) { 27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project distance = mListPadding.top - mTempRect.bottom; 27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mTempRect.top > listBottom) { 27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project distance = mTempRect.top - listBottom; 27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return distance; 27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Scroll the children by amount, adding a view at the end and removing 27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * views that fall off as necessary. 27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param amount The amount (positive or negative) to scroll. 27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void scrollListItemsBy(int amount) { 27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetChildrenTopAndBottom(amount); 27519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listBottom = getHeight() - mListPadding.bottom; 27539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int listTop = mListPadding.top; 2754c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final AbsListView.RecycleBin recycleBin = mRecycler; 27559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (amount < 0) { 27579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // shifted items up 27589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // may need to pan views into the bottom space 27609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numChildren = getChildCount(); 27619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View last = getChildAt(numChildren - 1); 27629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (last.getBottom() < listBottom) { 27639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int lastVisiblePosition = mFirstPosition + numChildren - 1; 27649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lastVisiblePosition < mItemCount - 1) { 27659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project last = addViewBelow(last, lastVisiblePosition); 27669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numChildren++; 27679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 27689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 27699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // may have brought in the last child of the list that is skinnier 27739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // than the fading edge, thereby leaving space at the end. need 27749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to shift back 27759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (last.getBottom() < listBottom) { 27769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetChildrenTopAndBottom(listBottom - last.getBottom()); 27779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // top views may be panned off screen 27809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View first = getChildAt(0); 27819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (first.getBottom() < listTop) { 2782c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams(); 2783c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { 27842d51bff2b6597804307d8883a071ff18adc2644aRomain Guy detachViewFromParent(first); 2785c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project recycleBin.addScrapView(first); 2786c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 27872d51bff2b6597804307d8883a071ff18adc2644aRomain Guy removeViewInLayout(first); 2788c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 27899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project first = getChildAt(0); 27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition++; 27919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // shifted items down 27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View first = getChildAt(0); 27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // may need to pan views into top 27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((first.getTop() > listTop) && (mFirstPosition > 0)) { 27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project first = addViewAbove(first, mFirstPosition); 27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFirstPosition--; 28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // may have brought the very first child of the list in too far and 28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to shift it back 28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (first.getTop() > listTop) { 28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetChildrenTopAndBottom(listTop - first.getTop()); 28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastIndex = getChildCount() - 1; 28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View last = getChildAt(lastIndex); 28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bottom view may be panned off screen 28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (last.getTop() > listBottom) { 2813c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams(); 2814c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { 28152d51bff2b6597804307d8883a071ff18adc2644aRomain Guy detachViewFromParent(last); 2816c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project recycleBin.addScrapView(last); 2817c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 28182d51bff2b6597804307d8883a071ff18adc2644aRomain Guy removeViewInLayout(last); 2819c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 28209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project last = getChildAt(--lastIndex); 28219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View addViewAbove(View theView, int position) { 28269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int abovePosition = position - 1; 282721875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy View view = obtainView(abovePosition, mIsScrap); 28289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int edgeOfNewChild = theView.getTop() - mDividerHeight; 282921875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left, 283021875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy false, mIsScrap[0]); 28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View addViewBelow(View theView, int position) { 28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int belowPosition = position + 1; 283621875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy View view = obtainView(belowPosition, mIsScrap); 28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int edgeOfNewChild = theView.getBottom() + mDividerHeight; 283821875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left, 283921875052adddf2b52bc57fea62bf097b8aa04cbfRomain Guy false, mIsScrap[0]); 28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 28419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 28449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Indicates that the views created by the ListAdapter can contain focusable 28459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * items. 28469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 28479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param itemsCanFocus true if items can get focus, false otherwise 28489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 28499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setItemsCanFocus(boolean itemsCanFocus) { 28509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mItemsCanFocus = itemsCanFocus; 28519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!itemsCanFocus) { 28529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 28539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 28579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the views created by the ListAdapter can contain focusable 28589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * items. 28599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 28609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean getItemsCanFocus() { 28619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mItemsCanFocus; 28629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28642d6afea6813be3081138874cf879ac8b0860e4efRomain Guy /** 28652d6afea6813be3081138874cf879ac8b0860e4efRomain Guy * @hide Pending API council approval. 28662d6afea6813be3081138874cf879ac8b0860e4efRomain Guy */ 28679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 286824443ea3992e372e47daa50266b0f2ec38cac388Romain Guy public boolean isOpaque() { 28698f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy return (mCachingStarted && mIsCacheColorOpaque && mDividerIsOpaque && 28708f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy hasOpaqueScrollbars()) || super.isOpaque(); 287124443ea3992e372e47daa50266b0f2ec38cac388Romain Guy } 287224443ea3992e372e47daa50266b0f2ec38cac388Romain Guy 287324443ea3992e372e47daa50266b0f2ec38cac388Romain Guy @Override 287424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy public void setCacheColorHint(int color) { 28758f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy final boolean opaque = (color >>> 24) == 0xFF; 28768f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy mIsCacheColorOpaque = opaque; 28778f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy if (opaque) { 2878a02903fbee6725563da4472bd120f844e9d5518cRomain Guy if (mDividerPaint == null) { 2879a02903fbee6725563da4472bd120f844e9d5518cRomain Guy mDividerPaint = new Paint(); 2880a02903fbee6725563da4472bd120f844e9d5518cRomain Guy } 28818f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy mDividerPaint.setColor(color); 28828f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy } 288324443ea3992e372e47daa50266b0f2ec38cac388Romain Guy super.setCacheColorHint(color); 288424443ea3992e372e47daa50266b0f2ec38cac388Romain Guy } 288524443ea3992e372e47daa50266b0f2ec38cac388Romain Guy 288624443ea3992e372e47daa50266b0f2ec38cac388Romain Guy @Override 28879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void dispatchDraw(Canvas canvas) { 28889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw the dividers 28899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int dividerHeight = mDividerHeight; 28909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dividerHeight > 0 && mDivider != null) { 28929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Only modify the top and bottom in the loop, we set the left and right here 28939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect bounds = mTempRect; 28949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.left = mPaddingLeft; 28959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.right = mRight - mLeft - mPaddingRight; 28969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = getChildCount(); 28989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int headerCount = mHeaderViewInfos.size(); 28999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int footerLimit = mItemCount - mFooterViewInfos.size() - 1; 29009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean headerDividers = mHeaderDividersEnabled; 29019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean footerDividers = mFooterDividersEnabled; 29029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int first = mFirstPosition; 29032bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy final boolean areAllItemsSelectable = mAreAllItemsSelectable; 29042bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy final ListAdapter adapter = mAdapter; 2905e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy // If the list is opaque *and* the background is not, we want to 2906e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy // fill a rect where the dividers would be for non-selectable items 2907e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy // If the list is opaque and the background is also opaque, we don't 2908e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy // need to draw anything since the background will do it for us 2909e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy final boolean fillForMissingDividers = isOpaque() && !super.isOpaque(); 2910e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy 2911e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) { 2912a02903fbee6725563da4472bd120f844e9d5518cRomain Guy mDividerPaint = new Paint(); 2913e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy mDividerPaint.setColor(getCacheColorHint()); 2914a02903fbee6725563da4472bd120f844e9d5518cRomain Guy } 29158f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy final Paint paint = mDividerPaint; 29169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mStackFromBottom) { 29189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom; 29190b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell int listBottom = mBottom - mTop - mListPadding.bottom + mScrollY; 29200b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell 29210b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell // Draw top divider for overscroll 29220b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell if (count > 0 && mScrollY < 0) { 29230b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell bounds.bottom = 0; 29240b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell bounds.top = -dividerHeight; 29250b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell drawDivider(canvas, bounds, -1); 29260b8bb4282a7d1afb24f8c4d5beb2ca4ecc731116Adam Powell } 29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((headerDividers || first + i >= headerCount) && 29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (footerDividers || first + i < footerLimit)) { 29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child = getChildAt(i); 29329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = child.getBottom(); 29332bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy // Don't draw dividers next to items that are not enabled 29348f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy if (bottom < listBottom) { 29358f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy if ((areAllItemsSelectable || 29368f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy (adapter.isEnabled(first + i) && (i == count - 1 || 29378f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy adapter.isEnabled(first + i + 1))))) { 29388f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.top = bottom; 29398f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.bottom = bottom + dividerHeight; 29408f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy drawDivider(canvas, bounds, i); 2941e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy } else if (fillForMissingDividers) { 29428f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.top = bottom; 29438f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.bottom = bottom + dividerHeight; 29448f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy canvas.drawRect(bounds, paint); 29458f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy } 29469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 29509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top; 29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int listTop = mListPadding.top; 29529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((headerDividers || first + i >= headerCount) && 29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (footerDividers || first + i < footerLimit)) { 29569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View child = getChildAt(i); 29579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = child.getTop(); 29582bed22744281a093ee5e76eab531819f3c62b0bfRomain Guy // Don't draw dividers next to items that are not enabled 29598f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy if (top > listTop) { 29608f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy if ((areAllItemsSelectable || 29618f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy (adapter.isEnabled(first + i) && (i == count - 1 || 29628f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy adapter.isEnabled(first + i + 1))))) { 29638f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.top = top - dividerHeight; 29648f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.bottom = top; 29658f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy // Give the method the child ABOVE the divider, so we 29668f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy // subtract one from our child 29678f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy // position. Give -1 when there is no child above the 29688f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy // divider. 29698f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy drawDivider(canvas, bounds, i - 1); 2970e32edc614e62ac874a969d3cc6bb1e0c0c3f2607Romain Guy } else if (fillForMissingDividers) { 29718f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.top = top - dividerHeight; 29728f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy bounds.bottom = top; 29738f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy canvas.drawRect(bounds, paint); 29748f1344f5e7c92f2fd532f65e5584afe0e4cc6b11Romain Guy } 29759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw the indicators (these should be drawn above the dividers) and children 29829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.dispatchDraw(canvas); 29839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 29869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Draws a divider for the given child in the given bounds. 29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param canvas The canvas to draw to. 29899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bounds The bounds of the divider. 29909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param childIndex The index of child (of the View) above the divider. 29919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will be -1 if there is no child above the divider to be 29929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * drawn. 29939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 29949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void drawDivider(Canvas canvas, Rect bounds, int childIndex) { 29959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This widget draws the same divider for all children 29969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Drawable divider = mDivider; 29979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean clipDivider = mClipDivider; 29989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!clipDivider) { 30009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project divider.setBounds(bounds); 30019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 30029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.save(); 30039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.clipRect(bounds); 30049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project divider.draw(canvas); 30079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (clipDivider) { 30099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.restore(); 30109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the drawable that will be drawn between each item in the list. 30159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the current drawable drawn between list elements 30179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Drawable getDivider() { 30199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDivider; 30209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the drawable that will be drawn between each item in the list. If the drawable does 30249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * not have an intrinsic height, you should also call {@link #setDividerHeight(int)} 30259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param divider The drawable to use. 30279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDivider(Drawable divider) { 30299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (divider != null) { 30309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDividerHeight = divider.getIntrinsicHeight(); 30319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClipDivider = divider instanceof ColorDrawable; 30329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 30339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDividerHeight = 0; 30349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClipDivider = false; 30359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDivider = divider; 303724443ea3992e372e47daa50266b0f2ec38cac388Romain Guy mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE; 30389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayoutIfNecessary(); 30399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns the height of the divider that will be drawn between each item in the list. 30439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDividerHeight() { 30459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDividerHeight; 30469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the height of the divider that will be drawn between each item in the list. Calling 30509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this will override the intrinsic height as set by {@link #setDivider(Drawable)} 30519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param height The new height of the divider in pixels. 30539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDividerHeight(int height) { 30559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDividerHeight = height; 30569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayoutIfNecessary(); 30579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables the drawing of the divider for header views. 30619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param headerDividersEnabled True to draw the headers, false otherwise. 30639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setFooterDividersEnabled(boolean) 30659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #addHeaderView(android.view.View) 30669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setHeaderDividersEnabled(boolean headerDividersEnabled) { 30689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHeaderDividersEnabled = headerDividersEnabled; 30699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 30709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 30739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables the drawing of the divider for footer views. 30749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param footerDividersEnabled True to draw the footers, false otherwise. 30769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 30779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setHeaderDividersEnabled(boolean) 30789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #addFooterView(android.view.View) 30799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 30809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFooterDividersEnabled(boolean footerDividersEnabled) { 30819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFooterDividersEnabled = footerDividersEnabled; 30829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 30839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 30869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 30879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 30889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 30899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int closetChildIndex = -1; 30909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (gainFocus && previouslyFocusedRect != null) { 30919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previouslyFocusedRect.offset(mScrollX, mScrollY); 30929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3093c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell final ListAdapter adapter = mAdapter; 3094c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell final int firstPosition = mFirstPosition; 3095c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell // Don't cache the result of getChildCount here, it could change in layoutChildren. 3096c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell if (adapter.getCount() < getChildCount() + firstPosition) { 3097c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell mLayoutMode = LAYOUT_NORMAL; 3098c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell layoutChildren(); 3099c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell } 3100c854f281a1c330931a2a03eef802ad7d4521998eAdam Powell 31019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out which item should be selected based on previously 31029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // focused rect 31039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Rect otherRect = mTempRect; 31049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int minDistance = Integer.MAX_VALUE; 31059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int childCount = getChildCount(); 31069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < childCount; i++) { 31089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // only consider selectable views 31099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!adapter.isEnabled(firstPosition + i)) { 31109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 31119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View other = getChildAt(i); 31149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project other.getDrawingRect(otherRect); 31159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offsetDescendantRectToMyCoords(other, otherRect); 31169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int distance = getDistance(previouslyFocusedRect, otherRect, direction); 31179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (distance < minDistance) { 31199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project minDistance = distance; 31209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closetChildIndex = i; 31219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (closetChildIndex >= 0) { 31269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSelection(closetChildIndex + mFirstPosition); 31279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 31289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 31299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 31349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (non-Javadoc) 31359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 31369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Children specified in XML are assumed to be header views. After we have 31379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * parsed them move them out of the children list and into mHeaderViews. 31389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 31399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 31409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onFinishInflate() { 31419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onFinishInflate(); 31429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = getChildCount(); 31449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count > 0) { 31459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; ++i) { 31469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addHeaderView(getChildAt(i)); 31479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeAllViews(); 31499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* (non-Javadoc) 31539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.View#findViewById(int) 31549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * First look in our children, then in any header and footer views that may be scrolled off. 31559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 31569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 31579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected View findViewTraversal(int id) { 31589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View v; 31599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = super.findViewTraversal(id); 31609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v == null) { 31619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = findViewInHeadersOrFooters(mHeaderViewInfos, id); 31629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 31639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 31649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = findViewInHeadersOrFooters(mFooterViewInfos, id); 31669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 31679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 31689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 31719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* (non-Javadoc) 31749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 31759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Look in the passed in list of headers or footers for the view. 31769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 31779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) { 31789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where != null) { 31799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = where.size(); 31809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View v; 31819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < len; i++) { 31839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = where.get(i).view; 31849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!v.isRootNamespace()) { 31869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = v.findViewById(id); 31879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 31899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 31909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 31959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* (non-Javadoc) 31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.View#findViewWithTag(String) 31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * First look in our children, then in any header and footer views that may be scrolled off. 32009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 32019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 32029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected View findViewWithTagTraversal(Object tag) { 32039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View v; 32049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = super.findViewWithTagTraversal(tag); 32059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v == null) { 32069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = findViewTagInHeadersOrFooters(mHeaderViewInfos, tag); 32079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 32089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 32099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = findViewTagInHeadersOrFooters(mFooterViewInfos, tag); 32129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 32139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 32149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 32179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* (non-Javadoc) 32209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 32219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Look in the passed in list of headers or footers for the view with the tag. 32229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 32239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View findViewTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) { 32249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where != null) { 32259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = where.size(); 32269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View v; 32279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < len; i++) { 32299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = where.get(i).view; 32309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!v.isRootNamespace()) { 32329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = v.findViewWithTag(tag); 32339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v != null) { 32359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 32369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 32419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 32449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTouchEvent(MotionEvent ev) { 32459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mItemsCanFocus && ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 32469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't handle edge touches immediately -- they may actually belong to one of our 32479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // descendants. 32489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 32499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onTouchEvent(ev); 32519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 32549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setChoiceMode(int) 32559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 32569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The current choice mode 32579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 32589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getChoiceMode() { 32599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mChoiceMode; 32609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 32639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the choice behavior for the List. By default, Lists do not have any choice behavior 32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the 32659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * List allows up to one item to be in a chosen state. By setting the choiceMode to 32669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen. 32679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 32689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or 32699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #CHOICE_MODE_MULTIPLE} 32709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 32719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setChoiceMode(int choiceMode) { 32729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mChoiceMode = choiceMode; 32739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates == null) { 32749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates = new SparseBooleanArray(); 32759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 32799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean performItemClick(View view, int position, long id) { 32809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean handled = false; 32819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode != CHOICE_MODE_NONE) { 32839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled = true; 32849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode == CHOICE_MODE_MULTIPLE) { 32869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean oldValue = mCheckStates.get(position, false); 32879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.put(position, !oldValue); 32889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 32899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean oldValue = mCheckStates.get(position, false); 32909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!oldValue) { 32919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.clear(); 32929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.put(position, true); 32939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 32969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataChanged = true; 32979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rememberSyncState(); 32989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 32999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handled |= super.performItemClick(view, position, id); 33029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handled; 33049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 33079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the checked state of the specified position. The is only valid if 33089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or 33099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #CHOICE_MODE_MULTIPLE}. 33109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The item whose checked state is to be checked 33129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param value The new checked sate for the item 33139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 33149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setItemChecked(int position, boolean value) { 33159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode == CHOICE_MODE_NONE) { 33169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 33179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode == CHOICE_MODE_MULTIPLE) { 33209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.put(position, value); 33219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3322845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot // Clear all values if we're checking something, or unchecking the currently 3323845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot // selected item 3324845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot if (value || isItemChecked(position)) { 3325845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot mCheckStates.clear(); 3326845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot } 33278842f0bd5c97cb39f6912392f34ba7435c275a42Romain Guy // this may end up selecting the value we just cleared but this way 3328845df82084a0d3b14cdfb5baafea5c6b94967117Brett Chabot // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on 33298842f0bd5c97cb39f6912392f34ba7435c275a42Romain Guy if (value) { 33309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.put(position, true); 33319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Do not generate a data change while we are in the layout phase 33359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mInLayout && !mBlockLayoutRequests) { 33369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataChanged = true; 33379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rememberSyncState(); 33389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 33399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 33439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the checked state of the specified position. The result is only 3344abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE} 33459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or {@link #CHOICE_MODE_MULTIPLE}. 33469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param position The item whose checked state to return 3348abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * @return The item's checked state or <code>false</code> if choice mode 3349abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * is invalid 33509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setChoiceMode(int) 33529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 33539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isItemChecked(int position) { 33549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) { 33559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mCheckStates.get(position); 33569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 33599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 33629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the currently checked item. The result is only valid if the choice 3363abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * mode has been set to {@link #CHOICE_MODE_SINGLE}. 33649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The position of the currently checked item or 33669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #INVALID_POSITION} if nothing is selected 33679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setChoiceMode(int) 33699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 33709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getCheckedItemPosition() { 33719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) { 33729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mCheckStates.keyAt(0); 33739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return INVALID_POSITION; 33769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 33799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the set of checked items in the list. The result is only valid if 3380abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * the choice mode has not been set to {@link #CHOICE_MODE_NONE}. 33819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 33829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A SparseBooleanArray which will return true for each call to 3383abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * get(int position) where position is a position in the list, 3384abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * or <code>null</code> if the choice mode is set to 3385abca4e8384c71721670f860b0d6d544fde8559ccKenny Root * {@link #CHOICE_MODE_NONE}. 33869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 33879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SparseBooleanArray getCheckedItemPositions() { 33889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChoiceMode != CHOICE_MODE_NONE) { 33899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mCheckStates; 33909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 33929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 33939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3395ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy * Returns the set of checked items ids. The result is only valid if 3396ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}. 3397ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy * 3398ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy * @return A new array which contains the id of each checked item in the list. 3399ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy */ 3400ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy public long[] getCheckItemIds() { 3401ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null && mAdapter != null) { 3402ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy final SparseBooleanArray states = mCheckStates; 3403ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy final int count = states.size(); 3404ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy final long[] ids = new long[count]; 3405ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy final ListAdapter adapter = mAdapter; 3406ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy 3407ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy for (int i = 0; i < count; i++) { 3408ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy ids[i]= adapter.getItemId(states.keyAt(i)); 3409ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy } 3410ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy 3411ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy return ids; 3412ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy } 3413ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy 3414ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy return new long[0]; 3415ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy } 3416ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy 3417ad28bed52ccabd252149b5297a2d94bacdb388ccRomain Guy /** 34189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear any choices previously set 34199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 34209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearChoices() { 34219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCheckStates != null) { 34229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates.clear(); 34239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class SavedState extends BaseSavedState { 34279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SparseBooleanArray checkState; 34289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 34309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link ListView#onSaveInstanceState()} 34319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 34329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SavedState(Parcelable superState, SparseBooleanArray checkState) { 34339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(superState); 34349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.checkState = checkState; 34359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 34389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link #CREATOR} 34399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 34409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcel in) { 34419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(in); 34429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkState = in.readSparseBooleanArray(); 34439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 34469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel out, int flags) { 34479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.writeToParcel(out, flags); 34489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeSparseBooleanArray(checkState); 34499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 34529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 34539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "ListView.SavedState{" 34549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Integer.toHexString(System.identityHashCode(this)) 34559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " checkState=" + checkState + "}"; 34569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<SavedState> CREATOR 34599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = new Parcelable.Creator<SavedState>() { 34609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState createFromParcel(Parcel in) { 34619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(in); 34629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState[] newArray(int size) { 34659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState[size]; 34669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 34689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 34719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Parcelable onSaveInstanceState() { 34729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parcelable superState = super.onSaveInstanceState(); 34739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(superState, mCheckStates); 34749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 34779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRestoreInstanceState(Parcelable state) { 34789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SavedState ss = (SavedState) state; 34799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onRestoreInstanceState(ss.getSuperState()); 34819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ss.checkState != null) { 34839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckStates = ss.checkState; 34849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3488