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 19ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohenimport android.animation.AnimatorInflater; 20a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haaseimport android.animation.ObjectAnimator; 213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Context; 223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Intent; 233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.res.TypedArray; 243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Handler; 25b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcel; 26b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcelable; 273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.AttributeSet; 28a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohenimport android.view.MotionEvent; 293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.View; 30a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohenimport android.view.ViewConfiguration; 3144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.view.ViewGroup; 328a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 338a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 34a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohenimport android.widget.RemoteViews.OnClickHandler; 353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 362148d43eb23c702e834c93ae427f822f32d280a2Adam Cohenimport java.util.ArrayList; 372148d43eb23c702e834c93ae427f822f32d280a2Adam Cohenimport java.util.HashMap; 382148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen 393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/** 403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Base class for a {@link AdapterView} that will perform animations 413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * when switching between its views. 423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation 443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation 453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView 461b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_loopViews 473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenpublic abstract class AdapterViewAnimator extends AdapterView<Adapter> 49a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen implements RemoteViewsAdapter.RemoteAdapterConnectionCallback, Advanceable { 503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private static final String TAG = "RemoteViewAnimator"; 513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index of the current child, which appears anywhere from the beginning 5444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * to the end of the current set of children, as specified by {@link #mActiveOffset} 5544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int mWhichChild = 0; 5744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung * The index of the child to restore after the asynchronous connection from the 6016c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung * RemoteViewsAdapter has been. 6116c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung */ 6216c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung private int mRestoreWhichChild = -1; 6316c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung 6416c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung /** 6544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Whether or not the first view(s) should be animated in 6644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mAnimateFirstTime = true; 683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Represents where the in the current window of 7144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * views the current <code>mDisplayedChild</code> sits 7244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mActiveOffset = 0; 7444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The number of views that the {@link AdapterViewAnimator} keeps as children at any 7744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * given time (not counting views that are pending removal, see {@link #mPreviousViews}). 7844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7996d8d56302da81b24333b204e6d7f15064538036Adam Cohen int mMaxNumActiveViews = 1; 8044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 821b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen * Map of the children of the {@link AdapterViewAnimator}. 8344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 84d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen HashMap<Integer, ViewAndMetaData> mViewsMap = new HashMap<Integer, ViewAndMetaData>(); 8544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * List of views pending removal from the {@link AdapterViewAnimator} 8844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 891b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen ArrayList<Integer> mPreviousViews; 9044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the beginning of the window of views 9344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStart = 0; 9544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the end of the window of views 9844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowEnd = -1; 10044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 10144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The same as {@link #mCurrentWindowStart}, except when the we have bounded 10344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * {@link #mCurrentWindowStart} to be non-negative 10444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 10544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStartUnbounded = 0; 10644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 10744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Listens for data changes from the adapter 10944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen AdapterDataSetObserver mDataSetObserver; 1113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 11244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link Adapter} for this {@link AdapterViewAnimator} 11444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Adapter mAdapter; 11644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link RemoteViewsAdapter} for this {@link AdapterViewAnimator} 11944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 12044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen RemoteViewsAdapter mRemoteViewsAdapter; 12144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 12244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 1232148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen * The remote adapter containing the data to be displayed by this view to be set 1242148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen */ 1252148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen boolean mDeferNotifyDataSetChanged = false; 1262148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen 1272148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen /** 12844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Specifies whether this is the first time the animator is showing views 12944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 13044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean mFirstTime = true; 1313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 13244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 133b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Specifies if the animator should wrap from 0 to the end and vice versa 134b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * or have hard boundaries at the beginning and end 135b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 1361b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean mLoopViews = true; 137b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 138b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 139839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * The width and height of some child, used as a size reference in-case our 140839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * dimensions are unspecified by the parent. 141839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen */ 142839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildWidth = -1; 143839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildHeight = -1; 144839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 145839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen /** 146ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen * In and out animations. 14744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1482794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator mInAnimation; 1492794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator mOutAnimation; 150ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 151a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen /** 152a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen * Current touch state. 153a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen */ 154a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen private int mTouchMode = TOUCH_MODE_NONE; 155a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 156a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen /** 157a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen * Private touch states. 158a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen */ 159a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_NONE = 0; 160a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_DOWN_IN_CURRENT_VIEW = 1; 161a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen static final int TOUCH_MODE_HANDLED = 2; 162a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 163a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen private Runnable mPendingCheckForTap; 164a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 165ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen private static final int DEFAULT_ANIMATION_DURATION = 200; 166ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 1673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context) { 16826f072c3ee4f2baecf4fd3f8ed829ed709055cf4Adam Cohen this(context, null); 1693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs) { 17226f072c3ee4f2baecf4fd3f8ed829ed709055cf4Adam Cohen this(context, attrs, 0); 17326f072c3ee4f2baecf4fd3f8ed829ed709055cf4Adam Cohen } 17426f072c3ee4f2baecf4fd3f8ed829ed709055cf4Adam Cohen 17526f072c3ee4f2baecf4fd3f8ed829ed709055cf4Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs, int defStyleAttr) { 176617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 177617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 178617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 179617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public AdapterViewAnimator( 180617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 181617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 1823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 183617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette final TypedArray a = context.obtainStyledAttributes(attrs, 184617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette com.android.internal.R.styleable.AdapterViewAnimator, defStyleAttr, defStyleRes); 18544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int resource = a.getResourceId( 1861b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0); 1873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(context, resource); 189ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } else { 190ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen setInAnimation(getDefaultInAnimation()); 1913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1931b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen resource = a.getResourceId(com.android.internal.R.styleable.AdapterViewAnimator_outAnimation, 0); 1943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(context, resource); 196ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } else { 197ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen setOutAnimation(getDefaultOutAnimation()); 1983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 20044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean flag = a.getBoolean( 2011b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_animateFirstView, true); 2023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAnimateFirstView(flag); 2033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2041b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mLoopViews = a.getBoolean( 2051b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen com.android.internal.R.styleable.AdapterViewAnimator_loopViews, false); 2061b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 2073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen a.recycle(); 2083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2095b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 2103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Initialize this {@link AdapterViewAnimator} 2143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2155b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy private void initViewAnimator() { 2161b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mPreviousViews = new ArrayList<Integer>(); 21744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 21844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 219d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen class ViewAndMetaData { 2201b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View view; 221d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen int relativeIndex; 222d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen int adapterPosition; 223d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen long itemId; 224d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen 225d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen ViewAndMetaData(View view, int relativeIndex, int adapterPosition, long itemId) { 226d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen this.view = view; 227d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen this.relativeIndex = relativeIndex; 228d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen this.adapterPosition = adapterPosition; 229d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen this.itemId = itemId; 230d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } 2311b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 2321b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 23344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 23444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This method is used by subclasses to configure the animator to display the 23544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * desired number of views, and specify the offset 23644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 23744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param numVisibleViews The number of views the animator keeps in the {@link ViewGroup} 2385b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * @param activeOffset This parameter specifies where the current index ({@link #mWhichChild}) 23944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * sits within the window. For example if activeOffset is 1, and numVisibleViews is 3, 2405b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * and {@link #setDisplayedChild(int)} is called with 10, then the effective window will 2415b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * be the indexes 9, 10, and 11. In the same example, if activeOffset were 0, then the 24244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * window would instead contain indexes 10, 11 and 12. 243b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * @param shouldLoop If the animator is show view 0, and setPrevious() is called, do we 244b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * we loop back to the end, or do we do nothing 24544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 2461b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen void configureViewAnimator(int numVisibleViews, int activeOffset) { 24744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (activeOffset > numVisibleViews - 1) { 24844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Throw an exception here. 24944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 25096d8d56302da81b24333b204e6d7f15064538036Adam Cohen mMaxNumActiveViews = numVisibleViews; 25144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveOffset = activeOffset; 25244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 2531b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.clear(); 25444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeAllViewsInLayout(); 25544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = 0; 25644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = -1; 25744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 25844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 25944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 26044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This class should be overridden by subclasses to customize view transitions within 26144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * the set of visible views 26244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 26344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param fromIndex The relative index within the window that the view was in, -1 if it wasn't 26444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * in the window 26544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param toIndex The relative index within the window that the view is going to, -1 if it is 26644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * being removed 26744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param view The view that is being animated 26844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 26978db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen void transformViewForTransition(int fromIndex, int toIndex, View view, boolean animate) { 27044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (fromIndex == -1) { 271ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mInAnimation.setTarget(view); 272ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mInAnimation.start(); 27344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else if (toIndex == -1) { 274ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mOutAnimation.setTarget(view); 275ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen mOutAnimation.start(); 27644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 2773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2792794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator getDefaultInAnimation() { 2802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator anim = ObjectAnimator.ofFloat(null, "alpha", 0.0f, 1.0f); 2812794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase anim.setDuration(DEFAULT_ANIMATION_DURATION); 2822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase return anim; 283ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } 284ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 2852794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator getDefaultOutAnimation() { 2862794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ObjectAnimator anim = ObjectAnimator.ofFloat(null, "alpha", 1.0f, 0.0f); 2872794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase anim.setDuration(DEFAULT_ANIMATION_DURATION); 2882794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase return anim; 289ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen } 290ef52176f1244a5bb98d82a0c8c7f4351edec17a1Adam Cohen 2913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets which child view will be displayed. 2933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param whichChild the index of the child view to display 2953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2960b96a57c851af2f66e3bc738035478efb3c1957eAdam Cohen @android.view.RemotableViewMethod 2973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setDisplayedChild(int whichChild) { 29853838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen setDisplayedChild(whichChild, true); 29953838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen } 30053838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen 30153838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen private void setDisplayedChild(int whichChild, boolean animate) { 3023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 3033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = whichChild; 30496d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (whichChild >= getWindowSize()) { 30596d8d56302da81b24333b204e6d7f15064538036Adam Cohen mWhichChild = mLoopViews ? 0 : getWindowSize() - 1; 3063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else if (whichChild < 0) { 30796d8d56302da81b24333b204e6d7f15064538036Adam Cohen mWhichChild = mLoopViews ? getWindowSize() - 1 : 0; 3083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean hasFocus = getFocusedChild() != null; 3113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This will clear old focus if we had it 31253838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen showOnly(mWhichChild, animate); 3133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (hasFocus) { 3143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Try to retake focus if we had it 3153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestFocus(FOCUS_FORWARD); 3163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 32144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * To be overridden by subclasses. This method applies a view / index specific 32244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * transform to the child view. 32344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 32444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param child 32544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex 32644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 32744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void applyTransformForChildAtIndex(View child, int relativeIndex) { 32844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 32944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 33044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 3313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the index of the currently displayed child view. 3323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getDisplayedChild() { 3343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mWhichChild; 3353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the next child. 3393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showNext() { 3413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild + 1); 3423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the previous child. 3463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showPrevious() { 3483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild - 1); 3493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 35196d8d56302da81b24333b204e6d7f15064538036Adam Cohen int modulo(int pos, int size) { 3523042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen if (size > 0) { 3533042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen return (size + (pos % size)) % size; 3543042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen } else { 3553042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen return 0; 3563042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen } 3573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 35944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 36044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Get the view at this index relative to the current window's start 36144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 36244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex Position relative to the current window's start 36344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @return View at this index, null if the index is outside the bounds 36444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 36544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View getViewAtRelativeIndex(int relativeIndex) { 36696d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (relativeIndex >= 0 && relativeIndex <= getNumActiveViews() - 1 && mAdapter != null) { 36796d8d56302da81b24333b204e6d7f15064538036Adam Cohen int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, getWindowSize()); 3686f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen if (mViewsMap.get(i) != null) { 3696f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen return mViewsMap.get(i).view; 3706f279627cfa3286e6901a8dc2ed8361576ce226dAdam Cohen } 37144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 37244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return null; 37344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 37596d8d56302da81b24333b204e6d7f15064538036Adam Cohen int getNumActiveViews() { 37696d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (mAdapter != null) { 377ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen return Math.min(getCount() + 1, mMaxNumActiveViews); 37896d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 37996d8d56302da81b24333b204e6d7f15064538036Adam Cohen return mMaxNumActiveViews; 38096d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 38196d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 38296d8d56302da81b24333b204e6d7f15064538036Adam Cohen 38396d8d56302da81b24333b204e6d7f15064538036Adam Cohen int getWindowSize() { 38496d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (mAdapter != null) { 385ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen int adapterCount = getCount(); 38696d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (adapterCount <= getNumActiveViews() && mLoopViews) { 38796d8d56302da81b24333b204e6d7f15064538036Adam Cohen return adapterCount*mMaxNumActiveViews; 38896d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 38996d8d56302da81b24333b204e6d7f15064538036Adam Cohen return adapterCount; 39096d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 39196d8d56302da81b24333b204e6d7f15064538036Adam Cohen } else { 39296d8d56302da81b24333b204e6d7f15064538036Adam Cohen return 0; 39396d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 39496d8d56302da81b24333b204e6d7f15064538036Adam Cohen } 39596d8d56302da81b24333b204e6d7f15064538036Adam Cohen 396d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen private ViewAndMetaData getMetaDataForChild(View child) { 397d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen for (ViewAndMetaData vm: mViewsMap.values()) { 398d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen if (vm.view == child) { 399d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen return vm; 400d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } 401d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } 402d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen return null; 403d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } 404d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen 4059b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen LayoutParams createOrReuseLayoutParams(View v) { 4065b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy final ViewGroup.LayoutParams currentLp = v.getLayoutParams(); 4079b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen if (currentLp instanceof ViewGroup.LayoutParams) { 408b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen LayoutParams lp = (LayoutParams) currentLp; 409b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return lp; 41044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4119b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen return new ViewGroup.LayoutParams(0, 0); 41244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4146364f2bbe5254b4274f3feffc48f4259eacc205eWinson Chung void refreshChildren() { 415a9238c89a43500ed0bcdeaee182be08ff991c627Adam Cohen if (mAdapter == null) return; 416bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) { 417a9238c89a43500ed0bcdeaee182be08ff991c627Adam Cohen int index = modulo(i, getWindowSize()); 418bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 419ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen int adapterCount = getCount(); 420bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // get the fresh child from the adapter 421ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final View updatedChild = mAdapter.getView(modulo(i, adapterCount), null, this); 422bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 4234213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (updatedChild.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 4244213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov updatedChild.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 4254213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 4264213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 4271b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mViewsMap.containsKey(index)) { 428ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final FrameLayout fl = (FrameLayout) mViewsMap.get(index).view; 429bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // add the new child to the frame, if it exists 430bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen if (updatedChild != null) { 431ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // flush out the old child 432ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen fl.removeAllViewsInLayout(); 433bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(updatedChild); 434bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 435bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 436bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 437bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 438bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 439dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen /** 440dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * This method can be overridden so that subclasses can provide a custom frame in which their 441dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * children can live. For example, StackView adds padding to its childrens' frames so as to 442dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * accomodate for the highlight effect. 443dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * 444dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * @return The FrameLayout into which children can be placed. 445dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen */ 446dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout getFrameForChild() { 447dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen return new FrameLayout(mContext); 448dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen } 449dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen 450ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen /** 451ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * Shows only the specified child. The other displays Views exit the screen, 452ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * optionally with the with the {@link #getOutAnimation() out animation} and 453ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * the specified child enters the screen, optionally with the 454ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * {@link #getInAnimation() in animation}. 455ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * 456ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * @param childIndex The index of the child to be shown. 457ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * @param animate Whether or not to use the in and out animations, defaults 458ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen * to true. 459ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen */ 460ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen void showOnly(int childIndex, boolean animate) { 46144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mAdapter == null) return; 462ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen final int adapterCount = getCount(); 4633042944c6ec68210ba1746540b53789e70d15ef4Adam Cohen if (adapterCount == 0) return; 4643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 46544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mPreviousViews.size(); i++) { 4661b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View viewToRemove = mViewsMap.get(mPreviousViews.get(i)).view; 4671b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.remove(mPreviousViews.get(i)); 46844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen viewToRemove.clearAnimation(); 4693d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen if (viewToRemove instanceof ViewGroup) { 4703d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen ViewGroup vg = (ViewGroup) viewToRemove; 4713d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen vg.removeAllViewsInLayout(); 4723d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen } 47344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // applyTransformForChildAtIndex here just allows for any cleanup 47444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // associated with this view that may need to be done by a subclass 47544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(viewToRemove, -1); 4763d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen 47744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeViewInLayout(viewToRemove); 47844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 47944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 48044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStartUnbounded = childIndex - mActiveOffset; 48196d8d56302da81b24333b204e6d7f15064538036Adam Cohen int newWindowEndUnbounded = newWindowStartUnbounded + getNumActiveViews() - 1; 48244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStart = Math.max(0, newWindowStartUnbounded); 4831b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int newWindowEnd = Math.min(adapterCount - 1, newWindowEndUnbounded); 48444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 4851b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mLoopViews) { 4861b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen newWindowStart = newWindowStartUnbounded; 4871b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen newWindowEnd = newWindowEndUnbounded; 4881b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 48996d8d56302da81b24333b204e6d7f15064538036Adam Cohen int rangeStart = modulo(newWindowStart, getWindowSize()); 49096d8d56302da81b24333b204e6d7f15064538036Adam Cohen int rangeEnd = modulo(newWindowEnd, getWindowSize()); 4911b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4921b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean wrap = false; 4931b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (rangeStart > rangeEnd) { 4941b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen wrap = true; 4951b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 4961b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 4971b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // This section clears out any items that are in our active views list 49844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // but are outside the effective bounds of our window (this is becomes an issue 49944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // at the extremities of the list, eg. where newWindowStartUnbounded < 0 or 500ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // newWindowEndUnbounded > adapterCount - 1 5011b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen for (Integer index : mViewsMap.keySet()) { 5021b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean remove = false; 5031b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (!wrap && (index < rangeStart || index > rangeEnd)) { 5041b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen remove = true; 5051b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } else if (wrap && (index > rangeEnd && index < rangeStart)) { 5061b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen remove = true; 5071b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 5081b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 5091b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (remove) { 5101b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View previousView = mViewsMap.get(index).view; 511d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen int oldRelativeIndex = mViewsMap.get(index).relativeIndex; 5121b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 5131b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mPreviousViews.add(index); 51478db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(oldRelativeIndex, -1, previousView, animate); 5153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 51644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 5173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 51844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the window has changed 51996d8d56302da81b24333b204e6d7f15064538036Adam Cohen if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd && 52096d8d56302da81b24333b204e6d7f15064538036Adam Cohen newWindowStartUnbounded == mCurrentWindowStartUnbounded)) { 52144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Run through the indices in the new range 52244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStart; i <= newWindowEnd; i++) { 52344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 52496d8d56302da81b24333b204e6d7f15064538036Adam Cohen int index = modulo(i, getWindowSize()); 5251b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen int oldRelativeIndex; 5261b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (mViewsMap.containsKey(index)) { 527d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen oldRelativeIndex = mViewsMap.get(index).relativeIndex; 5281b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } else { 5291b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen oldRelativeIndex = -1; 5301b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen } 53144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newRelativeIndex = i - newWindowStartUnbounded; 53244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 53344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If this item is in the current window, great, we just need to apply 53444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // the transform for it's new relative position in the window, and animate 53544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // between it's current and new relative positions 5361b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen boolean inOldRange = mViewsMap.containsKey(index) && !mPreviousViews.contains(index); 5371b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen 5381b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen if (inOldRange) { 5391b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen View view = mViewsMap.get(index).view; 540d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen mViewsMap.get(index).relativeIndex = newRelativeIndex; 54144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(view, newRelativeIndex); 54278db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(oldRelativeIndex, newRelativeIndex, view, animate); 54344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5441b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // Otherwise this view is new to the window 54544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 5461b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen // Get the new view from the adapter, add it and apply any transform / animation 547d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen final int adapterPosition = modulo(i, adapterCount); 548d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen View newView = mAdapter.getView(adapterPosition, null, this); 549d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen long itemId = mAdapter.getItemId(adapterPosition); 550bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 551bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // We wrap the new view in a FrameLayout so as to respect the contract 552bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // with the adapter, that is, that we don't modify this view directly 553dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout fl = getFrameForChild(); 554bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 555bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // If the view from the adapter is null, we still keep an empty frame in place 55644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (newView != null) { 557bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(newView); 55844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 559d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen mViewsMap.put(index, new ViewAndMetaData(fl, newRelativeIndex, 560d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen adapterPosition, itemId)); 561bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen addChild(fl); 562bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen applyTransformForChildAtIndex(fl, newRelativeIndex); 56378db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen transformViewForTransition(-1, newRelativeIndex, fl, animate); 5643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5651b065cd1401253f999caa5d0ac12909407cef00eAdam Cohen mViewsMap.get(index).view.bringToFront(); 5663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 56744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = newWindowStart; 56844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = newWindowEnd; 56944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStartUnbounded = newWindowStartUnbounded; 570b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen if (mRemoteViewsAdapter != null) { 571d0c735fccc904366ded657263c33bb15475a1123Adam Cohen int adapterStart = modulo(mCurrentWindowStart, adapterCount); 572d0c735fccc904366ded657263c33bb15475a1123Adam Cohen int adapterEnd = modulo(mCurrentWindowEnd, adapterCount); 573d0c735fccc904366ded657263c33bb15475a1123Adam Cohen mRemoteViewsAdapter.setVisibleRangeHint(adapterStart, adapterEnd); 574b967392e0170af8cfd8053fd43fcdf8c46f703e9Adam Cohen } 57544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 576ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen requestLayout(); 577ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen invalidate(); 5783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 580839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void addChild(View child) { 581839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen addViewInLayout(child, -1, createOrReuseLayoutParams(child)); 582839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 583839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // This code is used to obtain a reference width and height of a child in case we need 584839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // to decide our own size. TODO: Do we want to update the size of the child that we're 585839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // using for reference size? If so, when? 586839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) { 587839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 588839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(measureSpec, measureSpec); 589839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildWidth = child.getMeasuredWidth(); 590839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildHeight = child.getMeasuredHeight(); 591839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 592839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 593839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 594a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void showTapFeedback(View v) { 595a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen v.setPressed(true); 596a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 597a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 598a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void hideTapFeedback(View v) { 599a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen v.setPressed(false); 600a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 601a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 602a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen void cancelHandleClick() { 603a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 604a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 605a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 606a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 607a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 608a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 609a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 610a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final class CheckForTap implements Runnable { 611a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 612a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) { 613a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 614a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen showTapFeedback(v); 615a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 616a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 617a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 618a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 619a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen @Override 620a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public boolean onTouchEvent(MotionEvent ev) { 621a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen int action = ev.getAction(); 622a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen boolean handled = false; 623a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen switch (action) { 624a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_DOWN: { 625a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 626a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 627a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) { 628a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mPendingCheckForTap == null) { 629a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mPendingCheckForTap = new CheckForTap(); 630a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 631a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_DOWN_IN_CURRENT_VIEW; 632a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 633a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 634a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 635a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen break; 636a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 637a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_MOVE: break; 638a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_POINTER_UP: break; 639a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_UP: { 640a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) { 641a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final View v = getCurrentView(); 642d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen final ViewAndMetaData viewData = getMetaDataForChild(v); 643a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 644a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) { 645a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen final Handler handler = getHandler(); 646a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (handler != null) { 647a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen handler.removeCallbacks(mPendingCheckForTap); 648a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 649a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen showTapFeedback(v); 650a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen postDelayed(new Runnable() { 651a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 652a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 653a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen post(new Runnable() { 654a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen public void run() { 655d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen if (viewData != null) { 656d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen performItemClick(v, viewData.adapterPosition, 657d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen viewData.itemId); 658d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } else { 659d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen performItemClick(v, 0, 0); 660d38a0cee2074fcf8005fc0d746aad282941a39b8Adam Cohen } 661a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 662a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen }); 663a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 664a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen }, ViewConfiguration.getPressedStateDuration()); 665a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen handled = true; 666a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 667a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 668a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 669a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 670a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen break; 671a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 672a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen case MotionEvent.ACTION_CANCEL: { 673a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen View v = getCurrentView(); 674a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen if (v != null) { 675a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen hideTapFeedback(v); 676a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 677a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen mTouchMode = TOUCH_MODE_NONE; 678a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 679a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 680a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen return handled; 681a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen } 682a32edd4b4c894f4fb3d9fd7e9d5b80321df79e20Adam Cohen 683839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void measureChildren() { 684839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int count = getChildCount(); 685189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn final int childWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight; 686189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn final int childHeight = getMeasuredHeight() - mPaddingTop - mPaddingBottom; 687839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 688839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen for (int i = 0; i < count; i++) { 689839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final View child = getChildAt(i); 690839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 691839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); 692839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 693839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 694839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 695839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen @Override 696839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 697839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 698839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 699839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 700839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 701839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 702839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1); 703839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 704839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // We need to deal with the case where our parent hasn't told us how 705839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // big we should be. In this case we try to use the desired size of the first 706839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // child added. 707839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (heightSpecMode == MeasureSpec.UNSPECIFIED) { 708839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop + 709839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingBottom : 0; 710839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 711189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (haveChildRefSize) { 712189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn int height = mReferenceChildHeight + mPaddingTop + mPaddingBottom; 713189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (height > heightSpecSize) { 714189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn heightSpecSize |= MEASURED_STATE_TOO_SMALL; 715189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } else { 716189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn heightSpecSize = height; 717189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 718189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 719839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 720839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 721839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (widthSpecMode == MeasureSpec.UNSPECIFIED) { 722839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft + 723839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingRight : 0; 724839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 725189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (haveChildRefSize) { 726189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn int width = mReferenceChildWidth + mPaddingLeft + mPaddingRight; 727189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn if (width > widthSpecSize) { 728189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn widthSpecSize |= MEASURED_STATE_TOO_SMALL; 729189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } else { 730189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn widthSpecSize = width; 731189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 732189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn } 733839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 734839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 735839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 736839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen measureChildren(); 737839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 738839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 739ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen void checkForAndHandleDataChanged() { 7403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean dataChanged = mDataChanged; 7413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (dataChanged) { 742ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen post(new Runnable() { 743ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen public void run() { 744ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen handleDataChanged(); 745ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // if the data changes, mWhichChild might be out of the bounds of the adapter 746ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen // in this case, we reset mWhichChild to the beginning 747ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen if (mWhichChild >= getWindowSize()) { 748ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mWhichChild = 0; 7493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 75078db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 751e86ff4d56145d875c13a1637833f9f55d79febc9Adam Cohen } else if (mOldItemCount != getCount()) { 75278db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 753ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 754ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen refreshChildren(); 755ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen requestLayout(); 756ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 757ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen }); 7583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 759ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mDataChanged = false; 760ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen } 761ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen 762ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen @Override 763ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 764ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen checkForAndHandleDataChanged(); 7653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int childCount = getChildCount(); 7673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < childCount; i++) { 7683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 7693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childRight = mPaddingLeft + child.getMeasuredWidth(); 7713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childBottom = mPaddingTop + child.getMeasuredHeight(); 7723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 773839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom); 7743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 777b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen static class SavedState extends BaseSavedState { 778b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen int whichChild; 779b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 780b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 781b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link AdapterViewAnimator#onSaveInstanceState()} 782b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 783b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState(Parcelable superState, int whichChild) { 784b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(superState); 785b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen this.whichChild = whichChild; 786b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 787b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 788b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 789b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link #CREATOR} 790b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 791b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen private SavedState(Parcel in) { 792b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(in); 7933ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung this.whichChild = in.readInt(); 794b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 795b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 796b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 797b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void writeToParcel(Parcel out, int flags) { 798b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.writeToParcel(out, flags); 7993ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung out.writeInt(this.whichChild); 800b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 801b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 802b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 803b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public String toString() { 8043ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung return "AdapterViewAnimator.SavedState{ whichChild = " + this.whichChild + " }"; 805b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 806b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 807b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public static final Parcelable.Creator<SavedState> CREATOR 808b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen = new Parcelable.Creator<SavedState>() { 809b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState createFromParcel(Parcel in) { 810b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(in); 811b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 812b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 813b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState[] newArray(int size) { 814b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState[size]; 815b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 816b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen }; 817b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 818b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 819b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 820b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public Parcelable onSaveInstanceState() { 821b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen Parcelable superState = super.onSaveInstanceState(); 822335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen if (mRemoteViewsAdapter != null) { 823335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen mRemoteViewsAdapter.saveRemoteViewsCache(); 824335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen } 825b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(superState, mWhichChild); 826b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 827b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 828b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 829b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void onRestoreInstanceState(Parcelable state) { 830b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState ss = (SavedState) state; 831b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.onRestoreInstanceState(ss.getSuperState()); 832b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 833b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // Here we set mWhichChild in addition to setDisplayedChild 834b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // We do the former in case mAdapter is null, and hence setDisplayedChild won't 835b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // set mWhichChild 836b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mWhichChild = ss.whichChild; 83769d66e00136f67332c992326a7b2eb334eeb32a2Adam Cohen 83816c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung // When using RemoteAdapters, the async connection process can lead to 83916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung // onRestoreInstanceState to be called before setAdapter(), so we need to save the previous 84016c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung // values to restore the list position after we connect, and can skip setting the displayed 84116c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung // child until then. 84216c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung if (mRemoteViewsAdapter != null && mAdapter == null) { 84316c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung mRestoreWhichChild = mWhichChild; 84416c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung } else { 84553838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen setDisplayedChild(mWhichChild, false); 84616c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung } 847b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 848b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 8493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the View corresponding to the currently displayed child. 8513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return The View currently displayed. 8533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getDisplayedChild() 8553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getCurrentView() { 85744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 8583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that enters the screen. 8623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 8643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8652794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setInAnimation(android.animation.ObjectAnimator) 8663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 8673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8682794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public ObjectAnimator getInAnimation() { 8693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mInAnimation; 8703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 8743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param inAnimation The animation started when a View enters the screen. 8763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 8783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 8793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public void setInAnimation(ObjectAnimator inAnimation) { 8813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mInAnimation = inAnimation; 8823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that exits the screen. 8863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 8883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8892794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setOutAnimation(android.animation.ObjectAnimator) 8903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 8913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8922794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public ObjectAnimator getOutAnimation() { 8933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mOutAnimation; 8943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 8983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 8993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param outAnimation The animation started when a View exit the screen. 9003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 9023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 9033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public void setOutAnimation(ObjectAnimator outAnimation) { 9053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mOutAnimation = outAnimation; 9063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 9093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 9103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 9123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 9133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 9152794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setInAnimation(android.animation.ObjectAnimator) 9163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Context context, int resourceID) { 9182794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase setInAnimation((ObjectAnimator) AnimatorInflater.loadAnimator(context, resourceID)); 9193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 9223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 9233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 9253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 9263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 9282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase * @see #setOutAnimation(android.animation.ObjectAnimator) 9293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Context context, int resourceID) { 9312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase setOutAnimation((ObjectAnimator) AnimatorInflater.loadAnimator(context, resourceID)); 9323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 9353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Indicates whether the current View should be animated the first time 9363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the ViewAnimation is displayed. 9373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 9383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate True to animate the current View the first time it is displayed, 9393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * false otherwise. 9403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAnimateFirstView(boolean animate) { 9423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAnimateFirstTime = animate; 9433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getBaseline() { 9473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 9483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Adapter getAdapter() { 9523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mAdapter; 9533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 9563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAdapter(Adapter adapter) { 9578322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen if (mAdapter != null && mDataSetObserver != null) { 9588322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen mAdapter.unregisterDataSetObserver(mDataSetObserver); 9598322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen } 9608322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen 9613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter = adapter; 9621480fddea874a42adb43b4bcdac6704e4c3e110bAdam Cohen checkFocus(); 9633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 9653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataSetObserver = new AdapterDataSetObserver(); 9663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.registerDataSetObserver(mDataSetObserver); 967ef17dd497edc14ca753616862efaa3457e1df5daAdam Cohen mItemCount = mAdapter.getCount(); 9683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 96944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen setFocusable(true); 97078db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen mWhichChild = 0; 97178db1aa9118edd71c2da28a2c23a0d875d1a707aAdam Cohen showOnly(mWhichChild, false); 9723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 9733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 9743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 97544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a 97644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * RemoteViewsService through the specified intent. 97744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 97844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param intent the intent used to identify the RemoteViewsService for the adapter to 97944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * connect to. 9803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 9813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @android.view.RemotableViewMethod 9823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setRemoteViewsAdapter(Intent intent) { 9839b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing 9849b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // service handling the specified intent. 9853ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung if (mRemoteViewsAdapter != null) { 9863ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung Intent.FilterComparison fcNew = new Intent.FilterComparison(intent); 9873ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung Intent.FilterComparison fcOld = new Intent.FilterComparison( 9883ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung mRemoteViewsAdapter.getRemoteViewsServiceIntent()); 9893ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung if (fcNew.equals(fcOld)) { 9903ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung return; 9913ec9a45c36d3ca5ffbc6e85bbeb497b065e14155Winson Chung } 9929b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung } 9932148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen mDeferNotifyDataSetChanged = false; 9949b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Otherwise, create a new RemoteViewsAdapter for binding 9953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); 996335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen if (mRemoteViewsAdapter.isDataReady()) { 997335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen setAdapter(mRemoteViewsAdapter); 998335c3b681bf1c118d9bf22d1a508c87173632ec6Adam Cohen } 9993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 10003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1001a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen /** 1002a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen * Sets up the onClickHandler to be used by the RemoteViewsAdapter when inflating RemoteViews 1003a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen * 1004a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen * @param handler The OnClickHandler to use when inflating RemoteViews. 1005a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen * 1006a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen * @hide 1007a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen */ 1008a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen public void setRemoteViewsOnClickHandler(OnClickHandler handler) { 1009a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen // Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing 1010a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen // service handling the specified intent. 1011a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen if (mRemoteViewsAdapter != null) { 1012a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen mRemoteViewsAdapter.setRemoteViewsOnClickHandler(handler); 1013a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen } 1014a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen } 1015a6a4cbc18f7e5a3831d787d3f398e02c5eae6512Adam Cohen 10163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 10173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setSelection(int position) { 10183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(position); 10193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 10203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 10213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 10223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getSelectedView() { 102344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 10243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 10253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 10263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 10272148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen * This defers a notifyDataSetChanged on the pending RemoteViewsAdapter if it has not 10282148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen * connected yet. 10292148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen */ 10302148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen public void deferNotifyDataSetChanged() { 10312148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen mDeferNotifyDataSetChanged = true; 10322148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen } 10332148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen 10342148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen /** 10353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter connects to the RemoteViewsService. 10363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 103716c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung public boolean onRemoteAdapterConnected() { 10383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 10393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 104016c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung 10412148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen if (mDeferNotifyDataSetChanged) { 10422148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen mRemoteViewsAdapter.notifyDataSetChanged(); 10432148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen mDeferNotifyDataSetChanged = false; 10442148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen } 10452148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen 104616c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung // Restore the previous position (see onRestoreInstanceState) 104716c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung if (mRestoreWhichChild > -1) { 104853838d265e36fb50341af168f5a91c3341c3cfc3Adam Cohen setDisplayedChild(mRestoreWhichChild, false); 104916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung mRestoreWhichChild = -1; 105016c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung } 105116c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung return false; 1052fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen } else if (mRemoteViewsAdapter != null) { 1053fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen mRemoteViewsAdapter.superNotifyDataSetChanged(); 105416c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung return true; 10553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 105616c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung return false; 10573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 10583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 10593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 10603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter disconnects from the RemoteViewsService. 10613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 10623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterDisconnected() { 1063fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // If the remote adapter disconnects, we keep it around 1064fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // since the currently displayed items are still cached. 1065fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // Further, we want the service to eventually reconnect 1066fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // when necessary, as triggered by this view requesting 1067fb60386b46d0c6216c765c10bd33ac42ca780917Adam Cohen // items from the Adapter. 10683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1069a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen 10700e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen /** 10710e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * Called by an {@link android.appwidget.AppWidgetHost} in order to advance the current view when 10720e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * it is being used within an app widget. 10730e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen */ 1074a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen public void advance() { 1075a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen showNext(); 1076a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen } 1077a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen 10780e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen /** 10790e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * Called by an {@link android.appwidget.AppWidgetHost} to indicate that it will be 10800e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * automatically advancing the views of this {@link AdapterViewAnimator} by calling 10810e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * {@link AdapterViewAnimator#advance()} at some point in the future. This allows subclasses to 10820e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen * perform any required setup, for example, to stop automatically advancing their children. 10830e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen */ 10840e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen public void fyiWillBeAdvancedByHostKThx() { 1085a02fdf1ba03fad71cc80a89dfc74b17456d5b4a5Adam Cohen } 10868a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 10878a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 10888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 10898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 10908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(AdapterViewAnimator.class.getName()); 10918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 10928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 10938a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 10948a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 10958a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 10968a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(AdapterViewAnimator.class.getName()); 10978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 10983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen} 1099