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; 25417ee5ba89f7e0fe5efd34fce74bf1ee5923d976Tor Norbyeimport android.annotation.StyleRes; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ColorStateList; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 2920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.graphics.Rect; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.os.Build; 324cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viveretteimport android.os.SystemClock; 33f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viveretteimport android.text.TextUtils; 340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.text.TextUtils.TruncateAt; 350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.IntProperty; 360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.MathUtils; 370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.Property; 387b63063625467baff1db048e84c5781408a5c86dAlan Viveretteimport android.util.TypedValue; 390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.Gravity; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 4111372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheevimport android.view.PointerIcon; 4220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.view.View; 430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.View.MeasureSpec; 44af5280cc71e155758c2f6625eb999cabb37e937fAdam Powellimport android.view.ViewConfiguration; 450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroup.LayoutParams; 460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroupOverlay; 47d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 488636ace69640566768f89c2d92d2851ff064a2e9Alan Viveretteimport android.widget.ImageView.ScaleType; 490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 50e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viveretteimport com.android.internal.R; 51e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-out animation. */ 570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_OUT = 300; 580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-in animation. */ 600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_IN = 150; 610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition cross-fade animation. */ 630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_CROSS_FADE = 50; 640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition resize animation. */ 660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_RESIZE = 100; 670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Inactivity timeout before fading controls. */ 690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long FADE_TIMEOUT = 1500; 70e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Minimum number of pages to justify showing a fast scroll thumb. */ 720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int MIN_PAGES = 4; 730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview not showing. */ 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 7620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb visible and moving along with the scrollbar. */ 780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_VISIBLE = 1; 790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview being dragged by user. */ 810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_DRAGGING = 2; 8220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Positions for preview image and text. 8420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_FLOATING = 0; 8520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_AT_THUMB = 1; 86e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette private static final int OVERLAY_ABOVE_THUMB = 2; 87e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 88e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette // Positions for thumb in relation to track. 89e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private static final int THUMB_POSITION_MIDPOINT = 0; 90e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private static final int THUMB_POSITION_INSIDE = 1; 91e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Indices for mPreviewResId. 930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_LEFT = 0; 940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_RIGHT = 1; 950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Delay before considering a tap in the thumb area to be a drag. */ 970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempBounds = new Rect(); 1000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempMargins = new Rect(); 101fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private final Rect mContainerRect = new Rect(); 10220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AbsListView mList; 1040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ViewGroupOverlay mOverlay; 1050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mPrimaryText; 1060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mSecondaryText; 1070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mThumbImage; 1080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mTrackImage; 1098636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private final View mPreviewImage; 1100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Preview image resource IDs for left- and right-aligned layouts. See 1120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}. 1130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int[] mPreviewResId = new int[2]; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1167d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette /** The minimum touch target size in pixels. */ 1177d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette private final int mMinimumTouchTarget; 1187d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 1190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Padding in pixels around the preview text. Applied as layout margins to 1210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the preview text and padding to the preview image. 1220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1238636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewPadding; 1248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1258636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinWidth; 1268636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinHeight; 1278636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinWidth; 1288636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinHeight; 1298636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1308636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text size. Used only if text appearance is not set. */ 1318636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private float mTextSize; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text color. Used only if text appearance is not set. */ 1348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private ColorStateList mTextColor; 1358636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mThumbDrawable; 1378636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mTrackDrawable; 1388636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mTextAppearance; 139e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private int mThumbPosition; 140e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 141e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette // Used to convert between y-coordinate and thumb position within track. 142e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private float mThumbOffset; 143e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private float mThumbRange; 1440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Total width of decorations. */ 1468636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mWidth; 14726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing decoration transition animations. */ 1490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mDecorAnimation; 1500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing preview text transition animations. */ 1520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mPreviewAnimation; 1530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the primary text is showing. */ 1550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mShowingPrimary; 1560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether we're waiting for completion of scrollTo(). */ 1580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mScrollCompleted; 1590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The position of the first visible item in the list. */ 1610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mFirstVisibleItem; 1620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of headers at the top of the view. */ 1640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mHeaderCount; 1650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The index of the current section. */ 1670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mCurrentSection = -1; 1680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** The current scrollbar position. */ 17026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollbarPosition = -1; 17126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the list is long enough to need a fast scroller. */ 1734df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 174e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private Object[] mSections; 176e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 177fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette /** Whether this view is currently performing layout. */ 178fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private boolean mUpdatingLayout; 179fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 1800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Current decoration state, one of: 1820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_NONE}, nothing visible 1840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_VISIBLE}, showing track and thumb 1850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_DRAGGING}, visible and showing preview 1860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 189e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 190f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette /** Whether the preview image is visible. */ 191f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette private boolean mShowingPreview; 192f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1934f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette private Adapter mListAdapter; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether decorations should be laid out from right to left. */ 1970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mLayoutFromRight; 19820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 199447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** Whether the fast scroller is enabled. */ 200447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette private boolean mEnabled; 201447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 2020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the scrollbar and decorations should always be shown. */ 20320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private boolean mAlwaysShow; 20420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 2050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Position for the preview image and text. One of: 2070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 2080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_FLOATING} 209e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette * <li>{@link #OVERLAY_AT_THUMB} 210e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette * <li>{@link #OVERLAY_ABOVE_THUMB} 2110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 2120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 21320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private int mOverlayPosition; 21420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 21526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Current scrollbar style, including inset and overlay properties. */ 21626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollBarStyle; 21726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether to precisely match the thumb position to the list. */ 219568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell private boolean mMatchDragPosition; 220568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 2210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float mInitialTouchY; 2224cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette private long mPendingDrag = -1; 223af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private int mScaledTouchSlop; 224af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2254b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private int mOldItemCount; 2264b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private int mOldChildCount; 2274b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette 2280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to delay hiding fast scroll decorations. 2300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Runnable mDeferHide = new Runnable() { 2320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void run() { 2340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 2350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to effect a transition from primary to secondary text. 2400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() { 2420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onAnimationEnd(Animator animation) { 2440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mShowingPrimary = !mShowingPrimary; 245af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 246af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell }; 247af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette public FastScroller(AbsListView listView, int styleResId) { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 2504b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldItemCount = listView.getCount(); 2514b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldChildCount = listView.getChildCount(); 2520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 25339bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette final Context context = listView.getContext(); 2540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 2558636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollBarStyle = listView.getScrollBarStyle(); 2568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollCompleted = true; 2588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mState = STATE_VISIBLE; 2598636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mMatchDragPosition = 2608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; 2618636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2628636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage = new ImageView(context); 2638636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setScaleType(ScaleType.FIT_XY); 2648636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage = new ImageView(context); 2658636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setScaleType(ScaleType.FIT_XY); 2668636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage = new View(context); 2678636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setAlpha(0f); 2688636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2698636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText = createPreviewTextView(context); 2708636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText = createPreviewTextView(context); 2718636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2727d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette mMinimumTouchTarget = listView.getResources().getDimensionPixelSize( 2737d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette com.android.internal.R.dimen.fast_scroller_minimum_touch_target); 2747d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 2758636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setStyle(styleResId); 2760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2778636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final ViewGroupOverlay overlay = listView.getOverlay(); 2788636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlay = overlay; 2798636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mTrackImage); 2808636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mThumbImage); 2818636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPreviewImage); 2828636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPrimaryText); 2838636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mSecondaryText); 2840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2858636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette getSectionsFromIndexer(); 2864b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette updateLongList(mOldChildCount, mOldItemCount); 2878636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setScrollbarPosition(listView.getVerticalScrollbarPosition()); 2888636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette postAutoHide(); 2898636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 29026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2918636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private void updateAppearance() { 29226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette int width = 0; 2930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add track to overlay if it has an image. 2958636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setImageDrawable(mTrackDrawable); 2968636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTrackDrawable != null) { 2978636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mTrackDrawable.getIntrinsicWidth()); 2980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add thumb to overlay if it has an image. 3018636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setImageDrawable(mThumbDrawable); 3028636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumWidth(mThumbMinWidth); 3038636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumHeight(mThumbMinHeight); 3048636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mThumbDrawable != null) { 3058636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mThumbDrawable.getIntrinsicWidth()); 3060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 3070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3088636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette // Account for minimum thumb width. 3098636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mWidth = Math.max(width, mThumbMinWidth); 3100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3118636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextAppearance != 0) { 312e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mPrimaryText.setTextAppearance(mTextAppearance); 313e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mSecondaryText.setTextAppearance(mTextAppearance); 3148636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3168636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextColor != null) { 3178636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextColor(mTextColor); 3188636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextColor(mTextColor); 3198636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3208636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 3218636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextSize > 0) { 3228636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3238636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 326e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int padding = mPreviewPadding; 327e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette mPrimaryText.setIncludeFontPadding(false); 328e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mPrimaryText.setPadding(padding, padding, padding, padding); 329e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette mSecondaryText.setIncludeFontPadding(false); 330e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mSecondaryText.setPadding(padding, padding, padding, padding); 3310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3328636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette refreshDrawablePressedState(); 3338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 335417ee5ba89f7e0fe5efd34fce74bf1ee5923d976Tor Norbye public void setStyle(@StyleRes int resId) { 3368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final Context context = mList.getContext(); 3378636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final TypedArray ta = context.obtainStyledAttributes(null, 338e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette R.styleable.FastScroll, R.attr.fastScrollStyle, resId); 3398636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int N = ta.getIndexCount(); 3408636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette for (int i = 0; i < N; i++) { 3418636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int index = ta.getIndex(i); 3428636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette switch (index) { 343e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_position: 3448636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlayPosition = ta.getInt(index, OVERLAY_FLOATING); 3458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 346e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_backgroundLeft: 3478636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(index, 0); 3488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 349e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_backgroundRight: 3508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(index, 0); 3518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 352e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_thumbDrawable: 3538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbDrawable = ta.getDrawable(index); 3548636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 355e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_trackDrawable: 3568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackDrawable = ta.getDrawable(index); 3578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 358e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_textAppearance: 3598636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextAppearance = ta.getResourceId(index, 0); 3608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 361e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_textColor: 3628636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextColor = ta.getColorStateList(index); 3638636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 364e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_textSize: 3658636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextSize = ta.getDimensionPixelSize(index, 0); 3668636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 367e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_minWidth: 3688636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinWidth = ta.getDimensionPixelSize(index, 0); 3698636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 370e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_minHeight: 3718636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinHeight = ta.getDimensionPixelSize(index, 0); 3728636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 373e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_thumbMinWidth: 3748636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinWidth = ta.getDimensionPixelSize(index, 0); 3758636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 376e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_thumbMinHeight: 3778636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinHeight = ta.getDimensionPixelSize(index, 0); 3788636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 379e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_padding: 3808636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewPadding = ta.getDimensionPixelSize(index, 0); 3818636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 382e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette case R.styleable.FastScroll_thumbPosition: 383e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mThumbPosition = ta.getInt(index, THUMB_POSITION_MIDPOINT); 384e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette break; 3858636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3868636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 38786c94cadddf4de58487825b845c38b045159114cferro_chang ta.recycle(); 3880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3898636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette updateAppearance(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 393447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * Removes this FastScroller overlay from the host view. 394447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 395447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void remove() { 396447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mTrackImage); 397447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mThumbImage); 398447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPreviewImage); 399447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPrimaryText); 400447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mSecondaryText); 401447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 402447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 403447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 404447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @param enabled Whether the fast scroll thumb is enabled. 405447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 406447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void setEnabled(boolean enabled) { 407b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mEnabled != enabled) { 408b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mEnabled = enabled; 409447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 4108ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(true); 411447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 412447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 413447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 414447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 415447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @return Whether the fast scroll thumb is enabled. 416447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 417447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public boolean isEnabled() { 418b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return mEnabled && (mLongList || mAlwaysShow); 419447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 420447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 421447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 4220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param alwaysShow Whether the fast scroll thumb should always be shown 4230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 42420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setAlwaysShow(boolean alwaysShow) { 425b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mAlwaysShow != alwaysShow) { 426b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mAlwaysShow = alwaysShow; 4270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4288ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 42920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 43020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 43120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the fast scroll thumb will always be shown 4340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #setAlwaysShow(boolean) 4350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 43620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public boolean isAlwaysShowEnabled() { 43720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell return mAlwaysShow; 43820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 43920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 440b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette /** 441b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette * Called when one of the variables affecting enabled state changes. 4428ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * 4438ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * @param peekIfEnabled whether the thumb should peek, if enabled 444b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette */ 4458ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette private void onStateDependencyChanged(boolean peekIfEnabled) { 446b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isEnabled()) { 447b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isAlwaysShowEnabled()) { 448b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette setState(STATE_VISIBLE); 449b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else if (mState == STATE_VISIBLE) { 450b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette postAutoHide(); 4518ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette } else if (peekIfEnabled) { 4528ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette setState(STATE_VISIBLE); 4538ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette postAutoHide(); 454b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 455b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else { 456b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette stop(); 457b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 458b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 459b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mList.resolvePadding(); 460b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 461b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 46226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void setScrollBarStyle(int style) { 46326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollBarStyle != style) { 46426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollBarStyle = style; 46526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 46626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 46726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 46826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 46926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 4700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Immediately transitions the fast scroller decorations to a hidden state. 4720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void stop() { 4740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 4750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 47620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 47720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setScrollbarPosition(int position) { 478c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio if (position == View.SCROLLBAR_POSITION_DEFAULT) { 479c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio position = mList.isLayoutRtl() ? 480c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; 481c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio } 4820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 48326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition != position) { 48426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollbarPosition = position; 48526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; 4860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 48726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; 48826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setBackgroundResource(previewResId); 4890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 490e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette // Propagate padding to text min width/height. 491e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int textMinWidth = Math.max(0, mPreviewMinWidth - mPreviewImage.getPaddingLeft() 492e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette - mPreviewImage.getPaddingRight()); 493e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mPrimaryText.setMinimumWidth(textMinWidth); 494e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mSecondaryText.setMinimumWidth(textMinWidth); 495e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 496e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int textMinHeight = Math.max(0, mPreviewMinHeight - mPreviewImage.getPaddingTop() 497e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette - mPreviewImage.getPaddingBottom()); 498e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mPrimaryText.setMinimumHeight(textMinHeight); 499e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mSecondaryText.setMinimumHeight(textMinHeight); 5000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 50126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Requires re-layout. 50226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 50326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 50420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 50520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 50620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public int getWidth() { 50726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette return mWidth; 50820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 50920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 5100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onSizeChanged(int w, int h, int oldw, int oldh) { 5110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 5120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5144b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette public void onItemCountChanged(int childCount, int itemCount) { 5154b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette if (mOldItemCount != itemCount || mOldChildCount != childCount) { 5164b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldItemCount = itemCount; 5174b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette mOldChildCount = childCount; 518b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5194b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final boolean hasMoreItems = itemCount - childCount > 0; 5204b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 5214b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final int firstVisibleItem = mList.getFirstVisiblePosition(); 5224b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, childCount, itemCount)); 5234b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette } 5244b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette 5254b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette updateLongList(childCount, itemCount); 5264b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette } 527b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 528b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5294b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette private void updateLongList(int childCount, int itemCount) { 5304b95cc7ef7f1364799eba3bfa8830515282dcab7Alan Viverette final boolean longList = childCount > 0 && itemCount / childCount >= MIN_PAGES; 531b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mLongList != longList) { 532b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mLongList = longList; 533b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5348ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 535b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 537e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Creates a view into which preview text can be placed. 5400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5418636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private TextView createPreviewTextView(Context context) { 5420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final LayoutParams params = new LayoutParams( 5430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 5440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView textView = new TextView(context); 5450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutParams(params); 5460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setSingleLine(true); 5470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setEllipsize(TruncateAt.MIDDLE); 5480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setGravity(Gravity.CENTER); 5490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setAlpha(0f); 5500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Manually propagate inherited layout direction. 5520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutDirection(mList.getLayoutDirection()); 5530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return textView; 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 556e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures and layouts the scrollbar and decorations. 5590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 56026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void updateLayout() { 561fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // Prevent re-entry when RTL properties change as a side-effect of 562fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // resolving padding. 563fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (mUpdatingLayout) { 564fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette return; 565fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 566fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 567fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = true; 568fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 569fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette updateContainerRect(); 570fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 5710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutThumb(); 5720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutTrack(); 5730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 574e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette updateOffsetAndRange(); 575e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 5760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 5770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mPrimaryText, bounds); 5780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPrimaryText, bounds); 5790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mSecondaryText, bounds); 5800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mSecondaryText, bounds); 5810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewImage != null) { 5830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding. 5840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 5850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 5860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 5870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 5880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPreviewImage, bounds); 58920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 590fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 591fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = false; 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 593e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Layouts a view within the specified bounds and pins the pivot point to 5960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the appropriate edge. 5970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to layout. 5990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param bounds Bounds at which to layout the view. 6000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void applyLayout(View view, Rect bounds) { 6020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom); 6030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0); 6040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 6050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the preview text bounds, taking preview image padding into 6080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * account. This method should only be called after {@link #layoutThumb()} 6090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * and {@link #layoutTrack()} have both been called at least once. 6100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 6110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param v The preview text view to measure. 6120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 6130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measurePreview(View v, Rect out) { 6150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply the preview image's padding as layout margins. 6160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect margins = mTempMargins; 6170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.left = mPreviewImage.getPaddingLeft(); 6180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.top = mPreviewImage.getPaddingTop(); 6190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.right = mPreviewImage.getPaddingRight(); 6200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.bottom = mPreviewImage.getPaddingBottom(); 6210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 622e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette if (mOverlayPosition == OVERLAY_FLOATING) { 6230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureFloating(v, margins, out); 624e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette } else { 625e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette measureViewToSide(v, mThumbImage, margins, out); 62620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the bounds for a view that should be laid out against the edge 6310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * of an adjacent view. If no adjacent view is provided, lays out against 6320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the list edge. 6330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 6340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to measure for layout. 6350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param adjacent (Optional) The adjacent view, may be null to align to the 6360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * list edge. 6370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param margins Layout margins to apply to the view. 6380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 6390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) { 6410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 6531ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 654fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 655fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 6560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int maxWidth; 6570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (adjacent == null) { 658fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth; 6590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (mLayoutFromRight) { 6600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = adjacent.getLeft(); 6610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 662fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth - adjacent.getRight(); 6630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 66420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 665de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int adjMaxHeight = Math.max(0, container.height()); 666c98922ba2fa3b35e1395bd68d8525d51af4ac11fAlan Viverette final int adjMaxWidth = Math.max(0, maxWidth - marginLeft - marginRight); 6670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 668de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( 669de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette adjMaxHeight, MeasureSpec.UNSPECIFIED); 6700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.measure(widthMeasureSpec, heightMeasureSpec); 6710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align to the left or right. 6738636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int width = Math.min(adjMaxWidth, view.getMeasuredWidth()); 6740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left; 6750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right; 6760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 677fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette right = (adjacent == null ? container.right : adjacent.getLeft()) - marginRight; 6780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = right - width; 6790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 680fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette left = (adjacent == null ? container.left : adjacent.getRight()) + marginLeft; 6810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = left + width; 6820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 68320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Don't adjust the vertical position. 6850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = marginTop; 6860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + view.getMeasuredHeight(); 6870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 689af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 6900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureFloating(View preview, Rect margins, Rect out) { 6910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 7000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 7010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 7020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 703568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 704fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 705fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 706de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int adjMaxHeight = Math.max(0, container.height()); 707de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int adjMaxWidth = Math.max(0, containerWidth - marginLeft - marginRight); 7080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 709de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( 710de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette adjMaxHeight, MeasureSpec.UNSPECIFIED); 7110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette preview.measure(widthMeasureSpec, heightMeasureSpec); 7120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align at the vertical center, 10% from the top. 714fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerHeight = container.height(); 7150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = preview.getMeasuredWidth(); 716fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = containerHeight / 10 + marginTop + container.top; 7170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + preview.getMeasuredHeight(); 718fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = (containerWidth - width) / 2 + container.left; 7190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + width; 7200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 722e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 72326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** 72426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette * Updates the container rectangle used for layout. 72526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette */ 726fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private void updateContainerRect() { 727fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final AbsListView list = mList; 72826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette list.resolvePadding(); 72926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 730fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 731fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left = 0; 732fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top = 0; 733fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right = list.getWidth(); 734fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom = list.getHeight(); 735fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 73626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int scrollbarStyle = mScrollBarStyle; 737fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET 738fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { 739fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left += list.getPaddingLeft(); 740fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top += list.getPaddingTop(); 741fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right -= list.getPaddingRight(); 742fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom -= list.getPaddingBottom(); 74326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 74426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // In inset mode, we need to adjust for padded scrollbar width. 74526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { 74626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int width = getWidth(); 74726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { 74826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.right += width; 74926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } else { 75026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.left -= width; 75126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 75226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 753fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 754fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 755fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 7560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the thumb according to the current scrollbar position. 7580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutThumb() { 7600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 7610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(mThumbImage, null, null, bounds); 7620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mThumbImage, bounds); 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 764e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 766fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * Lays out the track centered on the thumb. Must be called after 767fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * {@link #layoutThumb}. 7680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutTrack() { 7700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View track = mTrackImage; 7710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View thumb = mThumbImage; 772fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 773de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int maxWidth = Math.max(0, container.width()); 774de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int maxHeight = Math.max(0, container.height()); 775a0f0494059d0648fb8176da64529ec5cabb5bf51Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); 776de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( 777de14ad55f6b74a96687cd88c208352c30b67cbeeAlan Viverette maxHeight, MeasureSpec.UNSPECIFIED); 7780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.measure(widthMeasureSpec, heightMeasureSpec); 7790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 780e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int top; 781e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int bottom; 782e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette if (mThumbPosition == THUMB_POSITION_INSIDE) { 783e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette top = container.top; 784e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette bottom = container.bottom; 785e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette } else { 786e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int thumbHalfHeight = thumb.getHeight() / 2; 787e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette top = container.top + thumbHalfHeight; 788e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette bottom = container.bottom - thumbHalfHeight; 789e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette } 790e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 7910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackWidth = track.getMeasuredWidth(); 792fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2; 7930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + trackWidth; 7940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.layout(left, top, right, bottom); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 796e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 797e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette /** 798e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette * Updates the offset and range used to convert from absolute y-position to 799e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette * thumb position within the track. 800e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette */ 801e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette private void updateOffsetAndRange() { 802e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final View trackImage = mTrackImage; 803e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final View thumbImage = mThumbImage; 804e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final float min; 805e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final float max; 806e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette if (mThumbPosition == THUMB_POSITION_INSIDE) { 807e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final float halfThumbHeight = thumbImage.getHeight() / 2f; 808e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette min = trackImage.getTop() + halfThumbHeight; 809e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette max = trackImage.getBottom() - halfThumbHeight; 810e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette } else{ 811e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette min = trackImage.getTop(); 812e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette max = trackImage.getBottom(); 813e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette } 814e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 815e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mThumbOffset = min; 816e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mThumbRange = max - min; 817e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette } 818e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette 8190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setState(int state) { 8200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.removeCallbacks(mDeferHide); 821e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mAlwaysShow && state == STATE_NONE) { 8230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette state = STATE_VISIBLE; 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (state == mState) { 8270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return; 8280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (state) { 8310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_NONE: 8320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToHidden(); 8330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 8340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_VISIBLE: 8350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToVisible(); 8360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 8370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_DRAGGING: 8386b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(mCurrentSection)) { 8396b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToDragging(); 8406b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 8416b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 8426b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 8430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 8440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 84520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 8460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = state; 847e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 8490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 850e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void refreshDrawablePressedState() { 8520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean isPressed = mState == STATE_DRAGGING; 8530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setPressed(isPressed); 8540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setPressed(isPressed); 8550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 856e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows nothing. 8590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToHidden() { 8610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage, 8660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT); 8670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Push the thumb and track outside the list bounds. 8690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth(); 8700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideOut = groupAnimatorOfFloat( 8710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, offset, mThumbImage, mTrackImage) 8720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeOut, slideOut); 8760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 877f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 878f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb and track. 8830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToVisible() { 8850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage) 8900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat( 8920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText) 8930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn); 8990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 900f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 901f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9032c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 9040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb, preview, and track. 9060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToDragging() { 9080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 9090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 9102c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 9110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat( 9130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage) 9140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 9150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 9160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 9170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 9190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, slideIn); 9200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 921f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 922f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = true; 9232c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 9242c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 925a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette private void postAutoHide() { 926a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.removeCallbacks(mDeferHide); 927a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.postDelayed(mDeferHide, FADE_TIMEOUT); 928a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 929a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 9300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 931b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 9320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 9370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 9380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mFirstVisibleItem != firstVisibleItem) { 9440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mFirstVisibleItem = firstVisibleItem; 945d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 9460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Show the thumb, if necessary, and set up auto-fade. 9470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState != STATE_DRAGGING) { 9480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 949a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 9500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 951d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 952d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 953d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 9540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void getSectionsFromIndexer() { 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 9560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Adapter adapter = mList.getAdapter(); 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 9590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount(); 9600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 9640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter) 9650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .getAdapter(); 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 9684f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (adapter instanceof SectionIndexer) { 9724f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSectionIndexer = (SectionIndexer) adapter; 9740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = mSectionIndexer.getSections(); 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9764f434c7fb40b75d94e3ca2e4a905808ca34296e5Alan Viverette mListAdapter = adapter; 9770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = null; 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 981b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell public void onSectionsChanged() { 982b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell mListAdapter = null; 983b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell } 984b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell 9850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Scrolls to a specific position within the section 9870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position 9880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void scrollTo(float position) { 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 9910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int count = mList.getCount(); 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 9940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int sectionCount = sections == null ? 0 : sections.length; 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 9960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (sections != null && sectionCount > 1) { 9970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int exactSection = MathUtils.constrain( 9980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette (int) (position * sectionCount), 0, sectionCount - 1); 9990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetSection = exactSection; 10000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetIndex = mSectionIndexer.getPositionForSection(targetSection); 10010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 10020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 10100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevIndex = targetIndex; 10110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevSection = targetSection; 10120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int nextSection = targetSection + 1; 10130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 10150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetSection < sectionCount - 1) { 10160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1); 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1018e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 10200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (nextIndex == targetIndex) { 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 10220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (targetSection > 0) { 10230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetSection--; 10240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevIndex = mSectionIndexer.getPositionForSection(targetSection); 10250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevIndex != targetIndex) { 10260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevSection = targetSection; 10270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 1028b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 10290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (targetSection == 0) { 1030b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 1031b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 1032b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 1033b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 1034b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 1039e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // unique. For instance, if there is no P, then request for P's 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 1041e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // sure that there is really a Q at Q's position. If not, move 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 10440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (nextNextSection < sectionCount && 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 10510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // currently visible section. This could be equal to or greater than 10520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // (1 / nSections). If the target position is near the previous 10530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // position, snap to the previous position. 10540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float prevPosition = (float) prevSection / sectionCount; 10550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float nextPosition = (float) nextSection / sectionCount; 10560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count; 10570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevSection == exactSection && position - prevPosition < snapThreshold) { 10580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex; 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition) 10610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette / (nextPosition - prevPosition)); 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Clamp to valid positions. 10650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = MathUtils.constrain(targetIndex, 0, count - 1); 1066e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListView expList = (ExpandableListView) mList; 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)), 10710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0); 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0); 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(targetIndex + mHeaderCount); 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int index = MathUtils.constrain((int) (position * count), 0, count - 1); 10797ee1ff1450a3ff83b6b8663bd7f44dc6f30775afAdam Powell 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0); 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(index + mHeaderCount); 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10936b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (mCurrentSection != sectionIndex) { 10946b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mCurrentSection = sectionIndex; 10956b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1096f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final boolean hasPreview = transitionPreviewLayout(sectionIndex); 1097f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (!mShowingPreview && hasPreview) { 10980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToDragging(); 1099f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } else if (mShowingPreview && !hasPreview) { 11006b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 11010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * Transitions the preview text to a new section. Handles animation, 11076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * measurement, and layout. If the new preview text is empty, returns false. 11080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 11096b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @param sectionIndex The section index to which the preview should 11106b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * transition. 11116b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @return False if the new preview text is empty. 11120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11136b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette private boolean transitionPreviewLayout(int sectionIndex) { 11146b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object[] sections = mSections; 11156b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette String text = null; 11166b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) { 11176b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object section = sections[sectionIndex]; 11186b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section != null) { 11196b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette text = section.toString(); 11206b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 11216b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 11226b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 11230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 11248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View preview = mPreviewImage; 11250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView showing; 11260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView target; 11270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mShowingPrimary) { 11280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mPrimaryText; 11290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mSecondaryText; 11300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 11310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mSecondaryText; 11320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mPrimaryText; 11330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Set and layout target immediately. 11360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setText(text); 11370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(target, bounds); 11380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(target, bounds); 11390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewAnimation != null) { 11410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.cancel(); 11420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Cross-fade preview text. 11450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE); 11460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE); 11470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette hideShowing.addListener(mSwitchPrimaryListener); 11480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding and animate bounds, if necessary. 11508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.left -= preview.getPaddingLeft(); 11518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.top -= preview.getPaddingTop(); 11528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.right += preview.getPaddingRight(); 11538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.bottom += preview.getPaddingBottom(); 11540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator resizePreview = animateBounds(preview, bounds); 11550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette resizePreview.setDuration(DURATION_RESIZE); 11560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation = new AnimatorSet(); 11580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget); 11590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(resizePreview); 11600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // The current preview size is unaffected by hidden or showing. It's 11620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // used to set starting scales for things that need to be scaled down. 11630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewWidth = preview.getWidth() - preview.getPaddingLeft() 11640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette - preview.getPaddingRight(); 11650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If target is too large, shrink it immediately to fit and expand to 11670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // target size. Otherwise, start at target size. 11680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int targetWidth = target.getWidth(); 11690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetWidth > previewWidth) { 11700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX((float) previewWidth / targetWidth); 11710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE); 11720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 11740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX(1f); 11750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If showing is larger than target, shrink to target size. 11780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int showingWidth = showing.getWidth(); 11790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (showingWidth > targetWidth) { 11800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float scale = (float) targetWidth / showingWidth; 11810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE); 11820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.start(); 11866b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1187f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return !TextUtils.isEmpty(text); 11880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Positions the thumb and preview widgets. 11920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 11930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position The position, between 0 and 1, along the track at which 11940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * to place the thumb. 11950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setThumbPos(float position) { 1197e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final float thumbMiddle = position * mThumbRange + mThumbOffset; 1198e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette mThumbImage.setTranslationY(thumbMiddle - mThumbImage.getHeight() / 2f); 11990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12008636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View previewImage = mPreviewImage; 1201fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float previewHalfHeight = previewImage.getHeight() / 2f; 1202e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette final float previewPos; 1203e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette switch (mOverlayPosition) { 1204e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_AT_THUMB: 1205e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = thumbMiddle; 1206e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1207e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_ABOVE_THUMB: 1208e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = thumbMiddle - previewHalfHeight; 1209e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1210e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette case OVERLAY_FLOATING: 1211e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette default: 1212e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette previewPos = 0; 1213e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette break; 1214e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette } 1215e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette 1216e8311ac850374c5362e8c1e48b81eb4b0211c70bAlan Viverette // Center the preview on the thumb, constrained to the list bounds. 1217e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final Rect container = mContainerRect; 1218e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int top = container.top; 1219e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette final int bottom = container.bottom; 12200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float minP = top + previewHalfHeight; 12210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float maxP = bottom - previewHalfHeight; 12225db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell final float previewMiddle = MathUtils.constrain(previewPos, minP, maxP); 12230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewTop = previewMiddle - previewHalfHeight; 1224fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette previewImage.setTranslationY(previewTop); 12250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText.setTranslationY(previewTop); 12270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText.setTranslationY(previewTop); 12280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromMotionEvent(float y) { 12310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the list is the same height as the thumbnail or shorter, 12320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // effectively disable scrolling. 1233e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette if (mThumbRange <= 0) { 12340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return 0f; 12350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1237e5f1fff6dbf2b0093f8383523c87caeba2875a01Alan Viverette return MathUtils.constrain((y - mThumbOffset) / mThumbRange, 0f, 1f); 12380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1240827015edb3037cc44c5133188684da0ec56f4027Alan Viverette /** 1241827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * Calculates the thumb position based on the visible items. 1242827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * 1243827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param firstVisibleItem First visible item, >= 0. 1244827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param visibleItemCount Number of visible items, >= 0. 1245827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @param totalItemCount Total number of items, >= 0. 1246827015edb3037cc44c5133188684da0ec56f4027Alan Viverette * @return 1247827015edb3037cc44c5133188684da0ec56f4027Alan Viverette */ 12480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromItemCount( 12490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int firstVisibleItem, int visibleItemCount, int totalItemCount) { 1250827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final SectionIndexer sectionIndexer = mSectionIndexer; 1251827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (sectionIndexer == null || mListAdapter == null) { 125232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell getSectionsFromIndexer(); 125332c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 12540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1255827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (visibleItemCount == 0 || totalItemCount == 0) { 1256827015edb3037cc44c5133188684da0ec56f4027Alan Viverette // No items are visible. 1257827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return 0; 1258827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } 1259827015edb3037cc44c5133188684da0ec56f4027Alan Viverette 1260827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final boolean hasSections = sectionIndexer != null && mSections != null 12610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette && mSections.length > 0; 12620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (!hasSections || !mMatchDragPosition) { 1263827015edb3037cc44c5133188684da0ec56f4027Alan Viverette if (visibleItemCount == totalItemCount) { 1264827015edb3037cc44c5133188684da0ec56f4027Alan Viverette // All items are visible. 1265827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return 0; 1266827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } else { 1267827015edb3037cc44c5133188684da0ec56f4027Alan Viverette return (float) firstVisibleItem / (totalItemCount - visibleItemCount); 1268827015edb3037cc44c5133188684da0ec56f4027Alan Viverette } 126932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 1270827015edb3037cc44c5133188684da0ec56f4027Alan Viverette 12716b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Ignore headers. 12720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette firstVisibleItem -= mHeaderCount; 127332c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell if (firstVisibleItem < 0) { 127432c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell return 0; 127532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 12760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette totalItemCount -= mHeaderCount; 127732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 12786b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Hidden portion of the first visible row. 12796b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final View child = mList.getChildAt(0); 12806b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float incrementalPos; 12816b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (child == null || child.getHeight() == 0) { 12826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = 0; 12836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12846b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight(); 12856b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 12866b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 12876b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Number of rows in this section. 1288827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final int section = sectionIndexer.getSectionForPosition(firstVisibleItem); 1289827015edb3037cc44c5133188684da0ec56f4027Alan Viverette final int sectionPos = sectionIndexer.getPositionForSection(section); 1290f49971ec06e65ee2a0f0fd48a615b89c677086e7Adam Powell final int sectionCount = mSections.length; 12916b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int positionsInSection; 12926b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section < sectionCount - 1) { 1293414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru final int nextSectionPos; 1294414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru if (section + 1 < sectionCount) { 1295827015edb3037cc44c5133188684da0ec56f4027Alan Viverette nextSectionPos = sectionIndexer.getPositionForSection(section + 1); 1296414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } else { 1297414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = totalItemCount - 1; 1298414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } 12996b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = nextSectionPos - sectionPos; 13006b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 13016b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = totalItemCount - sectionPos; 13026b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 13036b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 13046b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Position within this section. 13056b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float posWithinSection; 13066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (positionsInSection == 0) { 13076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = 0; 13086b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 13096b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = (firstVisibleItem + incrementalPos - sectionPos) 13106b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette / positionsInSection; 13116b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 131232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 1313f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette float result = (section + posWithinSection) / sectionCount; 1314f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1315f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // Fake out the scroll bar for the last item. Since the section indexer 1316f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // won't ever actually move the list in this end space, make scrolling 1317f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // across the last item account for whatever space is remaining. 1318f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (firstVisibleItem > 0 && firstVisibleItem + visibleItemCount == totalItemCount) { 1319f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final View lastChild = mList.getChildAt(visibleItemCount - 1); 132040c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int bottomPadding = mList.getPaddingBottom(); 132140c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int maxSize; 132240c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar final int currentVisibleSize; 132340c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar if (mList.getClipToPadding()) { 132440c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar maxSize = lastChild.getHeight(); 132540c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar currentVisibleSize = mList.getHeight() - bottomPadding - lastChild.getTop(); 132640c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } else { 132740c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar maxSize = lastChild.getHeight() + bottomPadding; 132840c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar currentVisibleSize = mList.getHeight() - lastChild.getTop(); 132940c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } 133040c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar if (currentVisibleSize > 0 && maxSize > 0) { 133140c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar result += (1 - result) * ((float) currentVisibleSize / maxSize ); 133240c6c555e9497bde30e5b1c1fc9026c784b29fa5Yigit Boyar } 1333f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } 1334f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1335f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return result; 133632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 133732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 13380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels an ongoing fling event by injecting a 13400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link MotionEvent#ACTION_CANCEL} into the host view. 13410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 13430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final MotionEvent cancelFling = MotionEvent.obtain( 13440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1348e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels a pending drag. 13510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 13520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #startPendingDrag() 13530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void cancelPendingDrag() { 13554cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 1356af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1357af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Delays dragging until after the framework has determined that the user is 13600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * scrolling, rather than tapping. 13610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void startPendingDrag() { 13634cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = SystemClock.uptimeMillis() + TAP_TIMEOUT; 1364af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1365af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void beginDrag() { 13674cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 13684cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 1369af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 13700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1371af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1372af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1373af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1375af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1376af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1377af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1378af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1379af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1380af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1381af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1382af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 13830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onInterceptTouchEvent(MotionEvent ev) { 1384b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1385447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1386447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1387447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1388af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell switch (ev.getActionMasked()) { 1389af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_DOWN: 13900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(ev.getX(), ev.getY())) { 13910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the parent has requested that its children delay 13920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // pressed state (e.g. is a scrolling container) then we 13930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // need to allow the parent time to decide whether it wants 13940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // to intercept events. If it does, we will receive a CANCEL 13950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // event. 1396b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!mList.isInScrollingContainer()) { 1397fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette // This will get dispatched to onTouchEvent(). Start 1398fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette // dragging there. 1399b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return true; 1400af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 14010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1402b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mInitialTouchY = ev.getY(); 1403b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette startPendingDrag(); 1404b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 1405b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette break; 1406b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette case MotionEvent.ACTION_MOVE: 1407b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isPointInside(ev.getX(), ev.getY())) { 1408b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette cancelPendingDrag(); 14094cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette } else if (mPendingDrag >= 0 && mPendingDrag <= SystemClock.uptimeMillis()) { 14104cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 14114cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 14124cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette final float pos = getPosFromMotionEvent(mInitialTouchY); 14134cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette scrollTo(pos); 14144cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 1415fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette // This may get dispatched to onTouchEvent(), but it 1416fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette // doesn't really matter since we'll already be in a drag. 14174cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette return onTouchEvent(ev); 1418af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1419af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 1420af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_UP: 1421af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_CANCEL: 1422af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1423af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1429a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette public boolean onInterceptHoverEvent(MotionEvent ev) { 1430b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1431a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1432a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1433a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1434a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette final int actionMasked = ev.getActionMasked(); 1435a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER 1436a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE 1437a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette && isPointInside(ev.getX(), ev.getY())) { 1438a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette setState(STATE_VISIBLE); 1439a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 1440a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1441a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1442a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1443a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1444a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 144511372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 144611372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev if (mState == STATE_DRAGGING || isPointInside(event.getX(), event.getY())) { 144711372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev return PointerIcon.getSystemIcon(mList.getContext(), PointerIcon.TYPE_ARROW); 144811372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev } 144911372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev return null; 145011372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev } 145111372fa466580bac916a330bb51ca8d274c6dca5Vladislav Kaznacheev 14520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onTouchEvent(MotionEvent me) { 1453b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1454447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1455447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1456447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 14570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (me.getActionMasked()) { 1458fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette case MotionEvent.ACTION_DOWN: { 1459fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette if (isPointInside(me.getX(), me.getY())) { 1460fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette if (!mList.isInScrollingContainer()) { 1461fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette beginDrag(); 1462fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette return true; 1463fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette } 1464fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette } 1465fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette } break; 1466fb99ba895e9921f46af38d5fe8c27c88676f7a65Alan Viverette 14670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_UP: { 14684cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0) { 14690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Allow a tap to scroll. 14700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 14730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 14740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 14750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Will hit the STATE_DRAGGING check below 1477d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 14780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 14800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList != null) { 14810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // ViewGroup does the right thing already, but there might 14820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // be other classes that don't properly reset on touch-up, 14830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // so do this explicitly just in case. 14840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.requestDisallowInterceptTouchEvent(false); 14850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 14860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 1489a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 14900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 149220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 14930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 149420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 14950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_MOVE: { 14964cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0 && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) { 14974cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 1498af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1499af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell // Will hit the STATE_DRAGGING check below 1500af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 15010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 15030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // TODO: Ignore jitter. 15040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 15050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 15060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the previous scrollTo is still pending 15080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mScrollCompleted) { 15090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 15100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 15150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_CANCEL: { 15170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 15180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1523d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 15240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns whether a coordinate is inside the scroller's activation area. If 15260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * there is a track image, touching anywhere within the thumb-width of the 15270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * track activates scrolling. Otherwise, the user has to touch inside thumb 15280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * itself. 15290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 15300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param x The x-coordinate. 15310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param y The y-coordinate. 15320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the coordinate is inside the scroller's activation area. 15330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInside(float x, float y) { 15358636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette return isPointInsideX(x) && (mTrackDrawable != null || isPointInsideY(y)); 15360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideX(float x) { 15397d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float offset = mThumbImage.getTranslationX(); 15407d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float left = mThumbImage.getLeft() + offset; 15417d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float right = mThumbImage.getRight() + offset; 15427d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15437d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette // Apply the minimum touch target size. 15447d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float targetSizeDiff = mMinimumTouchTarget - (right - left); 15457d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float adjust = targetSizeDiff > 0 ? targetSizeDiff : 0; 15467d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 15487d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return x >= mThumbImage.getLeft() - adjust; 15490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 15507d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return x <= mThumbImage.getRight() + adjust; 15510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideY(float y) { 1555d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float offset = mThumbImage.getTranslationY(); 1556d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float top = mThumbImage.getTop() + offset; 1557d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float bottom = mThumbImage.getBottom() + offset; 15587d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15597d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette // Apply the minimum touch target size. 15607d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float targetSizeDiff = mMinimumTouchTarget - (bottom - top); 15617d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette final float adjust = targetSizeDiff > 0 ? targetSizeDiff / 2 : 0; 15627d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette 15637d5bcd7990704dd89c596a85429be661607b6dbcAlan Viverette return y >= (top - adjust) && y <= (bottom + adjust); 15640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Constructs an animator for the specified property on a group of views. 15680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for 15690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * implementation details. 15700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 15710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param property The property being animated. 15720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param value The value to which that property should animate. 15730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param views The target views to animate. 15740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return An animator for all the specified views. 15750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator groupAnimatorOfFloat( 15770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Property<View, Float> property, float value, View... views) { 15780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet animSet = new AnimatorSet(); 15790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet.Builder builder = null; 15800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette for (int i = views.length - 1; i >= 0; i--) { 15820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator anim = ObjectAnimator.ofFloat(views[i], property, value); 15830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (builder == null) { 15840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder = animSet.play(anim); 15850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 15860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(anim); 15870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 158820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 158920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 15900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return animSet; 159182f3495b146b267f3786997752cef25310176349Romain Guy } 159282f3495b146b267f3786997752cef25310176349Romain Guy 15930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's scaleX value. 15950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateScaleX(View v, float target) { 15970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.SCALE_X, target); 15980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1599e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 16000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's alpha value. 16020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateAlpha(View v, float alpha) { 16040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.ALPHA, alpha); 16050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1606e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 16070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>left</code> functionality handled by the 16090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setLeft(int)} and {@link View#getLeft()} methods. 16100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> LEFT = new IntProperty<View>("left") { 16120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 16140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setLeft(value); 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1616e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 16170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 16190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getLeft(); 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 1622e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 16230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>top</code> functionality handled by the 16250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setTop(int)} and {@link View#getTop()} methods. 16260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> TOP = new IntProperty<View>("top") { 1628e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 16290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 16300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setTop(value); 16310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1632e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 16330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 16350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getTop(); 16360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 16380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>right</code> functionality handled by the 16410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setRight(int)} and {@link View#getRight()} methods. 16420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> RIGHT = new IntProperty<View>("right") { 16440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 16460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setRight(value); 16470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 16510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getRight(); 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 16540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>bottom</code> functionality handled by the 16570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setBottom(int)} and {@link View#getBottom()} methods. 16580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") { 16600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 16620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setBottom(value); 16630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 16660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 16670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getBottom(); 16680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 16690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 16700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 16710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 16720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's bounds. 16730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 16740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateBounds(View v, Rect bounds) { 16750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left); 16760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top); 16770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right); 16780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom); 16790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom); 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1682