FastScroller.java revision b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator; 200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator.AnimatorListener; 210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorListenerAdapter; 220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorSet; 230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.ObjectAnimator; 240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.PropertyValuesHolder; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ColorStateList; 27e918a48df92fd16375c46624df74e6fd4609e016Alan Viveretteimport android.content.res.Resources; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 2920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.graphics.Rect; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.os.Build; 320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.text.TextUtils.TruncateAt; 330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.IntProperty; 340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.MathUtils; 350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.Property; 360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.Gravity; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 3820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.view.View; 390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.View.MeasureSpec; 40af5280cc71e155758c2f6625eb999cabb37e937fAdam Powellimport android.view.ViewConfiguration; 410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroup.LayoutParams; 420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroupOverlay; 43d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport com.android.internal.R; 460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-out animation. */ 520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_OUT = 300; 530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-in animation. */ 550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_IN = 150; 560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition cross-fade animation. */ 580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_CROSS_FADE = 50; 590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition resize animation. */ 610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_RESIZE = 100; 620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Inactivity timeout before fading controls. */ 640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long FADE_TIMEOUT = 1500; 65e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Minimum number of pages to justify showing a fast scroll thumb. */ 670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int MIN_PAGES = 4; 680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview not showing. */ 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 7120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb visible and moving along with the scrollbar. */ 730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_VISIBLE = 1; 740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview being dragged by user. */ 760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_DRAGGING = 2; 7720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Styleable attributes. */ 7920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int[] ATTRS = new int[] { 80b2e551711aa93a3d296ced6368e895743d43da80Adam Powell android.R.attr.fastScrollTextColor, 81128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollThumbDrawable, 82128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollTrackDrawable, 83128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollPreviewBackgroundLeft, 84128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollPreviewBackgroundRight, 85128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollOverlayPosition 8620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell }; 8720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Styleable attribute indices. 89b2e551711aa93a3d296ced6368e895743d43da80Adam Powell private static final int TEXT_COLOR = 0; 9020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int THUMB_DRAWABLE = 1; 9120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int TRACK_DRAWABLE = 2; 9220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int PREVIEW_BACKGROUND_LEFT = 3; 9320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int PREVIEW_BACKGROUND_RIGHT = 4; 9420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_POSITION = 5; 9520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Positions for preview image and text. 9720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_FLOATING = 0; 9820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_AT_THUMB = 1; 99e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Indices for mPreviewResId. 1010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_LEFT = 0; 1020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_RIGHT = 1; 1030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Delay before considering a tap in the thumb area to be a drag. */ 1050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 1060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempBounds = new Rect(); 1080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempMargins = new Rect(); 109fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private final Rect mContainerRect = new Rect(); 11020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AbsListView mList; 1120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ViewGroupOverlay mOverlay; 1130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mPrimaryText; 1140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mSecondaryText; 1150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mThumbImage; 1160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mTrackImage; 1170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mPreviewImage; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Preview image resource IDs for left- and right-aligned layouts. See 1210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}. 1220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int[] mPreviewResId = new int[2]; 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Padding in pixels around the preview text. Applied as layout margins to 1270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the preview text and padding to the preview image. 1280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int mPreviewPadding; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether there is a track image to display. */ 1320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final boolean mHasTrackImage; 1330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Total width of decorations. */ 13526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private final int mWidth; 13626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing decoration transition animations. */ 1380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mDecorAnimation; 1390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing preview text transition animations. */ 1410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mPreviewAnimation; 1420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the primary text is showing. */ 1440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mShowingPrimary; 1450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether we're waiting for completion of scrollTo(). */ 1470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mScrollCompleted; 1480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The position of the first visible item in the list. */ 1500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mFirstVisibleItem; 1510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of headers at the top of the view. */ 1530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mHeaderCount; 1540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The index of the current section. */ 1560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mCurrentSection = -1; 1570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** The current scrollbar position. */ 15926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollbarPosition = -1; 16026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the list is long enough to need a fast scroller. */ 1624df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 163e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private Object[] mSections; 165e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 166fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette /** Whether this view is currently performing layout. */ 167fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private boolean mUpdatingLayout; 168fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 1690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Current decoration state, one of: 1710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_NONE}, nothing visible 1730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_VISIBLE}, showing track and thumb 1740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_DRAGGING}, visible and showing preview 1750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 178e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private BaseAdapter mListAdapter; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether decorations should be laid out from right to left. */ 1830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mLayoutFromRight; 18420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 185447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** Whether the fast scroller is enabled. */ 186447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette private boolean mEnabled; 187447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the scrollbar and decorations should always be shown. */ 18920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private boolean mAlwaysShow; 19020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Position for the preview image and text. One of: 1930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_AT_THUMB} 1950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_FLOATING} 1960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 19820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private int mOverlayPosition; 19920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 20026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Current scrollbar style, including inset and overlay properties. */ 20126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollBarStyle; 20226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether to precisely match the thumb position to the list. */ 204568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell private boolean mMatchDragPosition; 205568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 2060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float mInitialTouchY; 2070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mHasPendingDrag; 208af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private int mScaledTouchSlop; 209af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 210af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private final Runnable mDeferStartDrag = new Runnable() { 211e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 212af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell public void run() { 213af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList.mIsAttached) { 214af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell beginDrag(); 215af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(mInitialTouchY); 2170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 218af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 219af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = false; 2210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to delay hiding fast scroll decorations. 2260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Runnable mDeferHide = new Runnable() { 2280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void run() { 2300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 2310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to effect a transition from primary to secondary text. 2360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() { 2380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onAnimationEnd(Animator animation) { 2400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mShowingPrimary = !mShowingPrimary; 241af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 242af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell }; 243af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 24439bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette public FastScroller(AbsListView listView) { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 2460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay = listView.getOverlay(); 2470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 24839bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette final Context context = listView.getContext(); 2490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 2500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Resources res = context.getResources(); 2520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS); 2530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 25426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final ImageView trackImage = new ImageView(context); 25526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mTrackImage = trackImage; 25626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 25726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette int width = 0; 2580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add track to overlay if it has an image. 26026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Drawable trackDrawable = ta.getDrawable(TRACK_DRAWABLE); 26126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (trackDrawable != null) { 2620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasTrackImage = true; 26326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette trackImage.setBackground(trackDrawable); 26426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mOverlay.add(trackImage); 26526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette width = Math.max(width, trackDrawable.getIntrinsicWidth()); 2660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 2670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasTrackImage = false; 2680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 27026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final ImageView thumbImage = new ImageView(context); 27126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mThumbImage = thumbImage; 2720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add thumb to overlay if it has an image. 2740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Drawable thumbDrawable = ta.getDrawable(THUMB_DRAWABLE); 2750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (thumbDrawable != null) { 27626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette thumbImage.setImageDrawable(thumbDrawable); 27726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mOverlay.add(thumbImage); 27826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette width = Math.max(width, thumbDrawable.getIntrinsicWidth()); 2790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If necessary, apply minimum thumb width and height. 2820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (thumbDrawable.getIntrinsicWidth() <= 0 || thumbDrawable.getIntrinsicHeight() <= 0) { 28326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int minWidth = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width); 28426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette thumbImage.setMinimumWidth(minWidth); 28526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette thumbImage.setMinimumHeight( 2860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height)); 28726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette width = Math.max(width, minWidth); 2880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 29026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mWidth = width; 29126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); 2930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage = new ImageView(context); 2940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setMinimumWidth(previewSize); 2950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setMinimumHeight(previewSize); 2960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setAlpha(0f); 2970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mPreviewImage); 2980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewPadding = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_padding); 3000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3016b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int textMinSize = Math.max(0, previewSize - mPreviewPadding); 3020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText = createPreviewTextView(context, ta); 3036b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumWidth(textMinSize); 3046b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumHeight(textMinSize); 3050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mPrimaryText); 3060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText = createPreviewTextView(context, ta); 3076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumWidth(textMinSize); 3086b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumHeight(textMinSize); 3090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mSecondaryText); 3100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(PREVIEW_BACKGROUND_LEFT, 0); 3120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(PREVIEW_BACKGROUND_RIGHT, 0); 3130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING); 3140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ta.recycle(); 3150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 31626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollBarStyle = listView.getScrollBarStyle(); 3170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScrollCompleted = true; 3180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = STATE_VISIBLE; 31926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mMatchDragPosition = context.getApplicationInfo().targetSdkVersion 32026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette >= Build.VERSION_CODES.HONEYCOMB; 3210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette getSectionsFromIndexer(); 3230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 324b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette updateLongList(listView.getChildCount(), listView.getCount()); 3250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setScrollbarPosition(mList.getVerticalScrollbarPosition()); 326a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 330447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * Removes this FastScroller overlay from the host view. 331447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 332447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void remove() { 333447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mTrackImage); 334447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mThumbImage); 335447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPreviewImage); 336447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPrimaryText); 337447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mSecondaryText); 338447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 339447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 340447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 341447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @param enabled Whether the fast scroll thumb is enabled. 342447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 343447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void setEnabled(boolean enabled) { 344b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mEnabled != enabled) { 345b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mEnabled = enabled; 346447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 347b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette onStateDependencyChanged(); 348447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 349447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 350447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 351447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 352447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @return Whether the fast scroll thumb is enabled. 353447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 354447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public boolean isEnabled() { 355b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return mEnabled && (mLongList || mAlwaysShow); 356447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 357447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 358447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 3590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param alwaysShow Whether the fast scroll thumb should always be shown 3600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 36120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setAlwaysShow(boolean alwaysShow) { 362b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mAlwaysShow != alwaysShow) { 363b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mAlwaysShow = alwaysShow; 3640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 365b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette onStateDependencyChanged(); 36620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 36720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 36820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 3690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 3700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the fast scroll thumb will always be shown 3710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #setAlwaysShow(boolean) 3720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 37320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public boolean isAlwaysShowEnabled() { 37420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell return mAlwaysShow; 37520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 37620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 377b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette /** 378b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette * Called when one of the variables affecting enabled state changes. 379b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette */ 380b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette private void onStateDependencyChanged() { 381b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isEnabled()) { 382b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isAlwaysShowEnabled()) { 383b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette setState(STATE_VISIBLE); 384b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else if (mState == STATE_VISIBLE) { 385b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette postAutoHide(); 386b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 387b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else { 388b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette stop(); 389b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 390b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 391b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mList.resolvePadding(); 392b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 393b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 39426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void setScrollBarStyle(int style) { 39526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollBarStyle != style) { 39626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollBarStyle = style; 39726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 39826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 39926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 40026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 40126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 4020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Immediately transitions the fast scroller decorations to a hidden state. 4040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void stop() { 4060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 4070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 40820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 40920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setScrollbarPosition(int position) { 410c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio if (position == View.SCROLLBAR_POSITION_DEFAULT) { 411c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio position = mList.isLayoutRtl() ? 412c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; 413c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio } 4140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 41526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition != position) { 41626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollbarPosition = position; 41726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; 4180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 41926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; 42026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setBackgroundResource(previewResId); 4210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 42226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Add extra padding for text. 42326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Drawable background = mPreviewImage.getBackground(); 42426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (background != null) { 42526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Rect padding = mTempBounds; 42626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette background.getPadding(padding); 42726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette padding.offset(mPreviewPadding, mPreviewPadding); 42826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); 42926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 4300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 43126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Requires re-layout. 43226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 43326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 43420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 43520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 43620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public int getWidth() { 43726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette return mWidth; 43820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 43920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onSizeChanged(int w, int h, int oldw, int oldh) { 4410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 4420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 4430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onItemCountChanged(int oldTotalItemCount, int totalItemCount) { 4450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int visibleItemCount = mList.getChildCount(); 4460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 4470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 4480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int firstVisibleItem = mList.getFirstVisiblePosition(); 4490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 451b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 452b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette updateLongList(visibleItemCount, totalItemCount); 453b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 454b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 455b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette private void updateLongList(int visibleItemCount, int totalItemCount) { 456b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette final boolean longList = visibleItemCount > 0 457b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette && totalItemCount / visibleItemCount >= MIN_PAGES; 458b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mLongList != longList) { 459b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mLongList = longList; 460b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 461b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette onStateDependencyChanged(); 462b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 464e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 4650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Creates a view into which preview text can be placed. 4670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private TextView createPreviewTextView(Context context, TypedArray ta) { 4690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final LayoutParams params = new LayoutParams( 4700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 4710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Resources res = context.getResources(); 4720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int minSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); 4730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ColorStateList textColor = ta.getColorStateList(TEXT_COLOR); 4740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float textSize = res.getDimension(R.dimen.fastscroll_overlay_text_size); 4750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView textView = new TextView(context); 4760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutParams(params); 4770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setTextColor(textColor); 4780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setTextSize(textSize); 4790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setSingleLine(true); 4800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setEllipsize(TruncateAt.MIDDLE); 4810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setGravity(Gravity.CENTER); 4820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setAlpha(0f); 4830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Manually propagate inherited layout direction. 4850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutDirection(mList.getLayoutDirection()); 4860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return textView; 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 489e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 4900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures and layouts the scrollbar and decorations. 4920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 49326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void updateLayout() { 494fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // Prevent re-entry when RTL properties change as a side-effect of 495fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // resolving padding. 496fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (mUpdatingLayout) { 497fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette return; 498fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 499fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 500fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = true; 501fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 502fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette updateContainerRect(); 503fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 5040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutThumb(); 5050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutTrack(); 5060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 5080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mPrimaryText, bounds); 5090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPrimaryText, bounds); 5100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mSecondaryText, bounds); 5110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mSecondaryText, bounds); 5120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewImage != null) { 5140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding. 5150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 5160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 5170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 5180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 5190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPreviewImage, bounds); 52020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 521fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 522fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = false; 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 524e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Layouts a view within the specified bounds and pins the pivot point to 5270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the appropriate edge. 5280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to layout. 5300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param bounds Bounds at which to layout the view. 5310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void applyLayout(View view, Rect bounds) { 5330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom); 5340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0); 5350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the preview text bounds, taking preview image padding into 5390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * account. This method should only be called after {@link #layoutThumb()} 5400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * and {@link #layoutTrack()} have both been called at least once. 5410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param v The preview text view to measure. 5430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 5440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measurePreview(View v, Rect out) { 5460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply the preview image's padding as layout margins. 5470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect margins = mTempMargins; 5480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.left = mPreviewImage.getPaddingLeft(); 5490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.top = mPreviewImage.getPaddingTop(); 5500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.right = mPreviewImage.getPaddingRight(); 5510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.bottom = mPreviewImage.getPaddingBottom(); 5520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mOverlayPosition == OVERLAY_AT_THUMB) { 5540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(v, mThumbImage, margins, out); 55520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } else { 5560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureFloating(v, margins, out); 55720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the bounds for a view that should be laid out against the edge 5620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * of an adjacent view. If no adjacent view is provided, lays out against 5630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the list edge. 5640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to measure for layout. 5660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param adjacent (Optional) The adjacent view, may be null to align to the 5670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * list edge. 5680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param margins Layout margins to apply to the view. 5690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 5700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) { 5720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 5730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 5740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 5750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 5760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 5770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 5780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 5790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 5800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 5810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 5820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 5830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5841ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 585fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 586fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 5870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int maxWidth; 5880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (adjacent == null) { 589fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth; 5900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (mLayoutFromRight) { 5910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = adjacent.getLeft(); 5920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 593fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth - adjacent.getRight(); 5940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 59520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 5960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int adjMaxWidth = maxWidth - marginLeft - marginRight; 5970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 5980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 5990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.measure(widthMeasureSpec, heightMeasureSpec); 6000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align to the left or right. 6020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = view.getMeasuredWidth(); 6030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left; 6040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right; 6050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 606fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette right = (adjacent == null ? container.right : adjacent.getLeft()) - marginRight; 6070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = right - width; 6080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 609fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette left = (adjacent == null ? container.left : adjacent.getRight()) + marginLeft; 6100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = left + width; 6110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 61220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Don't adjust the vertical position. 6140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = marginTop; 6150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + view.getMeasuredHeight(); 6160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 618af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 6190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureFloating(View preview, Rect margins, Rect out) { 6200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 632568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 633fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 634fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 635fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int adjMaxWidth = containerWidth - marginLeft - marginRight; 6360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 6370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 6380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette preview.measure(widthMeasureSpec, heightMeasureSpec); 6390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align at the vertical center, 10% from the top. 641fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerHeight = container.height(); 6420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = preview.getMeasuredWidth(); 643fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = containerHeight / 10 + marginTop + container.top; 6440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + preview.getMeasuredHeight(); 645fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = (containerWidth - width) / 2 + container.left; 6460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + width; 6470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 65026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** 65126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette * Updates the container rectangle used for layout. 65226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette */ 653fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private void updateContainerRect() { 654fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final AbsListView list = mList; 65526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette list.resolvePadding(); 65626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 657fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 658fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left = 0; 659fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top = 0; 660fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right = list.getWidth(); 661fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom = list.getHeight(); 662fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 66326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int scrollbarStyle = mScrollBarStyle; 664fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET 665fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { 666fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left += list.getPaddingLeft(); 667fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top += list.getPaddingTop(); 668fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right -= list.getPaddingRight(); 669fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom -= list.getPaddingBottom(); 67026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 67126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // In inset mode, we need to adjust for padded scrollbar width. 67226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { 67326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int width = getWidth(); 67426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { 67526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.right += width; 67626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } else { 67726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.left -= width; 67826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 67926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 680fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 681fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 682fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 6830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the thumb according to the current scrollbar position. 6850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutThumb() { 6870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 6880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(mThumbImage, null, null, bounds); 6890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mThumbImage, bounds); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 691e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 693fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * Lays out the track centered on the thumb. Must be called after 694fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * {@link #layoutThumb}. 6950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutTrack() { 6970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View track = mTrackImage; 6980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View thumb = mThumbImage; 699fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 700fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 701fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(containerWidth, MeasureSpec.AT_MOST); 7020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 7030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.measure(widthMeasureSpec, heightMeasureSpec); 7040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackWidth = track.getMeasuredWidth(); 7060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int thumbHalfHeight = thumb == null ? 0 : thumb.getHeight() / 2; 707fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2; 7080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + trackWidth; 709fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top + thumbHalfHeight; 710fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom - thumbHalfHeight; 7110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.layout(left, top, right, bottom); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 713e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setState(int state) { 7150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.removeCallbacks(mDeferHide); 716e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mAlwaysShow && state == STATE_NONE) { 7180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette state = STATE_VISIBLE; 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (state == mState) { 7220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return; 7230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (state) { 7260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_NONE: 7270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToHidden(); 7280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_VISIBLE: 7300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToVisible(); 7310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_DRAGGING: 7336b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(mCurrentSection)) { 7346b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToDragging(); 7356b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 7366b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 7376b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 7380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 74020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 7410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = state; 742e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 7440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 745e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void refreshDrawablePressedState() { 7470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean isPressed = mState == STATE_DRAGGING; 7480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setPressed(isPressed); 7490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setPressed(isPressed); 7500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 751e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows nothing. 7540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToHidden() { 7560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 7570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage, 7610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT); 7620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Push the thumb and track outside the list bounds. 7640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth(); 7650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideOut = groupAnimatorOfFloat( 7660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, offset, mThumbImage, mTrackImage) 7670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 7680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 7700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeOut, slideOut); 7710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb and track. 7760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToVisible() { 7780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 7790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage) 7830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 7840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat( 7850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText) 7860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 7870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 7880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 7890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 7910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn); 7920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7942c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 7950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb, preview, and track. 7970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToDragging() { 7990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8012c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat( 8040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage) 8050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, slideIn); 8110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 8122c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8132c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 814a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette private void postAutoHide() { 815a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.removeCallbacks(mDeferHide); 816a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.postDelayed(mDeferHide, FADE_TIMEOUT); 817a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 818a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 8190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 820b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 8210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 8260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 8270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mFirstVisibleItem != firstVisibleItem) { 8330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mFirstVisibleItem = firstVisibleItem; 834d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 8350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Show the thumb, if necessary, and set up auto-fade. 8360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState != STATE_DRAGGING) { 8370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 838a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 8390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 840d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 841d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 842d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 8430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void getSectionsFromIndexer() { 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 8450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Adapter adapter = mList.getAdapter(); 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 8480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount(); 8490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 8530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter) 8540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .getAdapter(); 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (adapter instanceof SectionIndexer) { 8610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 8620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSectionIndexer = (SectionIndexer) adapter; 8630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = mSectionIndexer.getSections(); 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 8660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = null; 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 870b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell public void onSectionsChanged() { 871b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell mListAdapter = null; 872b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell } 873b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell 8740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Scrolls to a specific position within the section 8760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position 8770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void scrollTo(float position) { 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 8800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int count = mList.getCount(); 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 8830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int sectionCount = sections == null ? 0 : sections.length; 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 8850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (sections != null && sectionCount > 1) { 8860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int exactSection = MathUtils.constrain( 8870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette (int) (position * sectionCount), 0, sectionCount - 1); 8880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetSection = exactSection; 8890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetIndex = mSectionIndexer.getPositionForSection(targetSection); 8900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 8910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 8990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevIndex = targetIndex; 9000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevSection = targetSection; 9010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int nextSection = targetSection + 1; 9020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 9040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetSection < sectionCount - 1) { 9050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1); 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 907e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 9090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (nextIndex == targetIndex) { 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 9110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (targetSection > 0) { 9120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetSection--; 9130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevIndex = mSectionIndexer.getPositionForSection(targetSection); 9140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevIndex != targetIndex) { 9150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevSection = targetSection; 9160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 917b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 9180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (targetSection == 0) { 919b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 920b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 921b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 922b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 923b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 928e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // unique. For instance, if there is no P, then request for P's 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 930e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // sure that there is really a Q at Q's position. If not, move 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 9330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (nextNextSection < sectionCount && 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 9400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // currently visible section. This could be equal to or greater than 9410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // (1 / nSections). If the target position is near the previous 9420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // position, snap to the previous position. 9430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float prevPosition = (float) prevSection / sectionCount; 9440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float nextPosition = (float) nextSection / sectionCount; 9450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count; 9460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevSection == exactSection && position - prevPosition < snapThreshold) { 9470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex; 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition) 9500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette / (nextPosition - prevPosition)); 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Clamp to valid positions. 9540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = MathUtils.constrain(targetIndex, 0, count - 1); 955e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 9570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListView expList = (ExpandableListView) mList; 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 9590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)), 9600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0); 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 9620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0); 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(targetIndex + mHeaderCount); 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int index = MathUtils.constrain((int) (position * count), 0, count - 1); 9687ee1ff1450a3ff83b6b8663bd7f44dc6f30775afAdam Powell 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 9720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0); 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 9740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0); 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(index + mHeaderCount); 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (mCurrentSection != sectionIndex) { 9836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mCurrentSection = sectionIndex; 9846b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 9856b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(sectionIndex)) { 9860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToDragging(); 9876b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 9886b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 9890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9946b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * Transitions the preview text to a new section. Handles animation, 9956b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * measurement, and layout. If the new preview text is empty, returns false. 9960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 9976b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @param sectionIndex The section index to which the preview should 9986b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * transition. 9996b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @return False if the new preview text is empty. 10000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 10016b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette private boolean transitionPreviewLayout(int sectionIndex) { 10026b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object[] sections = mSections; 10036b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette String text = null; 10046b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) { 10056b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object section = sections[sectionIndex]; 10066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section != null) { 10076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette text = section.toString(); 10086b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10096b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10106b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 10120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ImageView preview = mPreviewImage; 10130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView showing; 10140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView target; 10150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mShowingPrimary) { 10160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mPrimaryText; 10170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mSecondaryText; 10180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 10190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mSecondaryText; 10200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mPrimaryText; 10210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Set and layout target immediately. 10240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setText(text); 10250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(target, bounds); 10260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(target, bounds); 10270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewAnimation != null) { 10290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.cancel(); 10300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Cross-fade preview text. 10330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE); 10340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE); 10350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette hideShowing.addListener(mSwitchPrimaryListener); 10360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding and animate bounds, if necessary. 10380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 10390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 10400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 10410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 10420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator resizePreview = animateBounds(preview, bounds); 10430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette resizePreview.setDuration(DURATION_RESIZE); 10440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation = new AnimatorSet(); 10460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget); 10470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(resizePreview); 10480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // The current preview size is unaffected by hidden or showing. It's 10500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // used to set starting scales for things that need to be scaled down. 10510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewWidth = preview.getWidth() - preview.getPaddingLeft() 10520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette - preview.getPaddingRight(); 10530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If target is too large, shrink it immediately to fit and expand to 10550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // target size. Otherwise, start at target size. 10560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int targetWidth = target.getWidth(); 10570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetWidth > previewWidth) { 10580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX((float) previewWidth / targetWidth); 10590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE); 10600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 10610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 10620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX(1f); 10630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If showing is larger than target, shrink to target size. 10660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int showingWidth = showing.getWidth(); 10670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (showingWidth > targetWidth) { 10680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float scale = (float) targetWidth / showingWidth; 10690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE); 10700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 10710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.start(); 10746b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10756b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette return (text != null && text.length() > 0); 10760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 10790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Positions the thumb and preview widgets. 10800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 10810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position The position, between 0 and 1, along the track at which 10820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * to place the thumb. 10830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 10840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setThumbPos(float position) { 1085fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 1086fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top; 1087fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom; 1088fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 1089fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final ImageView trackImage = mTrackImage; 1090fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final ImageView thumbImage = mThumbImage; 1091fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1092fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 10930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 10940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 10950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbMiddle = position * range + offset; 1096fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2); 10970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Center the preview on the thumb, constrained to the list bounds. 1099fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final ImageView previewImage = mPreviewImage; 1100fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float previewHalfHeight = previewImage.getHeight() / 2f; 11010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float minP = top + previewHalfHeight; 11020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float maxP = bottom - previewHalfHeight; 11030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewMiddle = MathUtils.constrain(thumbMiddle, minP, maxP); 11040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewTop = previewMiddle - previewHalfHeight; 1105fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette previewImage.setTranslationY(previewTop); 11060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText.setTranslationY(previewTop); 11080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText.setTranslationY(previewTop); 11090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromMotionEvent(float y) { 1112fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 1113fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top; 1114fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom; 11150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1116fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final ImageView trackImage = mTrackImage; 1117fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1118fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 11190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 11200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 11210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the list is the same height as the thumbnail or shorter, 11230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // effectively disable scrolling. 11240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (range <= 0) { 11250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return 0f; 11260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return MathUtils.constrain((y - offset) / range, 0f, 1f); 11290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromItemCount( 11320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int firstVisibleItem, int visibleItemCount, int totalItemCount) { 113335948b7ed502d3f126acc8f2d61e099fa5deb0c7Adam Powell if (mSectionIndexer == null || mListAdapter == null) { 113432c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell getSectionsFromIndexer(); 113532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 11360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasSections = mSectionIndexer != null && mSections != null 11380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette && mSections.length > 0; 11390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (!hasSections || !mMatchDragPosition) { 11406b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette return (float) firstVisibleItem / (totalItemCount - visibleItemCount); 114132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 114232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11436b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Ignore headers. 11440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette firstVisibleItem -= mHeaderCount; 114532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell if (firstVisibleItem < 0) { 114632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell return 0; 114732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 11480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette totalItemCount -= mHeaderCount; 114932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11506b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Hidden portion of the first visible row. 11516b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final View child = mList.getChildAt(0); 11526b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float incrementalPos; 11536b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (child == null || child.getHeight() == 0) { 11546b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = 0; 11556b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 11566b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight(); 11576b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 11586b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 11596b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Number of rows in this section. 116032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem); 116132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int sectionPos = mSectionIndexer.getPositionForSection(section); 1162f49971ec06e65ee2a0f0fd48a615b89c677086e7Adam Powell final int sectionCount = mSections.length; 11636b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int positionsInSection; 11646b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section < sectionCount - 1) { 1165414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru final int nextSectionPos; 1166414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru if (section + 1 < sectionCount) { 1167414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = mSectionIndexer.getPositionForSection(section + 1); 1168414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } else { 1169414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = totalItemCount - 1; 1170414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } 11716b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = nextSectionPos - sectionPos; 11726b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 11736b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = totalItemCount - sectionPos; 11746b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 11756b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 11766b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Position within this section. 11776b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float posWithinSection; 11786b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (positionsInSection == 0) { 11796b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = 0; 11806b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 11816b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = (firstVisibleItem + incrementalPos - sectionPos) 11826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette / positionsInSection; 11836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 118432c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return (section + posWithinSection) / sectionCount; 118632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 118732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels an ongoing fling event by injecting a 11900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link MotionEvent#ACTION_CANCEL} into the host view. 11910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 11930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final MotionEvent cancelFling = MotionEvent.obtain( 11940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1198e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 11990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels a pending drag. 12010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 12020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #startPendingDrag() 12030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void cancelPendingDrag() { 1205af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.removeCallbacks(mDeferStartDrag); 12060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = false; 1207af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1208af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Delays dragging until after the framework has determined that the user is 12110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * scrolling, rather than tapping. 12120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void startPendingDrag() { 12140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = true; 12150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.postDelayed(mDeferStartDrag, TAP_TIMEOUT); 1216af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1217af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void beginDrag() { 1219af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 12200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1221af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1222af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1223af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 12240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1225af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1226af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1227af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1228af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1229af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1230af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1231af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1232af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onInterceptTouchEvent(MotionEvent ev) { 1234b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1235447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1236447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1237447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1238af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell switch (ev.getActionMasked()) { 1239af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_DOWN: 12400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(ev.getX(), ev.getY())) { 12410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the parent has requested that its children delay 12420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // pressed state (e.g. is a scrolling container) then we 12430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // need to allow the parent time to decide whether it wants 12440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // to intercept events. If it does, we will receive a CANCEL 12450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // event. 1246b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!mList.isInScrollingContainer()) { 1247b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette beginDrag(); 1248b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return true; 1249af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 12500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1251b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mInitialTouchY = ev.getY(); 1252b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette startPendingDrag(); 1253b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 1254b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette break; 1255b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette case MotionEvent.ACTION_MOVE: 1256b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isPointInside(ev.getX(), ev.getY())) { 1257b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette cancelPendingDrag(); 1258af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1259af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 1260af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_UP: 1261af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_CANCEL: 1262af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1263af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1269a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette public boolean onInterceptHoverEvent(MotionEvent ev) { 1270b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1271a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1272a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1273a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1274a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette final int actionMasked = ev.getActionMasked(); 1275a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER 1276a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE 1277a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette && isPointInside(ev.getX(), ev.getY())) { 1278a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette setState(STATE_VISIBLE); 1279a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 1280a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1281a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1282a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1283a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1284a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 12850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onTouchEvent(MotionEvent me) { 1286b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1287447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1288447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1289447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 12900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (me.getActionMasked()) { 12910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_UP: { 12920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mHasPendingDrag) { 12930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Allow a tap to scroll. 12940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 12970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 12980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 12990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 13010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Will hit the STATE_DRAGGING check below 1302d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 13030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 13050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList != null) { 13060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // ViewGroup does the right thing already, but there might 13070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // be other classes that don't properly reset on touch-up, 13080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // so do this explicitly just in case. 13090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.requestDisallowInterceptTouchEvent(false); 13100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 13110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 1314a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 13150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 131720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 13180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 131920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 13200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_MOVE: { 13210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mHasPendingDrag && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) { 1322af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 13230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1324af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1325af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1326af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1328af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1329af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1330af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1331af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1332af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1333af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1334af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1335af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell // Will hit the STATE_DRAGGING check below 1336af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 13390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // TODO: Ignore jitter. 13400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 13410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 13420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the previous scrollTo is still pending 13440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mScrollCompleted) { 13450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 13460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 13510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_CANCEL: { 13530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 13540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1359d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 13600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns whether a coordinate is inside the scroller's activation area. If 13620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * there is a track image, touching anywhere within the thumb-width of the 13630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * track activates scrolling. Otherwise, the user has to touch inside thumb 13640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * itself. 13650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 13660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param x The x-coordinate. 13670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param y The y-coordinate. 13680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the coordinate is inside the scroller's activation area. 13690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInside(float x, float y) { 13710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return isPointInsideX(x) && (mHasTrackImage || isPointInsideY(y)); 13720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideX(float x) { 13750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 13760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x >= mThumbImage.getLeft(); 13770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 13780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x <= mThumbImage.getRight(); 13790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideY(float y) { 13830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return y >= mThumbImage.getTop() && y <= mThumbImage.getBottom(); 13840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Constructs an animator for the specified property on a group of views. 13880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for 13890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * implementation details. 13900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 13910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param property The property being animated. 13920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param value The value to which that property should animate. 13930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param views The target views to animate. 13940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return An animator for all the specified views. 13950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator groupAnimatorOfFloat( 13970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Property<View, Float> property, float value, View... views) { 13980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet animSet = new AnimatorSet(); 13990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet.Builder builder = null; 14000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette for (int i = views.length - 1; i >= 0; i--) { 14020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator anim = ObjectAnimator.ofFloat(views[i], property, value); 14030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (builder == null) { 14040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder = animSet.play(anim); 14050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 14060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(anim); 14070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 140820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 140920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 14100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return animSet; 141182f3495b146b267f3786997752cef25310176349Romain Guy } 141282f3495b146b267f3786997752cef25310176349Romain Guy 14130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's scaleX value. 14150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateScaleX(View v, float target) { 14170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.SCALE_X, target); 14180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1419e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's alpha value. 14220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateAlpha(View v, float alpha) { 14240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.ALPHA, alpha); 14250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1426e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>left</code> functionality handled by the 14290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setLeft(int)} and {@link View#getLeft()} methods. 14300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> LEFT = new IntProperty<View>("left") { 14320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 14340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setLeft(value); 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1436e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 14390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getLeft(); 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 1442e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>top</code> functionality handled by the 14450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setTop(int)} and {@link View#getTop()} methods. 14460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> TOP = new IntProperty<View>("top") { 1448e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 14490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 14500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setTop(value); 14510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1452e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 14550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getTop(); 14560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 14580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>right</code> functionality handled by the 14610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setRight(int)} and {@link View#getRight()} methods. 14620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> RIGHT = new IntProperty<View>("right") { 14640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 14660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setRight(value); 14670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 14710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getRight(); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 14740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>bottom</code> functionality handled by the 14770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setBottom(int)} and {@link View#getBottom()} methods. 14780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") { 14800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 14820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setBottom(value); 14830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 14870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getBottom(); 14880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 14900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's bounds. 14930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateBounds(View v, Rect bounds) { 14950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left); 14960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top); 14970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right); 14980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom); 14990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom); 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1502