AdapterViewAnimator.java revision 78db1aa9118edd71c2da28a2c23a0d875d1a707a
13db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/* 23db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Copyright (C) 2010 The Android Open Source Project 33db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 43db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Licensed under the Apache License, Version 2.0 (the "License"); 53db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * you may not use this file except in compliance with the License. 63db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * You may obtain a copy of the License at 73db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 83db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * http://www.apache.org/licenses/LICENSE-2.0 93db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Unless required by applicable law or agreed to in writing, software 113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * distributed under the License is distributed on an "AS IS" BASIS, 123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * See the License for the specific language governing permissions and 143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * limitations under the License. 153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenpackage android.widget; 183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport java.util.ArrayList; 201b065cd1401253f999caa5d0ac12909407cef00eAdam Cohenimport java.util.HashMap; 2144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 22ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohenimport android.animation.AnimatorInflater; 23a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haaseimport android.animation.ObjectAnimator; 243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Context; 253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Intent; 263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.res.TypedArray; 273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Handler; 283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Looper; 29b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcel; 30b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcelable; 313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.AttributeSet; 32a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohenimport android.view.MotionEvent; 333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.View; 34a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohenimport android.view.ViewConfiguration; 3544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.view.ViewGroup; 363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/** 383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Base class for a {@link AdapterView} that will perform animations 393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * when switching between its views. 403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation 423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation 433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView 441b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_loopViews 453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenpublic abstract class AdapterViewAnimator extends AdapterView<Adapter> 47a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen implements RemoteViewsAdapter.RemoteAdapterConnectionCallback, Advanceable { 483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private static final String TAG = "RemoteViewAnimator"; 493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index of the current child, which appears anywhere from the beginning 5244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * to the end of the current set of children, as specified by {@link #mActiveOffset} 5344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int mWhichChild = 0; 5544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Whether or not the first view(s) should be animated in 5844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mAnimateFirstTime = true; 603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 6244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Represents where the in the current window of 6344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * views the current <code>mDisplayedChild</code> sits 6444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 6544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mActiveOffset = 0; 6644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 6744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 6844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The number of views that the {@link AdapterViewAnimator} keeps as children at any 6944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * given time (not counting views that are pending removal, see {@link #mPreviousViews}). 7044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7196d8d56302da81b24333b204e6d7f15064538036Adam Cohen int mMaxNumActiveViews = 1; 7244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 741b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen * Map of the children of the {@link AdapterViewAnimator}. 7544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7696d8d56302da81b24333b204e6d7f15064538036Adam Cohen HashMap<Integer, ViewAndIndex> mViewsMap = new HashMap<Integer, ViewAndIndex>(); 7744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * List of views pending removal from the {@link AdapterViewAnimator} 8044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 811b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen ArrayList<Integer> mPreviousViews; 8244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the beginning of the window of views 8544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 8644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStart = 0; 8744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the end of the window of views 9044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowEnd = -1; 9244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The same as {@link #mCurrentWindowStart}, except when the we have bounded 9544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * {@link #mCurrentWindowStart} to be non-negative 9644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStartUnbounded = 0; 9844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Handler to post events to the main thread 10144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 10244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Handler mMainQueue; 10344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 10444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Listens for data changes from the adapter 10644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen AdapterDataSetObserver mDataSetObserver; 1083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 10944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link Adapter} for this {@link AdapterViewAnimator} 11144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Adapter mAdapter; 11344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link RemoteViewsAdapter} for this {@link AdapterViewAnimator} 11644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen RemoteViewsAdapter mRemoteViewsAdapter; 11844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 12044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Specifies whether this is the first time the animator is showing views 12144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 12244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean mFirstTime = true; 1233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 12444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 125b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Specifies if the animator should wrap from 0 to the end and vice versa 126b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * or have hard boundaries at the beginning and end 127b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 1281b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean mLoopViews = true; 129b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 130b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 131839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * The width and height of some child, used as a size reference in-case our 132839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * dimensions are unspecified by the parent. 133839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen */ 134839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildWidth = -1; 135839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildHeight = -1; 136839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 137839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen /** 138ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen * In and out animations. 13944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1402794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator mInAnimation; 1412794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator mOutAnimation; 142ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 143a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen /** 144a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen * Current touch state. 145a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen */ 146a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen private int mTouchMode = TOUCH_MODE_NONE; 147a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 148a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen /** 149a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen * Private touch states. 150a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen */ 151a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_NONE = 0; 152a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_DOWN_IN_CURRENT_VIEW = 1; 153a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_HANDLED = 2; 154a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 155a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen private Runnable mPendingCheckForTap; 156a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 157ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen private static final int DEFAULT_ANIMATION_DURATION = 200; 158ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 1593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context) { 1603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context); 1615b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs) { 1653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context, attrs); 1663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 16744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen TypedArray a = context.obtainStyledAttributes(attrs, 1681b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator); 16944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int resource = a.getResourceId( 1701b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0); 1713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(context, resource); 173ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } else { 174ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen setInAnimation(getDefaultInAnimation()); 1753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1771b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen resource = a.getResourceId(com.android.internal.R.styleable.AdapterViewAnimator_outAnimation, 0); 1783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(context, resource); 180ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } else { 181ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen setOutAnimation(getDefaultOutAnimation()); 1823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 18444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean flag = a.getBoolean( 1851b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_animateFirstView, true); 1863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAnimateFirstView(flag); 1873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1881b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mLoopViews = a.getBoolean( 1891b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_loopViews, false); 1901b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 1913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen a.recycle(); 1923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1935b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Initialize this {@link AdapterViewAnimator} 1983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1995b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy private void initViewAnimator() { 2003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mMainQueue = new Handler(Looper.myLooper()); 2011b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mPreviousViews = new ArrayList<Integer>(); 20244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 20344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 20496d8d56302da81b24333b204e6d7f15064538036Adam Cohen class ViewAndIndex { 2051b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen ViewAndIndex(View v, int i) { 2061b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen view = v; 2071b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen index = i; 2081b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 2091b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View view; 2101b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int index; 2111b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 2121b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 21344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 21444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This method is used by subclasses to configure the animator to display the 21544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * desired number of views, and specify the offset 21644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 21744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param numVisibleViews The number of views the animator keeps in the {@link ViewGroup} 2185b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * @param activeOffset This parameter specifies where the current index ({@link #mWhichChild}) 21944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * sits within the window. For example if activeOffset is 1, and numVisibleViews is 3, 2205b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * and {@link #setDisplayedChild(int)} is called with 10, then the effective window will 2215b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * be the indexes 9, 10, and 11. In the same example, if activeOffset were 0, then the 22244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * window would instead contain indexes 10, 11 and 12. 223b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * @param shouldLoop If the animator is show view 0, and setPrevious() is called, do we 224b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * we loop back to the end, or do we do nothing 22544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 2261b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen void configureViewAnimator(int numVisibleViews, int activeOffset) { 22744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (activeOffset > numVisibleViews - 1) { 22844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Throw an exception here. 22944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 23096d8d56302da81b24333b204e6d7f15064538036Adam Cohen mMaxNumActiveViews = numVisibleViews; 23144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveOffset = activeOffset; 23244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 2331b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.clear(); 23444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeAllViewsInLayout(); 23544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = 0; 23644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = -1; 23744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 23844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 23944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 24044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This class should be overridden by subclasses to customize view transitions within 24144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * the set of visible views 24244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 24344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param fromIndex The relative index within the window that the view was in, -1 if it wasn't 24444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * in the window 24544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param toIndex The relative index within the window that the view is going to, -1 if it is 24644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * being removed 24744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param view The view that is being animated 24844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 24978db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen void transformViewForTransition(int fromIndex, int toIndex, View view, boolean animate) { 25044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (fromIndex == -1) { 251ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mInAnimation.setTarget(view); 252ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mInAnimation.start(); 25344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else if (toIndex == -1) { 254ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mOutAnimation.setTarget(view); 255ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mOutAnimation.start(); 25644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 2573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2592794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator getDefaultInAnimation() { 2602794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator anim = ObjectAnimator.ofFloat(null, "alpha", 0.0f, 1.0f); 2612794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase anim.setDuration(DEFAULT_ANIMATION_DURATION); 2622794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase return anim; 263ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } 264ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 2652794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator getDefaultOutAnimation() { 2662794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator anim = ObjectAnimator.ofFloat(null, "alpha", 1.0f, 0.0f); 2672794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase anim.setDuration(DEFAULT_ANIMATION_DURATION); 2682794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase return anim; 269ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } 270ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 2713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets which child view will be displayed. 2733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param whichChild the index of the child view to display 2753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setDisplayedChild(int whichChild) { 2773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 2783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = whichChild; 27996d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (whichChild >= getWindowSize()) { 28096d8d56302da81b24333b204e6d7f15064538036Adam Cohen mWhichChild = mLoopViews ? 0 : getWindowSize() - 1; 2813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else if (whichChild < 0) { 28296d8d56302da81b24333b204e6d7f15064538036Adam Cohen mWhichChild = mLoopViews ? getWindowSize() - 1 : 0; 2833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean hasFocus = getFocusedChild() != null; 2863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This will clear old focus if we had it 2873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild); 2883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (hasFocus) { 2893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Try to retake focus if we had it 2903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestFocus(FOCUS_FORWARD); 2913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 29644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * To be overridden by subclasses. This method applies a view / index specific 29744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * transform to the child view. 29844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 29944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param child 30044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex 30144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 30244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void applyTransformForChildAtIndex(View child, int relativeIndex) { 30344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 30444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 30544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 3063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the index of the currently displayed child view. 3073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getDisplayedChild() { 3093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mWhichChild; 3103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the next child. 3143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showNext() { 3163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild + 1); 3173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the previous child. 3213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showPrevious() { 3233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild - 1); 3243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 32696d8d56302da81b24333b204e6d7f15064538036Adam Cohen int modulo(int pos, int size) { 3273042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen if (size > 0) { 3283042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen return (size + (pos % size)) % size; 3293042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen } else { 3303042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen return 0; 3313042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen } 3323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 33444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 33544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Get the view at this index relative to the current window's start 33644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 33744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex Position relative to the current window's start 33844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @return View at this index, null if the index is outside the bounds 33944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 34044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View getViewAtRelativeIndex(int relativeIndex) { 34196d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (relativeIndex >= 0 && relativeIndex <= getNumActiveViews() - 1 && mAdapter != null) { 34296d8d56302da81b24333b204e6d7f15064538036Adam Cohen int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, getWindowSize()); 3436f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen if (mViewsMap.get(i) != null) { 3446f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen return mViewsMap.get(i).view; 3456f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen } 34644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 34744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return null; 34844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 35096d8d56302da81b24333b204e6d7f15064538036Adam Cohen int getNumActiveViews() { 35196d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (mAdapter != null) { 352ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen return Math.min(getCount() + 1, mMaxNumActiveViews); 35396d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 35496d8d56302da81b24333b204e6d7f15064538036Adam Cohen return mMaxNumActiveViews; 35596d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 35696d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 35796d8d56302da81b24333b204e6d7f15064538036Adam Cohen 35896d8d56302da81b24333b204e6d7f15064538036Adam Cohen int getWindowSize() { 35996d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (mAdapter != null) { 360ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen int adapterCount = getCount(); 36196d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (adapterCount <= getNumActiveViews() && mLoopViews) { 36296d8d56302da81b24333b204e6d7f15064538036Adam Cohen return adapterCount*mMaxNumActiveViews; 36396d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 36496d8d56302da81b24333b204e6d7f15064538036Adam Cohen return adapterCount; 36596d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 36696d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 36796d8d56302da81b24333b204e6d7f15064538036Adam Cohen return 0; 36896d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 36996d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 37096d8d56302da81b24333b204e6d7f15064538036Adam Cohen 3719b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen LayoutParams createOrReuseLayoutParams(View v) { 3725b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy final ViewGroup.LayoutParams currentLp = v.getLayoutParams(); 3739b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen if (currentLp instanceof ViewGroup.LayoutParams) { 374b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen LayoutParams lp = (LayoutParams) currentLp; 375b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return lp; 37644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3779b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen return new ViewGroup.LayoutParams(0, 0); 37844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3806364f2bbe5254b4274f3feffc48f4259eacc205eWinson Chung void refreshChildren() { 381a9238c89a43500ed0bcdeaee182be08ff991c627Adam Cohen if (mAdapter == null) return; 382bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) { 383a9238c89a43500ed0bcdeaee182be08ff991c627Adam Cohen int index = modulo(i, getWindowSize()); 384bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 385ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen int adapterCount = getCount(); 386bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // get the fresh child from the adapter 387ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final View updatedChild = mAdapter.getView(modulo(i, adapterCount), null, this); 388bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 3891b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mViewsMap.containsKey(index)) { 390ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final FrameLayout fl = (FrameLayout) mViewsMap.get(index).view; 391bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // add the new child to the frame, if it exists 392bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen if (updatedChild != null) { 393ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // flush out the old child 394ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen fl.removeAllViewsInLayout(); 395bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(updatedChild); 396bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 397bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 398bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 399bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 400bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 401dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen /** 402dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * This method can be overridden so that subclasses can provide a custom frame in which their 403dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * children can live. For example, StackView adds padding to its childrens' frames so as to 404dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * accomodate for the highlight effect. 405dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * 406dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * @return The FrameLayout into which children can be placed. 407dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen */ 408dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout getFrameForChild() { 409dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen return new FrameLayout(mContext); 410dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen } 411dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen 412ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen /** 413ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * Shows only the specified child. The other displays Views exit the screen, 414ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * optionally with the with the {@link #getOutAnimation() out animation} and 415ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * the specified child enters the screen, optionally with the 416ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * {@link #getInAnimation() in animation}. 417ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * 418ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * @param childIndex The index of the child to be shown. 419ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * @param animate Whether or not to use the in and out animations, defaults 420ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * to true. 421ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen */ 422ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen void showOnly(int childIndex, boolean animate) { 42344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mAdapter == null) return; 424ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final int adapterCount = getCount(); 4253042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen if (adapterCount == 0) return; 4263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 42744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mPreviousViews.size(); i++) { 4281b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View viewToRemove = mViewsMap.get(mPreviousViews.get(i)).view; 4291b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.remove(mPreviousViews.get(i)); 43044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen viewToRemove.clearAnimation(); 4313d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen if (viewToRemove instanceof ViewGroup) { 4323d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen ViewGroup vg = (ViewGroup) viewToRemove; 4333d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen vg.removeAllViewsInLayout(); 4343d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen } 43544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // applyTransformForChildAtIndex here just allows for any cleanup 43644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // associated with this view that may need to be done by a subclass 43744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(viewToRemove, -1); 4383d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen 43944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeViewInLayout(viewToRemove); 44044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 44144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 44244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStartUnbounded = childIndex - mActiveOffset; 44396d8d56302da81b24333b204e6d7f15064538036Adam Cohen int newWindowEndUnbounded = newWindowStartUnbounded + getNumActiveViews() - 1; 44444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStart = Math.max(0, newWindowStartUnbounded); 4451b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int newWindowEnd = Math.min(adapterCount - 1, newWindowEndUnbounded); 44644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 4471b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mLoopViews) { 4481b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen newWindowStart = newWindowStartUnbounded; 4491b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen newWindowEnd = newWindowEndUnbounded; 4501b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 45196d8d56302da81b24333b204e6d7f15064538036Adam Cohen int rangeStart = modulo(newWindowStart, getWindowSize()); 45296d8d56302da81b24333b204e6d7f15064538036Adam Cohen int rangeEnd = modulo(newWindowEnd, getWindowSize()); 4531b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4541b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean wrap = false; 4551b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (rangeStart > rangeEnd) { 4561b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen wrap = true; 4571b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 4581b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4591b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // This section clears out any items that are in our active views list 46044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // but are outside the effective bounds of our window (this is becomes an issue 46144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // at the extremities of the list, eg. where newWindowStartUnbounded < 0 or 462ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // newWindowEndUnbounded > adapterCount - 1 4631b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen for (Integer index : mViewsMap.keySet()) { 4641b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean remove = false; 4651b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (!wrap && (index < rangeStart || index > rangeEnd)) { 4661b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen remove = true; 4671b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } else if (wrap && (index > rangeEnd && index < rangeStart)) { 4681b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen remove = true; 4691b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 4701b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4711b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (remove) { 4721b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View previousView = mViewsMap.get(index).view; 4731b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int oldRelativeIndex = mViewsMap.get(index).index; 4741b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4751b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mPreviousViews.add(index); 47678db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(oldRelativeIndex, -1, previousView, animate); 4773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 47844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 48044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the window has changed 48196d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd && 48296d8d56302da81b24333b204e6d7f15064538036Adam Cohen newWindowStartUnbounded == mCurrentWindowStartUnbounded)) { 48344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Run through the indices in the new range 48444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStart; i <= newWindowEnd; i++) { 48544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 48696d8d56302da81b24333b204e6d7f15064538036Adam Cohen int index = modulo(i, getWindowSize()); 4871b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int oldRelativeIndex; 4881b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mViewsMap.containsKey(index)) { 4891b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen oldRelativeIndex = mViewsMap.get(index).index; 4901b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } else { 4911b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen oldRelativeIndex = -1; 4921b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 49344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newRelativeIndex = i - newWindowStartUnbounded; 49444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 49544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If this item is in the current window, great, we just need to apply 49644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // the transform for it's new relative position in the window, and animate 49744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // between it's current and new relative positions 4981b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean inOldRange = mViewsMap.containsKey(index) && !mPreviousViews.contains(index); 4991b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 5001b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (inOldRange) { 5011b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View view = mViewsMap.get(index).view; 5021b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.get(index).index = newRelativeIndex; 50344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(view, newRelativeIndex); 50478db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(oldRelativeIndex, newRelativeIndex, view, animate); 50544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5061b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // Otherwise this view is new to the window 50744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 5081b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // Get the new view from the adapter, add it and apply any transform / animation 5091b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View newView = mAdapter.getView(modulo(i, adapterCount), null, this); 510bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 511bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // We wrap the new view in a FrameLayout so as to respect the contract 512bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // with the adapter, that is, that we don't modify this view directly 513dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout fl = getFrameForChild(); 514bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 515bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // If the view from the adapter is null, we still keep an empty frame in place 51644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (newView != null) { 517bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(newView); 51844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 5191b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.put(index, new ViewAndIndex(fl, newRelativeIndex)); 520bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen addChild(fl); 521bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen applyTransformForChildAtIndex(fl, newRelativeIndex); 52278db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(-1, newRelativeIndex, fl, animate); 5233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5241b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.get(index).view.bringToFront(); 5253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 52644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = newWindowStart; 52744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = newWindowEnd; 52844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStartUnbounded = newWindowStartUnbounded; 52944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 530ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen requestLayout(); 531ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen invalidate(); 5323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 534839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void addChild(View child) { 535839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen addViewInLayout(child, -1, createOrReuseLayoutParams(child)); 536839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 537839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // This code is used to obtain a reference width and height of a child in case we need 538839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // to decide our own size. TODO: Do we want to update the size of the child that we're 539839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // using for reference size? If so, when? 540839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) { 541839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 542839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(measureSpec, measureSpec); 543839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildWidth = child.getMeasuredWidth(); 544839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildHeight = child.getMeasuredHeight(); 545839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 546839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 547839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 548a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void showTapFeedback(View v) { 549a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen v.setPressed(true); 550a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 551a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 552a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void hideTapFeedback(View v) { 553a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen v.setPressed(false); 554a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 555a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 556a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void cancelHandleClick() { 557a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 558a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 559a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 560a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 561a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 562a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 563a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 564a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final class CheckForTap implements Runnable { 565a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 566a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) { 567a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 568a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen showTapFeedback(v); 569a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 570a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 571a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 572a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 573a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen @Override 574a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public boolean onTouchEvent(MotionEvent ev) { 575a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen int action = ev.getAction(); 576a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen boolean handled = false; 577a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen switch (action) { 578a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_DOWN: { 579a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 580a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 581a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) { 582a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mPendingCheckForTap == null) { 583a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mPendingCheckForTap = new CheckForTap(); 584a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 585a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_DOWN_IN_CURRENT_VIEW; 586a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 587a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 588a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 589a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen break; 590a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 591a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_MOVE: break; 592a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_POINTER_UP: break; 593a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_UP: { 594a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) { 595a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final View v = getCurrentView(); 596a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 597a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) { 598a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final Handler handler = getHandler(); 599a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (handler != null) { 600a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen handler.removeCallbacks(mPendingCheckForTap); 601a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 602a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen showTapFeedback(v); 603a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen postDelayed(new Runnable() { 604a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 605a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 606a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen post(new Runnable() { 607a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 608a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen performItemClick(v, 0, 0); 609a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 610a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen }); 611a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 612a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen }, ViewConfiguration.getPressedStateDuration()); 613a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen handled = true; 614a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 615a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 616a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 617a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 618a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen break; 619a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 620a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_CANCEL: { 621a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 622a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 623a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 624a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 625a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 626a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 627a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 628a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen return handled; 629a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 630a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 631839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void measureChildren() { 632839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int count = getChildCount(); 633189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn final int childWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight; 634189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn final int childHeight = getMeasuredHeight() - mPaddingTop - mPaddingBottom; 635839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 636839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen for (int i = 0; i < count; i++) { 637839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final View child = getChildAt(i); 638839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 639839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); 640839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 641839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 642839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 643839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen @Override 644839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 645839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 646839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 647839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 648839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 649839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 650839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1); 651839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 652839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // We need to deal with the case where our parent hasn't told us how 653839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // big we should be. In this case we try to use the desired size of the first 654839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // child added. 655839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (heightSpecMode == MeasureSpec.UNSPECIFIED) { 656839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop + 657839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingBottom : 0; 658839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 659189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (haveChildRefSize) { 660189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn int height = mReferenceChildHeight + mPaddingTop + mPaddingBottom; 661189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (height > heightSpecSize) { 662189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn heightSpecSize |= MEASURED_STATE_TOO_SMALL; 663189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } else { 664189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn heightSpecSize = height; 665189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 666189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 667839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 668839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 669839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (widthSpecMode == MeasureSpec.UNSPECIFIED) { 670839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft + 671839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingRight : 0; 672839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 673189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (haveChildRefSize) { 674189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn int width = mReferenceChildWidth + mPaddingLeft + mPaddingRight; 675189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (width > widthSpecSize) { 676189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn widthSpecSize |= MEASURED_STATE_TOO_SMALL; 677189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } else { 678189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn widthSpecSize = width; 679189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 680189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 681839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 682839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 683839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 684839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen measureChildren(); 685839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 686839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 687ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen void checkForAndHandleDataChanged() { 6883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean dataChanged = mDataChanged; 6893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (dataChanged) { 690ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen post(new Runnable() { 691ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen public void run() { 692ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen handleDataChanged(); 693ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // if the data changes, mWhichChild might be out of the bounds of the adapter 694ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // in this case, we reset mWhichChild to the beginning 695ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen if (mWhichChild >= getWindowSize()) { 696ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mWhichChild = 0; 6973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 69878db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 699e86ff4d56145d875c13a1637833f9f55d79febc9Adam Cohen } else if (mOldItemCount != getCount()) { 70078db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 701ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 702ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen refreshChildren(); 703ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen requestLayout(); 704ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 705ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen }); 7063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 707ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mDataChanged = false; 708ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 709ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen 710ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen @Override 711ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 712ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen checkForAndHandleDataChanged(); 7133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int childCount = getChildCount(); 7153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < childCount; i++) { 7163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 7173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childRight = mPaddingLeft + child.getMeasuredWidth(); 7193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childBottom = mPaddingTop + child.getMeasuredHeight(); 7203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 721839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom); 7223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 725b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen static class SavedState extends BaseSavedState { 726b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen int whichChild; 727b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 728b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 729b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link AdapterViewAnimator#onSaveInstanceState()} 730b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 731b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState(Parcelable superState, int whichChild) { 732b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(superState); 733b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen this.whichChild = whichChild; 734b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 735b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 736b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 737b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link #CREATOR} 738b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 739b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen private SavedState(Parcel in) { 740b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(in); 7413ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung this.whichChild = in.readInt(); 742b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 743b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 744b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 745b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void writeToParcel(Parcel out, int flags) { 746b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.writeToParcel(out, flags); 7473ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung out.writeInt(this.whichChild); 748b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 749b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 750b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 751b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public String toString() { 7523ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung return "AdapterViewAnimator.SavedState{ whichChild = " + this.whichChild + " }"; 753b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 754b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 755b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public static final Parcelable.Creator<SavedState> CREATOR 756b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen = new Parcelable.Creator<SavedState>() { 757b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState createFromParcel(Parcel in) { 758b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(in); 759b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 760b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 761b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState[] newArray(int size) { 762b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState[size]; 763b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 764b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen }; 765b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 766b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 767b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 768b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public Parcelable onSaveInstanceState() { 769b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen Parcelable superState = super.onSaveInstanceState(); 770b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(superState, mWhichChild); 771b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 772b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 773b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 774b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void onRestoreInstanceState(Parcelable state) { 775b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState ss = (SavedState) state; 776b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.onRestoreInstanceState(ss.getSuperState()); 777b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 778b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // Here we set mWhichChild in addition to setDisplayedChild 779b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // We do the former in case mAdapter is null, and hence setDisplayedChild won't 780b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // set mWhichChild 781b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mWhichChild = ss.whichChild; 78269d66e00136f67332c992326a7b2eb334eeb32a2Adam Cohen 783b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen setDisplayedChild(mWhichChild); 784b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 785b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 7863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 7873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen 7883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * with the {@link #getOutAnimation() out animation} and the specified child 7893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * enters the screen with the {@link #getInAnimation() in animation}. 7903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 7923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex) { 7943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final boolean animate = (!mFirstTime || mAnimateFirstTime); 7953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate); 7963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 7993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the View corresponding to the currently displayed child. 8003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return The View currently displayed. 8023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getDisplayedChild() 8043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getCurrentView() { 80644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 8073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that enters the screen. 8113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 8133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8142794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setInAnimation(android.animation.ObjectAnimator) 8153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 8163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8172794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public ObjectAnimator getInAnimation() { 8183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mInAnimation; 8193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 8233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param inAnimation The animation started when a View enters the screen. 8253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 8273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 8283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8292794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public void setInAnimation(ObjectAnimator inAnimation) { 8303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mInAnimation = inAnimation; 8313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that exits the screen. 8353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 8373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8382794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setOutAnimation(android.animation.ObjectAnimator) 8393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 8403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8412794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public ObjectAnimator getOutAnimation() { 8423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mOutAnimation; 8433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 8473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param outAnimation The animation started when a View exit the screen. 8493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 8513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 8523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8532794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public void setOutAnimation(ObjectAnimator outAnimation) { 8543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mOutAnimation = outAnimation; 8553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 8593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 8613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 8623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 8642794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setInAnimation(android.animation.ObjectAnimator) 8653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Context context, int resourceID) { 8672794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase setInAnimation((ObjectAnimator) AnimatorInflater.loadAnimator(context, resourceID)); 8683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 8723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 8743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 8753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 8772794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setOutAnimation(android.animation.ObjectAnimator) 8783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Context context, int resourceID) { 8802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase setOutAnimation((ObjectAnimator) AnimatorInflater.loadAnimator(context, resourceID)); 8813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Indicates whether the current View should be animated the first time 8853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the ViewAnimation is displayed. 8863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate True to animate the current View the first time it is displayed, 8883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * false otherwise. 8893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAnimateFirstView(boolean animate) { 8913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAnimateFirstTime = animate; 8923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 8953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getBaseline() { 8963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 8973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Adapter getAdapter() { 9013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mAdapter; 9023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAdapter(Adapter adapter) { 9068322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen if (mAdapter != null && mDataSetObserver != null) { 9078322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen mAdapter.unregisterDataSetObserver(mDataSetObserver); 9088322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen } 9098322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen 9103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter = adapter; 9111480fddea874a42adb43b4bcdac6704e4c3e110bAdam Cohen checkFocus(); 9123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 9143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataSetObserver = new AdapterDataSetObserver(); 9153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.registerDataSetObserver(mDataSetObserver); 916ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mItemCount = mAdapter.getCount(); 9173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 91844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen setFocusable(true); 91978db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen mWhichChild = 0; 92078db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 9213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 92444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a 92544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * RemoteViewsService through the specified intent. 92644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 92744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param intent the intent used to identify the RemoteViewsService for the adapter to 92844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * connect to. 9293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @android.view.RemotableViewMethod 9313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setRemoteViewsAdapter(Intent intent) { 9329b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing 9339b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // service handling the specified intent. 9343ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung if (mRemoteViewsAdapter != null) { 9353ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung Intent.FilterComparison fcNew = new Intent.FilterComparison(intent); 9363ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung Intent.FilterComparison fcOld = new Intent.FilterComparison( 9373ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung mRemoteViewsAdapter.getRemoteViewsServiceIntent()); 9383ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung if (fcNew.equals(fcOld)) { 9393ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung return; 9403ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung } 9419b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung } 9429b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung 9439b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Otherwise, create a new RemoteViewsAdapter for binding 9443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); 9453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setSelection(int position) { 9493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(position); 9503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getSelectedView() { 95444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 9553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 9583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter connects to the RemoteViewsService. 9593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterConnected() { 9613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 9623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 963fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen } else if (mRemoteViewsAdapter != null) { 964fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen mRemoteViewsAdapter.superNotifyDataSetChanged(); 9653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 9693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter disconnects from the RemoteViewsService. 9703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterDisconnected() { 972fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // If the remote adapter disconnects, we keep it around 973fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // since the currently displayed items are still cached. 974fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // Further, we want the service to eventually reconnect 975fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // when necessary, as triggered by this view requesting 976fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // items from the Adapter. 9773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 978a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen 9790e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen /** 9800e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * Called by an {@link android.appwidget.AppWidgetHost} in order to advance the current view when 9810e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * it is being used within an app widget. 9820e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen */ 983a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen public void advance() { 984a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen showNext(); 985a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen } 986a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen 9870e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen /** 9880e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * Called by an {@link android.appwidget.AppWidgetHost} to indicate that it will be 9890e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * automatically advancing the views of this {@link AdapterViewAnimator} by calling 9900e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * {@link AdapterViewAnimator#advance()} at some point in the future. This allows subclasses to 9910e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * perform any required setup, for example, to stop automatically advancing their children. 9920e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen */ 9930e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen public void fyiWillBeAdvancedByHostKThx() { 994a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen } 995ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy 996ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy @Override 997ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy protected void onDetachedFromWindow() { 998ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy mAdapter = null; 999ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy super.onDetachedFromWindow(); 1000ec84c3a189e4aa70aa6ea8ba712e5a4f260a153bPatrick Dubroy } 10013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen} 1002