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; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 2820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.graphics.Rect; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.os.Build; 314cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viveretteimport android.os.SystemClock; 32f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viveretteimport android.text.TextUtils; 330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.text.TextUtils.TruncateAt; 340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.IntProperty; 350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.MathUtils; 360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.Property; 377b63063625467baff1db048e84c5781408a5c86dAlan Viveretteimport android.util.TypedValue; 380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.Gravity; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 4020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.view.View; 410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.View.MeasureSpec; 42af5280cc71e155758c2f6625eb999cabb37e937fAdam Powellimport android.view.ViewConfiguration; 430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroup.LayoutParams; 440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroupOverlay; 45d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 468636ace69640566768f89c2d92d2851ff064a2e9Alan Viveretteimport android.widget.ImageView.ScaleType; 470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-out animation. */ 530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_OUT = 300; 540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-in animation. */ 560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_IN = 150; 570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition cross-fade animation. */ 590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_CROSS_FADE = 50; 600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition resize animation. */ 620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_RESIZE = 100; 630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Inactivity timeout before fading controls. */ 650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long FADE_TIMEOUT = 1500; 66e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Minimum number of pages to justify showing a fast scroll thumb. */ 680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int MIN_PAGES = 4; 690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview not showing. */ 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 7220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb visible and moving along with the scrollbar. */ 740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_VISIBLE = 1; 750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview being dragged by user. */ 770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_DRAGGING = 2; 7820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Positions for preview image and text. 8020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_FLOATING = 0; 8120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_AT_THUMB = 1; 82e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette private static final int OVERLAY_ABOVE_THUMB = 2; 83e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Indices for mPreviewResId. 850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_LEFT = 0; 860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_RIGHT = 1; 870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Delay before considering a tap in the thumb area to be a drag. */ 890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempBounds = new Rect(); 920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempMargins = new Rect(); 93fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private final Rect mContainerRect = new Rect(); 9420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AbsListView mList; 960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ViewGroupOverlay mOverlay; 970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mPrimaryText; 980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mSecondaryText; 990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mThumbImage; 1000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mTrackImage; 1018636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private final View mPreviewImage; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Preview image resource IDs for left- and right-aligned layouts. See 1050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}. 1060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int[] mPreviewResId = new int[2]; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1097d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette /** The minimum touch target size in pixels. */ 1107d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette private final int mMinimumTouchTarget; 1117d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 1120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Padding in pixels around the preview text. Applied as layout margins to 1140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the preview text and padding to the preview image. 1150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1168636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewPadding; 1178636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1188636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinWidth; 1198636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinHeight; 1208636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinWidth; 1218636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinHeight; 1228636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1238636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text size. Used only if text appearance is not set. */ 1248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private float mTextSize; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1268636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text color. Used only if text appearance is not set. */ 1278636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private ColorStateList mTextColor; 1288636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1298636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mThumbDrawable; 1308636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mTrackDrawable; 1318636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mTextAppearance; 1320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Total width of decorations. */ 1348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mWidth; 13526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing decoration transition animations. */ 1370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mDecorAnimation; 1380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing preview text transition animations. */ 1400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mPreviewAnimation; 1410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the primary text is showing. */ 1430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mShowingPrimary; 1440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether we're waiting for completion of scrollTo(). */ 1460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mScrollCompleted; 1470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The position of the first visible item in the list. */ 1490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mFirstVisibleItem; 1500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of headers at the top of the view. */ 1520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mHeaderCount; 1530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The index of the current section. */ 1550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mCurrentSection = -1; 1560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** The current scrollbar position. */ 15826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollbarPosition = -1; 15926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the list is long enough to need a fast scroller. */ 1614df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 162e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private Object[] mSections; 164e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 165fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette /** Whether this view is currently performing layout. */ 166fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private boolean mUpdatingLayout; 167fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 1680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Current decoration state, one of: 1700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_NONE}, nothing visible 1720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_VISIBLE}, showing track and thumb 1730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_DRAGGING}, visible and showing preview 1740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 177e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 178f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette /** Whether the preview image is visible. */ 179f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette private boolean mShowingPreview; 180f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1814f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette private Adapter mListAdapter; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether decorations should be laid out from right to left. */ 1850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mLayoutFromRight; 18620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 187447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** Whether the fast scroller is enabled. */ 188447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette private boolean mEnabled; 189447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the scrollbar and decorations should always be shown. */ 19120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private boolean mAlwaysShow; 19220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Position for the preview image and text. One of: 1950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_FLOATING} 197e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette * <li>{@link #OVERLAY_AT_THUMB} 198e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette * <li>{@link #OVERLAY_ABOVE_THUMB} 1990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 2000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 20120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private int mOverlayPosition; 20220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 20326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Current scrollbar style, including inset and overlay properties. */ 20426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollBarStyle; 20526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether to precisely match the thumb position to the list. */ 207568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell private boolean mMatchDragPosition; 208568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 2090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float mInitialTouchY; 2104cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette private long mPendingDrag = -1; 211af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private int mScaledTouchSlop; 212af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2134b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private int mOldItemCount; 2144b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private int mOldChildCount; 2154b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette 2160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to delay hiding fast scroll decorations. 2180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Runnable mDeferHide = new Runnable() { 2200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void run() { 2220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 2230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to effect a transition from primary to secondary text. 2280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() { 2300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onAnimationEnd(Animator animation) { 2320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mShowingPrimary = !mShowingPrimary; 233af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 234af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell }; 235af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette public FastScroller(AbsListView listView, int styleResId) { 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 2384b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldItemCount = listView.getCount(); 2394b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldChildCount = listView.getChildCount(); 2400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 24139bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette final Context context = listView.getContext(); 2420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 2438636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollBarStyle = listView.getScrollBarStyle(); 2448636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollCompleted = true; 2468636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mState = STATE_VISIBLE; 2478636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mMatchDragPosition = 2488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; 2498636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage = new ImageView(context); 2518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setScaleType(ScaleType.FIT_XY); 2528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage = new ImageView(context); 2538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setScaleType(ScaleType.FIT_XY); 2548636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage = new View(context); 2558636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setAlpha(0f); 2568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText = createPreviewTextView(context); 2588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText = createPreviewTextView(context); 2598636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2607d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette mMinimumTouchTarget = listView.getResources().getDimensionPixelSize( 2617d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette com.android.internal.R.dimen.fast_scroller_minimum_touch_target); 2627d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 2638636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setStyle(styleResId); 2640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2658636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final ViewGroupOverlay overlay = listView.getOverlay(); 2668636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlay = overlay; 2678636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mTrackImage); 2688636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mThumbImage); 2698636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPreviewImage); 2708636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPrimaryText); 2718636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mSecondaryText); 2720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2738636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette getSectionsFromIndexer(); 2744b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette updateLongList(mOldChildCount, mOldItemCount); 2758636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setScrollbarPosition(listView.getVerticalScrollbarPosition()); 2768636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette postAutoHide(); 2778636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 27826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2798636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private void updateAppearance() { 2808636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final Context context = mList.getContext(); 28126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette int width = 0; 2820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add track to overlay if it has an image. 2848636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setImageDrawable(mTrackDrawable); 2858636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTrackDrawable != null) { 2868636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mTrackDrawable.getIntrinsicWidth()); 2870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add thumb to overlay if it has an image. 2908636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setImageDrawable(mThumbDrawable); 2918636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumWidth(mThumbMinWidth); 2928636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumHeight(mThumbMinHeight); 2938636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mThumbDrawable != null) { 2948636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mThumbDrawable.getIntrinsicWidth()); 2950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2978636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette // Account for minimum thumb width. 2988636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mWidth = Math.max(width, mThumbMinWidth); 2990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3008636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setMinimumWidth(mPreviewMinWidth); 3018636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setMinimumHeight(mPreviewMinHeight); 30226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 3038636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextAppearance != 0) { 3048636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextAppearance(context, mTextAppearance); 3058636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextAppearance(context, mTextAppearance); 3068636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3088636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextColor != null) { 3098636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextColor(mTextColor); 3108636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextColor(mTextColor); 3118636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3128636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 3138636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextSize > 0) { 3148636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3158636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3168636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3188636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int textMinSize = Math.max(0, mPreviewMinHeight); 3196b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumWidth(textMinSize); 3206b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumHeight(textMinSize); 321e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette mPrimaryText.setIncludeFontPadding(false); 3226b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumWidth(textMinSize); 3236b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumHeight(textMinSize); 324e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette mSecondaryText.setIncludeFontPadding(false); 3250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3268636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette refreshDrawablePressedState(); 3278636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3298636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette public void setStyle(int resId) { 3308636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final Context context = mList.getContext(); 3318636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final TypedArray ta = context.obtainStyledAttributes(null, 3328636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette com.android.internal.R.styleable.FastScroll, android.R.attr.fastScrollStyle, resId); 3338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int N = ta.getIndexCount(); 3348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette for (int i = 0; i < N; i++) { 3358636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int index = ta.getIndex(i); 3368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette switch (index) { 3378636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_position: 3388636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlayPosition = ta.getInt(index, OVERLAY_FLOATING); 3398636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3408636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_backgroundLeft: 3418636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(index, 0); 3428636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3438636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_backgroundRight: 3448636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(index, 0); 3458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3468636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbDrawable: 3478636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbDrawable = ta.getDrawable(index); 3488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3498636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_trackDrawable: 3508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackDrawable = ta.getDrawable(index); 3518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textAppearance: 3538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextAppearance = ta.getResourceId(index, 0); 3548636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3558636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textColor: 3568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextColor = ta.getColorStateList(index); 3578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textSize: 3598636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextSize = ta.getDimensionPixelSize(index, 0); 3608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3618636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_minWidth: 3628636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinWidth = ta.getDimensionPixelSize(index, 0); 3638636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3648636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_minHeight: 3658636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinHeight = ta.getDimensionPixelSize(index, 0); 3668636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3678636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbMinWidth: 3688636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinWidth = ta.getDimensionPixelSize(index, 0); 3698636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3708636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbMinHeight: 3718636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinHeight = ta.getDimensionPixelSize(index, 0); 3728636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3738636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_padding: 3748636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewPadding = ta.getDimensionPixelSize(index, 0); 3758636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3768636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3778636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3798636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette updateAppearance(); 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 383447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * Removes this FastScroller overlay from the host view. 384447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 385447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void remove() { 386447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mTrackImage); 387447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mThumbImage); 388447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPreviewImage); 389447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPrimaryText); 390447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mSecondaryText); 391447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 392447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 393447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 394447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @param enabled Whether the fast scroll thumb is enabled. 395447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 396447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void setEnabled(boolean enabled) { 397b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mEnabled != enabled) { 398b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mEnabled = enabled; 399447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 4008ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(true); 401447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 402447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 403447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 404447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 405447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @return Whether the fast scroll thumb is enabled. 406447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 407447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public boolean isEnabled() { 408b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return mEnabled && (mLongList || mAlwaysShow); 409447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 410447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 411447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 4120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param alwaysShow Whether the fast scroll thumb should always be shown 4130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 41420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setAlwaysShow(boolean alwaysShow) { 415b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mAlwaysShow != alwaysShow) { 416b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mAlwaysShow = alwaysShow; 4170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4188ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 41920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 42020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 42120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the fast scroll thumb will always be shown 4240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #setAlwaysShow(boolean) 4250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 42620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public boolean isAlwaysShowEnabled() { 42720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell return mAlwaysShow; 42820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 42920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 430b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette /** 431b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette * Called when one of the variables affecting enabled state changes. 4328ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * 4338ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * @param peekIfEnabled whether the thumb should peek, if enabled 434b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette */ 4358ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette private void onStateDependencyChanged(boolean peekIfEnabled) { 436b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isEnabled()) { 437b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isAlwaysShowEnabled()) { 438b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette setState(STATE_VISIBLE); 439b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else if (mState == STATE_VISIBLE) { 440b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette postAutoHide(); 4418ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette } else if (peekIfEnabled) { 4428ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette setState(STATE_VISIBLE); 4438ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette postAutoHide(); 444b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 445b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else { 446b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette stop(); 447b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 448b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 449b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mList.resolvePadding(); 450b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 451b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 45226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void setScrollBarStyle(int style) { 45326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollBarStyle != style) { 45426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollBarStyle = style; 45526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 45626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 45726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 45826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 45926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 4600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Immediately transitions the fast scroller decorations to a hidden state. 4620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void stop() { 4640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 4650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 46620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 46720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setScrollbarPosition(int position) { 468c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio if (position == View.SCROLLBAR_POSITION_DEFAULT) { 469c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio position = mList.isLayoutRtl() ? 470c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; 471c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio } 4720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 47326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition != position) { 47426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollbarPosition = position; 47526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; 4760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 47726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; 47826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setBackgroundResource(previewResId); 4790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 48026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Add extra padding for text. 48126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Drawable background = mPreviewImage.getBackground(); 48226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (background != null) { 48326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Rect padding = mTempBounds; 48426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette background.getPadding(padding); 48526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette padding.offset(mPreviewPadding, mPreviewPadding); 48626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); 48726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 4880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 48926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Requires re-layout. 49026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 49126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 49220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 49320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 49420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public int getWidth() { 49526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette return mWidth; 49620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 49720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onSizeChanged(int w, int h, int oldw, int oldh) { 4990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 5000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5024b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette public void onItemCountChanged(int childCount, int itemCount) { 5034b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette if (mOldItemCount != itemCount || mOldChildCount != childCount) { 5044b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldItemCount = itemCount; 5054b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldChildCount = childCount; 506b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5074b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final boolean hasMoreItems = itemCount - childCount > 0; 5084b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 5094b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final int firstVisibleItem = mList.getFirstVisiblePosition(); 5104b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, childCount, itemCount)); 5114b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette } 5124b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette 5134b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette updateLongList(childCount, itemCount); 5144b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette } 515b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 516b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5174b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private void updateLongList(int childCount, int itemCount) { 5184b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final boolean longList = childCount > 0 && itemCount / childCount >= MIN_PAGES; 519b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mLongList != longList) { 520b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mLongList = longList; 521b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5228ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 523b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 525e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Creates a view into which preview text can be placed. 5280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5298636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private TextView createPreviewTextView(Context context) { 5300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final LayoutParams params = new LayoutParams( 5310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 5320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView textView = new TextView(context); 5330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutParams(params); 5340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setSingleLine(true); 5350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setEllipsize(TruncateAt.MIDDLE); 5360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setGravity(Gravity.CENTER); 5370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setAlpha(0f); 5380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Manually propagate inherited layout direction. 5400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutDirection(mList.getLayoutDirection()); 5410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return textView; 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 544e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures and layouts the scrollbar and decorations. 5470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 54826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void updateLayout() { 549fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // Prevent re-entry when RTL properties change as a side-effect of 550fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // resolving padding. 551fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (mUpdatingLayout) { 552fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette return; 553fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 554fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 555fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = true; 556fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 557fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette updateContainerRect(); 558fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 5590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutThumb(); 5600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutTrack(); 5610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 5630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mPrimaryText, bounds); 5640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPrimaryText, bounds); 5650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mSecondaryText, bounds); 5660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mSecondaryText, bounds); 5670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewImage != null) { 5690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding. 5700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 5710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 5720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 5730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 5740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPreviewImage, bounds); 57520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 576fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 577fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = false; 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 579e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Layouts a view within the specified bounds and pins the pivot point to 5820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the appropriate edge. 5830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to layout. 5850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param bounds Bounds at which to layout the view. 5860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void applyLayout(View view, Rect bounds) { 5880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom); 5890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0); 5900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the preview text bounds, taking preview image padding into 5940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * account. This method should only be called after {@link #layoutThumb()} 5950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * and {@link #layoutTrack()} have both been called at least once. 5960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param v The preview text view to measure. 5980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 5990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measurePreview(View v, Rect out) { 6010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply the preview image's padding as layout margins. 6020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect margins = mTempMargins; 6030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.left = mPreviewImage.getPaddingLeft(); 6040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.top = mPreviewImage.getPaddingTop(); 6050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.right = mPreviewImage.getPaddingRight(); 6060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.bottom = mPreviewImage.getPaddingBottom(); 6070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 608e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette if (mOverlayPosition == OVERLAY_FLOATING) { 6090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureFloating(v, margins, out); 610e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette } else { 611e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette measureViewToSide(v, mThumbImage, margins, out); 61220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the bounds for a view that should be laid out against the edge 6170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * of an adjacent view. If no adjacent view is provided, lays out against 6180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the list edge. 6190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 6200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to measure for layout. 6210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param adjacent (Optional) The adjacent view, may be null to align to the 6220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * list edge. 6230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param margins Layout margins to apply to the view. 6240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 6250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) { 6270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 6391ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 640fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 641fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 6420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int maxWidth; 6430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (adjacent == null) { 644fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth; 6450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (mLayoutFromRight) { 6460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = adjacent.getLeft(); 6470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 648fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth - adjacent.getRight(); 6490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 65020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int adjMaxWidth = maxWidth - marginLeft - marginRight; 6520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 6530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 6540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.measure(widthMeasureSpec, heightMeasureSpec); 6550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align to the left or right. 6578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int width = Math.min(adjMaxWidth, view.getMeasuredWidth()); 6580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left; 6590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right; 6600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 661fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette right = (adjacent == null ? container.right : adjacent.getLeft()) - marginRight; 6620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = right - width; 6630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 664fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette left = (adjacent == null ? container.left : adjacent.getRight()) + marginLeft; 6650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = left + width; 6660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 66720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Don't adjust the vertical position. 6690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = marginTop; 6700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + view.getMeasuredHeight(); 6710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 673af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 6740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureFloating(View preview, Rect margins, Rect out) { 6750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 687568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 688fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 689fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 690fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int adjMaxWidth = containerWidth - marginLeft - marginRight; 6910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 6920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 6930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette preview.measure(widthMeasureSpec, heightMeasureSpec); 6940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align at the vertical center, 10% from the top. 696fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerHeight = container.height(); 6970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = preview.getMeasuredWidth(); 698fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = containerHeight / 10 + marginTop + container.top; 6990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + preview.getMeasuredHeight(); 700fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = (containerWidth - width) / 2 + container.left; 7010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + width; 7020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 704e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 70526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** 70626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette * Updates the container rectangle used for layout. 70726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette */ 708fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private void updateContainerRect() { 709fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final AbsListView list = mList; 71026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette list.resolvePadding(); 71126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 712fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 713fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left = 0; 714fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top = 0; 715fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right = list.getWidth(); 716fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom = list.getHeight(); 717fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 71826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int scrollbarStyle = mScrollBarStyle; 719fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET 720fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { 721fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left += list.getPaddingLeft(); 722fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top += list.getPaddingTop(); 723fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right -= list.getPaddingRight(); 724fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom -= list.getPaddingBottom(); 72526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 72626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // In inset mode, we need to adjust for padded scrollbar width. 72726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { 72826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int width = getWidth(); 72926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { 73026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.right += width; 73126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } else { 73226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.left -= width; 73326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 73426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 735fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 736fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 737fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 7380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the thumb according to the current scrollbar position. 7400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutThumb() { 7420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 7430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(mThumbImage, null, null, bounds); 7440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mThumbImage, bounds); 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 746e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 748fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * Lays out the track centered on the thumb. Must be called after 749fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * {@link #layoutThumb}. 7500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutTrack() { 7520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View track = mTrackImage; 7530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View thumb = mThumbImage; 754fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 755fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 756fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(containerWidth, MeasureSpec.AT_MOST); 7570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 7580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.measure(widthMeasureSpec, heightMeasureSpec); 7590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackWidth = track.getMeasuredWidth(); 7610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int thumbHalfHeight = thumb == null ? 0 : thumb.getHeight() / 2; 762fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2; 7630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + trackWidth; 764fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top + thumbHalfHeight; 765fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom - thumbHalfHeight; 7660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.layout(left, top, right, bottom); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 768e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setState(int state) { 7700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.removeCallbacks(mDeferHide); 771e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mAlwaysShow && state == STATE_NONE) { 7730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette state = STATE_VISIBLE; 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (state == mState) { 7770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return; 7780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (state) { 7810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_NONE: 7820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToHidden(); 7830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_VISIBLE: 7850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToVisible(); 7860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_DRAGGING: 7886b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(mCurrentSection)) { 7896b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToDragging(); 7906b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 7916b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 7926b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 7930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 79520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 7960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = state; 797e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 7990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 800e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void refreshDrawablePressedState() { 8020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean isPressed = mState == STATE_DRAGGING; 8030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setPressed(isPressed); 8040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setPressed(isPressed); 8050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 806e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows nothing. 8090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToHidden() { 8110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage, 8160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT); 8170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Push the thumb and track outside the list bounds. 8190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth(); 8200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideOut = groupAnimatorOfFloat( 8210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, offset, mThumbImage, mTrackImage) 8220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeOut, slideOut); 8260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 827f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 828f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb and track. 8330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToVisible() { 8350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage) 8400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat( 8420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText) 8430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn); 8490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 850f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 851f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8532c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 8540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb, preview, and track. 8560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToDragging() { 8580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8602c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat( 8630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage) 8640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, slideIn); 8700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 871f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 872f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = true; 8732c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8742c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 875a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette private void postAutoHide() { 876a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.removeCallbacks(mDeferHide); 877a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.postDelayed(mDeferHide, FADE_TIMEOUT); 878a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 879a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 8800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 881b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 8820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 8870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 8880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mFirstVisibleItem != firstVisibleItem) { 8940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mFirstVisibleItem = firstVisibleItem; 895d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 8960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Show the thumb, if necessary, and set up auto-fade. 8970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState != STATE_DRAGGING) { 8980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 899a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 9000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 901d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 902d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 903d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 9040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void getSectionsFromIndexer() { 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 9060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Adapter adapter = mList.getAdapter(); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 9090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount(); 9100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 9140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter) 9150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .getAdapter(); 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 9184f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (adapter instanceof SectionIndexer) { 9224f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSectionIndexer = (SectionIndexer) adapter; 9240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = mSectionIndexer.getSections(); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9264f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = null; 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 931b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell public void onSectionsChanged() { 932b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell mListAdapter = null; 933b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell } 934b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell 9350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Scrolls to a specific position within the section 9370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position 9380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void scrollTo(float position) { 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 9410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int count = mList.getCount(); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 9440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int sectionCount = sections == null ? 0 : sections.length; 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 9460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (sections != null && sectionCount > 1) { 9470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int exactSection = MathUtils.constrain( 9480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette (int) (position * sectionCount), 0, sectionCount - 1); 9490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetSection = exactSection; 9500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetIndex = mSectionIndexer.getPositionForSection(targetSection); 9510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 9520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 9600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevIndex = targetIndex; 9610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevSection = targetSection; 9620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int nextSection = targetSection + 1; 9630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 9650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetSection < sectionCount - 1) { 9660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1); 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 968e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 9700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (nextIndex == targetIndex) { 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 9720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (targetSection > 0) { 9730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetSection--; 9740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevIndex = mSectionIndexer.getPositionForSection(targetSection); 9750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevIndex != targetIndex) { 9760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevSection = targetSection; 9770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 978b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 9790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (targetSection == 0) { 980b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 981b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 982b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 983b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 984b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 989e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // unique. For instance, if there is no P, then request for P's 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 991e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // sure that there is really a Q at Q's position. If not, move 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 9940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (nextNextSection < sectionCount && 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 10010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // currently visible section. This could be equal to or greater than 10020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // (1 / nSections). If the target position is near the previous 10030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // position, snap to the previous position. 10040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float prevPosition = (float) prevSection / sectionCount; 10050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float nextPosition = (float) nextSection / sectionCount; 10060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count; 10070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevSection == exactSection && position - prevPosition < snapThreshold) { 10080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex; 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition) 10110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette / (nextPosition - prevPosition)); 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Clamp to valid positions. 10150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = MathUtils.constrain(targetIndex, 0, count - 1); 1016e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListView expList = (ExpandableListView) mList; 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)), 10210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0); 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(targetIndex + mHeaderCount); 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int index = MathUtils.constrain((int) (position * count), 0, count - 1); 10297ee1ff1450a3ff83b6b8663bd7f44dc6f30775afAdam Powell 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0); 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(index + mHeaderCount); 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10436b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (mCurrentSection != sectionIndex) { 10446b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mCurrentSection = sectionIndex; 10456b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1046f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final boolean hasPreview = transitionPreviewLayout(sectionIndex); 1047f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (!mShowingPreview && hasPreview) { 10480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToDragging(); 1049f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } else if (mShowingPreview && !hasPreview) { 10506b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 10510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 10566b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * Transitions the preview text to a new section. Handles animation, 10576b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * measurement, and layout. If the new preview text is empty, returns false. 10580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 10596b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @param sectionIndex The section index to which the preview should 10606b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * transition. 10616b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @return False if the new preview text is empty. 10620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 10636b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette private boolean transitionPreviewLayout(int sectionIndex) { 10646b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object[] sections = mSections; 10656b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette String text = null; 10666b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) { 10676b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object section = sections[sectionIndex]; 10686b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section != null) { 10696b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette text = section.toString(); 10706b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10716b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10726b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 10748636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View preview = mPreviewImage; 10750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView showing; 10760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView target; 10770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mShowingPrimary) { 10780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mPrimaryText; 10790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mSecondaryText; 10800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 10810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mSecondaryText; 10820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mPrimaryText; 10830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Set and layout target immediately. 10860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setText(text); 10870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(target, bounds); 10880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(target, bounds); 10890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewAnimation != null) { 10910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.cancel(); 10920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Cross-fade preview text. 10950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE); 10960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE); 10970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette hideShowing.addListener(mSwitchPrimaryListener); 10980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding and animate bounds, if necessary. 11008636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.left -= preview.getPaddingLeft(); 11018636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.top -= preview.getPaddingTop(); 11028636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.right += preview.getPaddingRight(); 11038636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.bottom += preview.getPaddingBottom(); 11040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator resizePreview = animateBounds(preview, bounds); 11050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette resizePreview.setDuration(DURATION_RESIZE); 11060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation = new AnimatorSet(); 11080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget); 11090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(resizePreview); 11100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // The current preview size is unaffected by hidden or showing. It's 11120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // used to set starting scales for things that need to be scaled down. 11130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewWidth = preview.getWidth() - preview.getPaddingLeft() 11140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette - preview.getPaddingRight(); 11150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If target is too large, shrink it immediately to fit and expand to 11170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // target size. Otherwise, start at target size. 11180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int targetWidth = target.getWidth(); 11190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetWidth > previewWidth) { 11200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX((float) previewWidth / targetWidth); 11210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE); 11220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 11240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX(1f); 11250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If showing is larger than target, shrink to target size. 11280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int showingWidth = showing.getWidth(); 11290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (showingWidth > targetWidth) { 11300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float scale = (float) targetWidth / showingWidth; 11310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE); 11320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.start(); 11366b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1137f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return !TextUtils.isEmpty(text); 11380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Positions the thumb and preview widgets. 11420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 11430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position The position, between 0 and 1, along the track at which 11440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * to place the thumb. 11450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setThumbPos(float position) { 1147fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 1148fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top; 1149fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom; 1150fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 11518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View trackImage = mTrackImage; 11528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View thumbImage = mThumbImage; 1153fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1154fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 11550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 11560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 11570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbMiddle = position * range + offset; 1158fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2); 11590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View previewImage = mPreviewImage; 1161fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float previewHalfHeight = previewImage.getHeight() / 2f; 1162e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette final float previewPos; 1163e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette switch (mOverlayPosition) { 1164e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_AT_THUMB: 1165e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = thumbMiddle; 1166e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1167e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_ABOVE_THUMB: 1168e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = thumbMiddle - previewHalfHeight; 1169e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1170e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_FLOATING: 1171e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette default: 1172e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = 0; 1173e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1174e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette } 1175e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette 1176e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette // Center the preview on the thumb, constrained to the list bounds. 11770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float minP = top + previewHalfHeight; 11780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float maxP = bottom - previewHalfHeight; 11795db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell final float previewMiddle = MathUtils.constrain(previewPos, minP, maxP); 11800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewTop = previewMiddle - previewHalfHeight; 1181fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette previewImage.setTranslationY(previewTop); 11820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText.setTranslationY(previewTop); 11840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText.setTranslationY(previewTop); 11850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromMotionEvent(float y) { 11888636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View trackImage = mTrackImage; 1189fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1190fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 11910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 11920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 11930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the list is the same height as the thumbnail or shorter, 11950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // effectively disable scrolling. 11960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (range <= 0) { 11970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return 0f; 11980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return MathUtils.constrain((y - offset) / range, 0f, 1f); 12010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1203827015edb3037cc44c5133188684da0ec56f4027Alan Viverette /** 1204827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * Calculates the thumb position based on the visible items. 1205827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * 1206827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param firstVisibleItem First visible item, >= 0. 1207827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param visibleItemCount Number of visible items, >= 0. 1208827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param totalItemCount Total number of items, >= 0. 1209827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @return 1210827015edb3037cc44c5133188684da0ec56f4027Alan Viverette */ 12110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromItemCount( 12120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int firstVisibleItem, int visibleItemCount, int totalItemCount) { 1213827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final SectionIndexer sectionIndexer = mSectionIndexer; 1214827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (sectionIndexer == null || mListAdapter == null) { 121532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell getSectionsFromIndexer(); 121632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 12170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1218827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (visibleItemCount == 0 || totalItemCount == 0) { 1219827015edb3037cc44c5133188684da0ec56f4027Alan Viverette // No items are visible. 1220827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return 0; 1221827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } 1222827015edb3037cc44c5133188684da0ec56f4027Alan Viverette 1223827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final boolean hasSections = sectionIndexer != null && mSections != null 12240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette && mSections.length > 0; 12250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (!hasSections || !mMatchDragPosition) { 1226827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (visibleItemCount == totalItemCount) { 1227827015edb3037cc44c5133188684da0ec56f4027Alan Viverette // All items are visible. 1228827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return 0; 1229827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } else { 1230827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return (float) firstVisibleItem / (totalItemCount - visibleItemCount); 1231827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } 123232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 1233827015edb3037cc44c5133188684da0ec56f4027Alan Viverette 12346b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Ignore headers. 12350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette firstVisibleItem -= mHeaderCount; 123632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell if (firstVisibleItem < 0) { 123732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell return 0; 123832c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 12390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette totalItemCount -= mHeaderCount; 124032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 12416b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Hidden portion of the first visible row. 12426b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final View child = mList.getChildAt(0); 12436b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float incrementalPos; 12446b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (child == null || child.getHeight() == 0) { 12456b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = 0; 12466b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12476b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight(); 12486b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 12496b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 12506b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Number of rows in this section. 1251827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final int section = sectionIndexer.getSectionForPosition(firstVisibleItem); 1252827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final int sectionPos = sectionIndexer.getPositionForSection(section); 1253f49971ec06e65ee2a0f0fd48a615b89c677086e7Adam Powell final int sectionCount = mSections.length; 12546b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int positionsInSection; 12556b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section < sectionCount - 1) { 1256414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru final int nextSectionPos; 1257414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru if (section + 1 < sectionCount) { 1258827015edb3037cc44c5133188684da0ec56f4027Alan Viverette nextSectionPos = sectionIndexer.getPositionForSection(section + 1); 1259414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } else { 1260414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = totalItemCount - 1; 1261414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } 12626b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = nextSectionPos - sectionPos; 12636b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12646b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = totalItemCount - sectionPos; 12656b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 12666b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 12676b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Position within this section. 12686b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float posWithinSection; 12696b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (positionsInSection == 0) { 12706b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = 0; 12716b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12726b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = (firstVisibleItem + incrementalPos - sectionPos) 12736b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette / positionsInSection; 12746b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 127532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 1276f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette float result = (section + posWithinSection) / sectionCount; 1277f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1278f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // Fake out the scroll bar for the last item. Since the section indexer 1279f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // won't ever actually move the list in this end space, make scrolling 1280f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // across the last item account for whatever space is remaining. 1281f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (firstVisibleItem > 0 && firstVisibleItem + visibleItemCount == totalItemCount) { 1282f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final View lastChild = mList.getChildAt(visibleItemCount - 1); 128340c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int bottomPadding = mList.getPaddingBottom(); 128440c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int maxSize; 128540c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int currentVisibleSize; 128640c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar if (mList.getClipToPadding()) { 128740c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar maxSize = lastChild.getHeight(); 128840c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar currentVisibleSize = mList.getHeight() - bottomPadding - lastChild.getTop(); 128940c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } else { 129040c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar maxSize = lastChild.getHeight() + bottomPadding; 129140c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar currentVisibleSize = mList.getHeight() - lastChild.getTop(); 129240c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } 129340c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar if (currentVisibleSize > 0 && maxSize > 0) { 129440c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar result += (1 - result) * ((float) currentVisibleSize / maxSize ); 129540c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } 1296f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } 1297f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1298f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return result; 129932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 130032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 13010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels an ongoing fling event by injecting a 13030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link MotionEvent#ACTION_CANCEL} into the host view. 13040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 13060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final MotionEvent cancelFling = MotionEvent.obtain( 13070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1311e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels a pending drag. 13140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 13150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #startPendingDrag() 13160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void cancelPendingDrag() { 13184cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 1319af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1320af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Delays dragging until after the framework has determined that the user is 13230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * scrolling, rather than tapping. 13240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void startPendingDrag() { 13264cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = SystemClock.uptimeMillis() + TAP_TIMEOUT; 1327af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1328af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void beginDrag() { 13304cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 13314cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 1332af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 13330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1334af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1335af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1336af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1338af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1339af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1340af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1341af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1342af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1343af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1344af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1345af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onInterceptTouchEvent(MotionEvent ev) { 1347b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1348447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1349447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1350447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1351af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell switch (ev.getActionMasked()) { 1352af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_DOWN: 13530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(ev.getX(), ev.getY())) { 13540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the parent has requested that its children delay 13550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // pressed state (e.g. is a scrolling container) then we 13560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // need to allow the parent time to decide whether it wants 13570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // to intercept events. If it does, we will receive a CANCEL 13580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // event. 1359b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!mList.isInScrollingContainer()) { 1360b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette beginDrag(); 1361b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return true; 1362af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1364b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mInitialTouchY = ev.getY(); 1365b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette startPendingDrag(); 1366b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 1367b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette break; 1368b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette case MotionEvent.ACTION_MOVE: 1369b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isPointInside(ev.getX(), ev.getY())) { 1370b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette cancelPendingDrag(); 13714cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette } else if (mPendingDrag >= 0 && mPendingDrag <= SystemClock.uptimeMillis()) { 13724cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 13734cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 13744cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette final float pos = getPosFromMotionEvent(mInitialTouchY); 13754cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette scrollTo(pos); 13764cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 13774cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette return onTouchEvent(ev); 1378af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1379af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 1380af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_UP: 1381af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_CANCEL: 1382af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1383af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1389a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette public boolean onInterceptHoverEvent(MotionEvent ev) { 1390b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1391a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1392a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1393a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1394a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette final int actionMasked = ev.getActionMasked(); 1395a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER 1396a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE 1397a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette && isPointInside(ev.getX(), ev.getY())) { 1398a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette setState(STATE_VISIBLE); 1399a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 1400a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1401a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1402a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1403a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1404a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 14050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onTouchEvent(MotionEvent me) { 1406b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1407447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1408447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1409447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 14100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (me.getActionMasked()) { 14110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_UP: { 14124cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0) { 14130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Allow a tap to scroll. 14140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 14170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 14180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 14190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Will hit the STATE_DRAGGING check below 1421d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 14220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 14240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList != null) { 14250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // ViewGroup does the right thing already, but there might 14260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // be other classes that don't properly reset on touch-up, 14270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // so do this explicitly just in case. 14280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.requestDisallowInterceptTouchEvent(false); 14290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 14300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 1433a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 14340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 143620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 14370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 143820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 14390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_MOVE: { 14404cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0 && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) { 14414cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 1442af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1443af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell // Will hit the STATE_DRAGGING check below 1444af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 14450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 14470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // TODO: Ignore jitter. 14480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 14490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 14500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the previous scrollTo is still pending 14520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mScrollCompleted) { 14530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 14540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 14590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_CANCEL: { 14610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 14620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1467d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 14680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns whether a coordinate is inside the scroller's activation area. If 14700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * there is a track image, touching anywhere within the thumb-width of the 14710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * track activates scrolling. Otherwise, the user has to touch inside thumb 14720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * itself. 14730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 14740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param x The x-coordinate. 14750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param y The y-coordinate. 14760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the coordinate is inside the scroller's activation area. 14770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInside(float x, float y) { 14798636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette return isPointInsideX(x) && (mTrackDrawable != null || isPointInsideY(y)); 14800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideX(float x) { 14837d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float offset = mThumbImage.getTranslationX(); 14847d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float left = mThumbImage.getLeft() + offset; 14857d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float right = mThumbImage.getRight() + offset; 14867d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 14877d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette // Apply the minimum touch target size. 14887d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float targetSizeDiff = mMinimumTouchTarget - (right - left); 14897d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float adjust = targetSizeDiff > 0 ? targetSizeDiff : 0; 14907d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 14910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 14927d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return x >= mThumbImage.getLeft() - adjust; 14930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 14947d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return x <= mThumbImage.getRight() + adjust; 14950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideY(float y) { 1499d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float offset = mThumbImage.getTranslationY(); 1500d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float top = mThumbImage.getTop() + offset; 1501d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float bottom = mThumbImage.getBottom() + offset; 15027d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15037d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette // Apply the minimum touch target size. 15047d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float targetSizeDiff = mMinimumTouchTarget - (bottom - top); 15057d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float adjust = targetSizeDiff > 0 ? targetSizeDiff / 2 : 0; 15067d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15077d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return y >= (top - adjust) && y <= (bottom + adjust); 15080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Constructs an animator for the specified property on a group of views. 15120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for 15130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * implementation details. 15140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 15150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param property The property being animated. 15160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param value The value to which that property should animate. 15170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param views The target views to animate. 15180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return An animator for all the specified views. 15190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator groupAnimatorOfFloat( 15210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Property<View, Float> property, float value, View... views) { 15220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet animSet = new AnimatorSet(); 15230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet.Builder builder = null; 15240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette for (int i = views.length - 1; i >= 0; i--) { 15260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator anim = ObjectAnimator.ofFloat(views[i], property, value); 15270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (builder == null) { 15280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder = animSet.play(anim); 15290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 15300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(anim); 15310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 153220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 153320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 15340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return animSet; 153582f3495b146b267f3786997752cef25310176349Romain Guy } 153682f3495b146b267f3786997752cef25310176349Romain Guy 15370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's scaleX value. 15390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateScaleX(View v, float target) { 15410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.SCALE_X, target); 15420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1543e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's alpha value. 15460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateAlpha(View v, float alpha) { 15480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.ALPHA, alpha); 15490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1550e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>left</code> functionality handled by the 15530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setLeft(int)} and {@link View#getLeft()} methods. 15540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> LEFT = new IntProperty<View>("left") { 15560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setLeft(value); 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1560e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getLeft(); 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 1566e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>top</code> functionality handled by the 15690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setTop(int)} and {@link View#getTop()} methods. 15700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> TOP = new IntProperty<View>("top") { 1572e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 15730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setTop(value); 15750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1576e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getTop(); 15800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 15820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>right</code> functionality handled by the 15850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setRight(int)} and {@link View#getRight()} methods. 15860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> RIGHT = new IntProperty<View>("right") { 15880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setRight(value); 15910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getRight(); 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 15980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>bottom</code> functionality handled by the 16010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setBottom(int)} and {@link View#getBottom()} methods. 16020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") { 16040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 16060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setBottom(value); 16070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 16110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getBottom(); 16120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 16140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's bounds. 16170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateBounds(View v, Rect bounds) { 16190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left); 16200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top); 16210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right); 16220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom); 16230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom); 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1626