179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes/* 279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Copyright (C) 2006 The Android Open Source Project 379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * you may not use this file except in compliance with the License. 679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * You may obtain a copy of the License at 779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * http://www.apache.org/licenses/LICENSE-2.0 979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 1079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Unless required by applicable law or agreed to in writing, software 1179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * distributed under the License is distributed on an "AS IS" BASIS, 1279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * See the License for the specific language governing permissions and 1479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * limitations under the License. 1579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 1679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 17da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownpackage android.support.v7.internal.widget; 18da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brown 1979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.content.Context; 2079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.database.DataSetObserver; 2179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.graphics.Rect; 2279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.os.Parcel; 2379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.os.Parcelable; 2479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.util.AttributeSet; 2579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.util.SparseArray; 2679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.view.View; 2779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.view.ViewGroup; 2879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesimport android.widget.SpinnerAdapter; 2979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 3079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes/** 3179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * An abstract base class for spinner widgets. SDK users will probably not 3279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * need to use this class. 3379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 3479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banesabstract class AbsSpinnerICS extends AdapterViewICS<SpinnerAdapter> { 3579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes SpinnerAdapter mAdapter; 3679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 3779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mHeightMeasureSpec; 3879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mWidthMeasureSpec; 3979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes boolean mBlockLayoutRequests; 4079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 4179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mSelectionLeftPadding = 0; 4279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mSelectionTopPadding = 0; 4379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mSelectionRightPadding = 0; 4479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int mSelectionBottomPadding = 0; 4579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final Rect mSpinnerPadding = new Rect(); 4679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 4779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final RecycleBin mRecycler = new RecycleBin(); 4879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes private DataSetObserver mDataSetObserver; 4979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 5079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** Temporary frame to hold a child View's frame rectangle */ 5179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes private Rect mTouchFrame; 5279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 5379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes AbsSpinnerICS(Context context) { 5479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super(context); 5579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes initAbsSpinner(); 5679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 5779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 5879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes AbsSpinnerICS(Context context, AttributeSet attrs) { 5979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes this(context, attrs, 0); 6079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 6179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 6279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes AbsSpinnerICS(Context context, AttributeSet attrs, int defStyle) { 6379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super(context, attrs, defStyle); 6479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes initAbsSpinner(); 6579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 6679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 6779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 6879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Common code for different constructor flavors 6979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 7079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes private void initAbsSpinner() { 7179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setFocusable(true); 7279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setWillNotDraw(false); 7379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 7479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 7579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 7679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * The Adapter is used to provide the data which backs this Spinner. 7779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * It also provides methods to transform spinner items based on their position 7879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * relative to the selected item. 7979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @param adapter The SpinnerAdapter to use for this Spinner 8079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 8179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 8279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void setAdapter(SpinnerAdapter adapter) { 8379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (null != mAdapter) { 8479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mAdapter.unregisterDataSetObserver(mDataSetObserver); 8579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes resetList(); 8679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 8779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 8879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mAdapter = adapter; 8979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 9079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mOldSelectedPosition = INVALID_POSITION; 9179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mOldSelectedRowId = INVALID_ROW_ID; 9279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 9379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (mAdapter != null) { 9479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mOldItemCount = mItemCount; 9579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mItemCount = mAdapter.getCount(); 9679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes checkFocus(); 9779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 9879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mDataSetObserver = new AdapterDataSetObserver(); 9979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mAdapter.registerDataSetObserver(mDataSetObserver); 10079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 10179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int position = mItemCount > 0 ? 0 : INVALID_POSITION; 10279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 10379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setSelectedPositionInt(position); 10479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setNextSelectedPositionInt(position); 10579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 10679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (mItemCount == 0) { 10779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Nothing selected 10879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes checkSelectionChanged(); 10979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 11079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 11179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } else { 11279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes checkFocus(); 11379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes resetList(); 11479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Nothing selected 11579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes checkSelectionChanged(); 11679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 11779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 11879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes requestLayout(); 11979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 12079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 12179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 12279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Clear out all children from the list 12379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 12479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes void resetList() { 12579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mDataChanged = false; 12679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mNeedSync = false; 12779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 12879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes removeAllViewsInLayout(); 12979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mOldSelectedPosition = INVALID_POSITION; 13079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mOldSelectedRowId = INVALID_ROW_ID; 13179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 13279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setSelectedPositionInt(INVALID_POSITION); 13379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setNextSelectedPositionInt(INVALID_POSITION); 13479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes invalidate(); 13579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 13679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 13779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 13879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @see android.view.View#measure(int, int) 13979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 14079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Figure out the dimensions of this Spinner. The width comes from 14179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * the widthMeasureSpec as Spinnners can't have their width set to 14279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * UNSPECIFIED. The height is based on the height of the selected item 14379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * plus padding. 14479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 14579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 14679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 14779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int widthMode = MeasureSpec.getMode(widthMeasureSpec); 14879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int widthSize; 14979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int heightSize; 15079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 15179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int paddingLeft = getPaddingLeft(); 15279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int paddingTop = getPaddingTop(); 15379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int paddingRight = getPaddingRight(); 15479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int paddingBottom = getPaddingBottom(); 15579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 15679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSpinnerPadding.left = paddingLeft > mSelectionLeftPadding ? paddingLeft 15779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes : mSelectionLeftPadding; 15879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSpinnerPadding.top = paddingTop > mSelectionTopPadding ? paddingTop 15979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes : mSelectionTopPadding; 16079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSpinnerPadding.right = paddingRight > mSelectionRightPadding ? paddingRight 16179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes : mSelectionRightPadding; 16279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSpinnerPadding.bottom = paddingBottom > mSelectionBottomPadding ? paddingBottom 16379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes : mSelectionBottomPadding; 16479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 16579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (mDataChanged) { 16679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes handleDataChanged(); 16779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 16879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 16979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int preferredHeight = 0; 17079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int preferredWidth = 0; 17179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes boolean needsMeasuring = true; 17279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 17379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int selectedPosition = getSelectedItemPosition(); 17479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) { 17579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Try looking in the recycler. (Maybe we were measured once already) 17679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes View view = mRecycler.get(selectedPosition); 17779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (view == null) { 17879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Make a new one 17979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes view = mAdapter.getView(selectedPosition, null, this); 18079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 18179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 18279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (view != null) { 18379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Put in recycler for re-measuring and/or layout 18479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mRecycler.put(selectedPosition, view); 18579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 18679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 18779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (view != null) { 18879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (view.getLayoutParams() == null) { 18979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mBlockLayoutRequests = true; 19079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes view.setLayoutParams(generateDefaultLayoutParams()); 19179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mBlockLayoutRequests = false; 19279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 19379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes measureChild(view, widthMeasureSpec, heightMeasureSpec); 19479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 19579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom; 19679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right; 19779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 19879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes needsMeasuring = false; 19979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 20079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 20179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 20279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (needsMeasuring) { 20379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // No views -- just use padding 20479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom; 20579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (widthMode == MeasureSpec.UNSPECIFIED) { 20679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right; 20779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 20879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 20979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 21079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight()); 21179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth()); 21279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 21379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes heightSize = resolveSize(preferredHeight, heightMeasureSpec); 21479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes widthSize = resolveSize(preferredWidth, widthMeasureSpec); 21579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 21679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setMeasuredDimension(widthSize, heightSize); 21779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mHeightMeasureSpec = heightMeasureSpec; 21879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mWidthMeasureSpec = widthMeasureSpec; 21979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 22079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 22179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int getChildHeight(View child) { 22279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return child.getMeasuredHeight(); 22379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 22479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 22579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int getChildWidth(View child) { 22679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return child.getMeasuredWidth(); 22779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 22879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 22979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 23079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 23179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return new ViewGroup.LayoutParams( 23279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes ViewGroup.LayoutParams.MATCH_PARENT, 23379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes ViewGroup.LayoutParams.WRAP_CONTENT); 23479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 23579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 23679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes void recycleAllViews() { 23779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int childCount = getChildCount(); 23879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final AbsSpinnerICS.RecycleBin recycleBin = mRecycler; 23979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int position = mFirstPosition; 24079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 24179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // All views go in recycler 24279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes for (int i = 0; i < childCount; i++) { 24379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes View v = getChildAt(i); 24479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int index = position + i; 24579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes recycleBin.put(index, v); 24679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 24779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 24879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 24979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 25079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Jump directly to a specific item in the adapter data. 25179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 25279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void setSelection(int position, boolean animate) { 25379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // Animate only if requested position is already on screen somewhere 25479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes boolean shouldAnimate = animate && mFirstPosition <= position && 25579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes position <= mFirstPosition + getChildCount() - 1; 25679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setSelectionInt(position, shouldAnimate); 25779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 25879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 25979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 26079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void setSelection(int position) { 26179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setNextSelectedPositionInt(position); 26279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes requestLayout(); 26379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes invalidate(); 26479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 26579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 26679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 26779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 26879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Makes the item at the supplied position selected. 26979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 27079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @param position Position to select 27179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @param animate Should the transition be animated 27279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 27379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 27479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes void setSelectionInt(int position, boolean animate) { 27579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (position != mOldSelectedPosition) { 27679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mBlockLayoutRequests = true; 27779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int delta = position - mSelectedPosition; 27879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes setNextSelectedPositionInt(position); 27979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes layout(delta, animate); 28079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mBlockLayoutRequests = false; 28179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 28279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 28379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 28479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes abstract void layout(int delta, boolean animate); 28579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 28679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 28779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public View getSelectedView() { 28879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (mItemCount > 0 && mSelectedPosition >= 0) { 28979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return getChildAt(mSelectedPosition - mFirstPosition); 29079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } else { 29179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return null; 29279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 29379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 29479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 29579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 29679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Override to prevent spamming ourselves with layout requests 29779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * as we place views 29879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 29979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @see android.view.View#requestLayout() 30079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 30179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 30279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void requestLayout() { 30379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (!mBlockLayoutRequests) { 30479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super.requestLayout(); 30579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 30679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 30779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 30879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 30979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public SpinnerAdapter getAdapter() { 31079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return mAdapter; 31179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 31279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 31379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 31479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public int getCount() { 31579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return mItemCount; 31679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 31779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 31879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 31979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Maps a point to a position in the list. 32079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * 32179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @param x X in local coordinate 32279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @param y Y in local coordinate 32379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * @return The position of the item which contains the specified point, or 32479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * {@link #INVALID_POSITION} if the point does not intersect an item. 32579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 32679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public int pointToPosition(int x, int y) { 32779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes Rect frame = mTouchFrame; 32879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (frame == null) { 32979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mTouchFrame = new Rect(); 33079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes frame = mTouchFrame; 33179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 33279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 33379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int count = getChildCount(); 33479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes for (int i = count - 1; i >= 0; i--) { 33579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes View child = getChildAt(i); 33679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (child.getVisibility() == View.VISIBLE) { 33779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes child.getHitRect(frame); 33879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (frame.contains(x, y)) { 33979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return mFirstPosition + i; 34079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 34179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 34279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 34379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return INVALID_POSITION; 34479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 34579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 34679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes static class SavedState extends BaseSavedState { 34779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes long selectedId; 34879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes int position; 34979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 35079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 35179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Constructor called from {@link AbsSpinnerICS#onSaveInstanceState()} 35279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 35379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes SavedState(Parcelable superState) { 35479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super(superState); 35579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 35679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 35779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes /** 35879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes * Constructor called from {@link #CREATOR} 35979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes */ 36079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes private SavedState(Parcel in) { 36179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super(in); 36279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes selectedId = in.readLong(); 36379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes position = in.readInt(); 36479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 36579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 36679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 36779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void writeToParcel(Parcel out, int flags) { 36879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super.writeToParcel(out, flags); 36979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes out.writeLong(selectedId); 37079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes out.writeInt(position); 37179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 37279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 37379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 37479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public String toString() { 37579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return "AbsSpinner.SavedState{" 37679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes + Integer.toHexString(System.identityHashCode(this)) 37779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes + " selectedId=" + selectedId 37879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes + " position=" + position + "}"; 37979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 38079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 38179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public static final Parcelable.Creator<SavedState> CREATOR 38279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes = new Parcelable.Creator<SavedState>() { 38379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public SavedState createFromParcel(Parcel in) { 38479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return new SavedState(in); 38579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 38679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 38779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public SavedState[] newArray(int size) { 38879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return new SavedState[size]; 38979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 39079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes }; 39179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 39279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 39379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 39479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public Parcelable onSaveInstanceState() { 39579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes Parcelable superState = super.onSaveInstanceState(); 39679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes SavedState ss = new SavedState(superState); 39779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes ss.selectedId = getSelectedItemId(); 39879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (ss.selectedId >= 0) { 39979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes ss.position = getSelectedItemPosition(); 40079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } else { 40179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes ss.position = INVALID_POSITION; 40279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 40379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return ss; 40479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 40579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 40679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes @Override 40779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void onRestoreInstanceState(Parcelable state) { 40879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes SavedState ss = (SavedState) state; 40979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 41079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes super.onRestoreInstanceState(ss.getSuperState()); 41179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 41279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (ss.selectedId >= 0) { 41379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mDataChanged = true; 41479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mNeedSync = true; 41579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSyncRowId = ss.selectedId; 41679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSyncPosition = ss.position; 41779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mSyncMode = SYNC_SELECTED_POSITION; 41879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes requestLayout(); 41979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 42079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 42179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 42279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes class RecycleBin { 42379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes private final SparseArray<View> mScrapHeap = new SparseArray<View>(); 42479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 42579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes public void put(int position, View v) { 42679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mScrapHeap.put(position, v); 42779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 42879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 42979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes View get(int position) { 43079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // System.out.print("Looking for " + position); 43179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes View result = mScrapHeap.get(position); 43279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (result != null) { 43379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // System.out.println(" HIT"); 43479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes mScrapHeap.delete(position); 43579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } else { 43679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes // System.out.println(" MISS"); 43779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 43879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes return result; 43979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 44079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes 44179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes void clear() { 44279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final SparseArray<View> scrapHeap = mScrapHeap; 44379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final int count = scrapHeap.size(); 44479e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes for (int i = 0; i < count; i++) { 44579e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes final View view = scrapHeap.valueAt(i); 44679e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes if (view != null) { 44779e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes removeDetachedView(view, true); 44879e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 44979e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 45079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes scrapHeap.clear(); 45179e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 45279e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes } 45379e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes}