AdapterViewAnimator.java revision 3db40678d33c2b5f90c380966d36b3e10ed11f05
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 193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Context; 203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Intent; 213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.res.TypedArray; 223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Handler; 233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Looper; 243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.AttributeSet; 253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.Log; 263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.View; 273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.Animation; 283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.AnimationUtils; 293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/** 313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Base class for a {@link AdapterView} that will perform animations 323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * when switching between its views. 333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation 353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation 363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView 373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenpublic class AdapterViewAnimator extends AdapterView<Adapter> implements RemoteViewsAdapter.RemoteAdapterConnectionCallback{ 393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private static final String TAG = "RemoteViewAnimator"; 403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int mWhichChild = 0; 423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mFirstTime = true; 433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mAnimateFirstTime = true; 443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen AdapterDataSetObserver mDataSetObserver; 463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen View mPreviousView; 483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen View mCurrentView; 493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mInAnimation; 513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mOutAnimation; 523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Adapter mAdapter; 533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen RemoteViewsAdapter mRemoteViewsAdapter; 543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private Handler mMainQueue; 553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context) { 573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context); 583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen initViewAnimator(context, null); 593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs) { 623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context, attrs); 633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator); 653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0); 663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(context, resource); 683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0); 713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(context, resource); 733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true); 763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAnimateFirstView(flag); 773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen a.recycle(); 793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen initViewAnimator(context, attrs); 813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Initialize this {@link AdapterViewAnimator} 853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private void initViewAnimator(Context context, AttributeSet attrs) { 873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mMainQueue = new Handler(Looper.myLooper()); 883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets which child view will be displayed. 923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param whichChild the index of the child view to display 943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setDisplayedChild(int whichChild) { 963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = whichChild; 983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (whichChild >= mAdapter.getCount()) { 993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = 0; 1003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else if (whichChild < 0) { 1013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = mAdapter.getCount() - 1; 1023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean hasFocus = getFocusedChild() != null; 1053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This will clear old focus if we had it 1063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild); 1073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (hasFocus) { 1083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Try to retake focus if we had it 1093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestFocus(FOCUS_FORWARD); 1103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Return default inAnimation. To be overriden by subclasses. 1163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getDefaultInAnimation() { 1183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 1193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Return default outAnimation. To be overriden by subclasses. 1233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getDefaultOutAnimation() { 1253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 1263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the index of the currently displayed child view. 1303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getDisplayedChild() { 1323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mWhichChild; 1333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the next child. 1373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showNext() { 1393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild + 1); 1403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the previous child. 1443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showPrevious() { 1463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild - 1); 1473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen, 1513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * optionally with the with the {@link #getOutAnimation() out animation} and 1523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the specified child enters the screen, optionally with the 1533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * {@link #getInAnimation() in animation}. 1543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 1553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 1563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate Whether or not to use the in and out animations, defaults 1573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * to true. 1583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex, boolean animate) { 1603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate, false); 1613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private LayoutParams makeLayoutParams() { 1643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int width = mMeasuredWidth - mPaddingLeft - mPaddingRight; 1653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int height = mMeasuredHeight - mPaddingTop - mPaddingBottom; 1663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return new LayoutParams(width, height); 1673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void showOnly(int childIndex, boolean animate, boolean onLayout) { 1703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 1713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // The previous view should be removed from the ViewGroup 1723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mPreviousView != null) { 1733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mPreviousView.clearAnimation(); 1743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // TODO: this is where we would store the the view for 1763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // recycling 1773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen removeViewInLayout(mPreviousView); 1783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // If the current view is still being animated, we should 1813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // force the animation to end 1823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mCurrentView != null) { 1833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView.clearAnimation(); 1843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // load the new mCurrentView from our adapter 1873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mPreviousView = mCurrentView; 1883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView = mAdapter.getView(childIndex, null, this); 1893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mPreviousView != mCurrentView) { 1903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen addViewInLayout(mCurrentView, 0, makeLayoutParams(), true); 1913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView.bringToFront(); 1923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Animate as necessary 1973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mPreviousView != null && mPreviousView != mCurrentView) { 1983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (animate && mOutAnimation != null) { 1993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mPreviousView.startAnimation(mOutAnimation); 2003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This line results in the view becoming invisible *after* 2023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // the above animation is complete, or, if there is no animation 2033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // then it becomes invisble immediately 2043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mPreviousView.setVisibility(View.GONE); 2053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mCurrentView != null && animate && mInAnimation != null) { 2083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView.startAnimation(mInAnimation); 2093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mFirstTime = false; 2123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (!onLayout) { 2133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestLayout(); 2143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen invalidate(); 2153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else { 2163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // If the Adapter tries to layout the current view when we get it using getView above 2173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // the layout will end up being ignored since we are currently laying out, so 2183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // we post a delayed requestLayout and invalidate 2193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mMainQueue.post(new Runnable() { 2203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 2213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void run() { 2223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView.requestLayout(); 2233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mCurrentView.invalidate(); 2243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen }); 2263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 2313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 2323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean dataChanged = mDataChanged; 2333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (dataChanged) { 2343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen handleDataChanged(); 2353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // if the data changes, mWhichChild might be out of the bounds of the adapter 2373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // in this case, we reset mWhichChild to the beginning 2383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mWhichChild >= mAdapter.getCount()) 2393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = 0; 2403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild, true, true); 2423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int childCount = getChildCount(); 2453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < childCount; i++) { 2463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 2473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childRight = mPaddingLeft + child.getMeasuredWidth(); 2493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childBottom = mPaddingTop + child.getMeasuredHeight(); 2503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom); 2523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataChanged = false; 2553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 2583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 2593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int count = getChildCount(); 2603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 2623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 2633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Log.v(TAG, "onMeasure"); 2653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < count; i++) { 2673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 2683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen lp.width = widthSpecSize - mPaddingLeft - mPaddingRight; 2723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen lp.height = heightSpecSize - mPaddingTop - mPaddingBottom; 2733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, 2753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen MeasureSpec.EXACTLY); 2763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, 2773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen MeasureSpec.EXACTLY); 2783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen child.measure(childWidthMeasureSpec, childheightMeasureSpec); 2803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 2833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen 2873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * with the {@link #getOutAnimation() out animation} and the specified child 2883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * enters the screen with the {@link #getInAnimation() in animation}. 2893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 2913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex) { 2933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final boolean animate = (!mFirstTime || mAnimateFirstTime); 2943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate); 2953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the View corresponding to the currently displayed child. 2993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return The View currently displayed. 3013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getDisplayedChild() 3033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getCurrentView() { 3053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mCurrentView; 3063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that enters the screen. 3103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 3123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 3143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 3153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getInAnimation() { 3173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mInAnimation; 3183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 3223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param inAnimation The animation started when a View enters the screen. 3243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 3263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 3273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Animation inAnimation) { 3293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mInAnimation = inAnimation; 3303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that exits the screen. 3343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 3363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 3383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 3393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getOutAnimation() { 3413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mOutAnimation; 3423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 3463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param outAnimation The animation started when a View exit the screen. 3483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 3503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 3513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Animation outAnimation) { 3533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mOutAnimation = outAnimation; 3543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 3583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 3603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 3613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 3633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 3643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Context context, int resourceID) { 3663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); 3673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 3713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 3733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 3743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 3763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 3773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Context context, int resourceID) { 3793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); 3803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Indicates whether the current View should be animated the first time 3843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the ViewAnimation is displayed. 3853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate True to animate the current View the first time it is displayed, 3873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * false otherwise. 3883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAnimateFirstView(boolean animate) { 3903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAnimateFirstTime = animate; 3913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 3943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getBaseline() { 3953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 3963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 3993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Adapter getAdapter() { 4003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mAdapter; 4013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 4043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAdapter(Adapter adapter) { 4053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter = adapter; 4063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 4083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mDataSetObserver != null) { 4093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.unregisterDataSetObserver(mDataSetObserver); 4103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataSetObserver = new AdapterDataSetObserver(); 4133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.registerDataSetObserver(mDataSetObserver); 4143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 4183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a RemoteViewsService 4193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * through the specified intent. 4203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to. 4213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @android.view.RemotableViewMethod 4233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setRemoteViewsAdapter(Intent intent) { 4243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); 4253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 4283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setSelection(int position) { 4293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(position); 4303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 4333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getSelectedView() { 4343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mCurrentView; 4353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 4383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter connects to the RemoteViewsService. 4393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterConnected() { 4413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 4423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 4433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 4473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter disconnects from the RemoteViewsService. 4483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterDisconnected() { 4503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 4513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = null; 4523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 4533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen} 456