FastScroller.java revision 8ac22b0ada459d8f97787d4f12973894778f03e1
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator; 200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator.AnimatorListener; 210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorListenerAdapter; 220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorSet; 230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.ObjectAnimator; 240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.PropertyValuesHolder; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ColorStateList; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 2820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.graphics.Rect; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.os.Build; 314cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viveretteimport android.os.SystemClock; 32f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viveretteimport android.text.TextUtils; 330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.text.TextUtils.TruncateAt; 340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.IntProperty; 350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.MathUtils; 360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.Property; 377b63063625467baff1db048e84c5781408a5c86dAlan Viveretteimport android.util.TypedValue; 380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.Gravity; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 4020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.view.View; 410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.View.MeasureSpec; 42af5280cc71e155758c2f6625eb999cabb37e937fAdam Powellimport android.view.ViewConfiguration; 430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroup.LayoutParams; 440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroupOverlay; 45d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 468636ace69640566768f89c2d92d2851ff064a2e9Alan Viveretteimport android.widget.ImageView.ScaleType; 470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-out animation. */ 530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_OUT = 300; 540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-in animation. */ 560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_IN = 150; 570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition cross-fade animation. */ 590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_CROSS_FADE = 50; 600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition resize animation. */ 620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_RESIZE = 100; 630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Inactivity timeout before fading controls. */ 650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long FADE_TIMEOUT = 1500; 66e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Minimum number of pages to justify showing a fast scroll thumb. */ 680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int MIN_PAGES = 4; 690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview not showing. */ 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 7220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb visible and moving along with the scrollbar. */ 740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_VISIBLE = 1; 750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview being dragged by user. */ 770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_DRAGGING = 2; 7820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Positions for preview image and text. 8020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_FLOATING = 0; 8120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_AT_THUMB = 1; 82e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Indices for mPreviewResId. 840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_LEFT = 0; 850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_RIGHT = 1; 860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Delay before considering a tap in the thumb area to be a drag. */ 880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempBounds = new Rect(); 910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempMargins = new Rect(); 92fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private final Rect mContainerRect = new Rect(); 9320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AbsListView mList; 950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ViewGroupOverlay mOverlay; 960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mPrimaryText; 970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mSecondaryText; 980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mThumbImage; 990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mTrackImage; 1008636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private final View mPreviewImage; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Preview image resource IDs for left- and right-aligned layouts. See 1040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}. 1050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int[] mPreviewResId = new int[2]; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Padding in pixels around the preview text. Applied as layout margins to 1100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the preview text and padding to the preview image. 1110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1128636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewPadding; 1138636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1148636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinWidth; 1158636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mPreviewMinHeight; 1168636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinWidth; 1178636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mThumbMinHeight; 1188636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1198636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text size. Used only if text appearance is not set. */ 1208636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private float mTextSize; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1228636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette /** Theme-specified text color. Used only if text appearance is not set. */ 1238636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private ColorStateList mTextColor; 1248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 1258636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mThumbDrawable; 1268636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private Drawable mTrackDrawable; 1278636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mTextAppearance; 1280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Total width of decorations. */ 1308636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private int mWidth; 13126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing decoration transition animations. */ 1330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mDecorAnimation; 1340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing preview text transition animations. */ 1360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mPreviewAnimation; 1370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the primary text is showing. */ 1390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mShowingPrimary; 1400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether we're waiting for completion of scrollTo(). */ 1420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mScrollCompleted; 1430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The position of the first visible item in the list. */ 1450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mFirstVisibleItem; 1460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of headers at the top of the view. */ 1480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mHeaderCount; 1490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The index of the current section. */ 1510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mCurrentSection = -1; 1520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** The current scrollbar position. */ 15426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollbarPosition = -1; 15526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 1560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the list is long enough to need a fast scroller. */ 1574df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 158e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private Object[] mSections; 160e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 161fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette /** Whether this view is currently performing layout. */ 162fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private boolean mUpdatingLayout; 163fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 1640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Current decoration state, one of: 1660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_NONE}, nothing visible 1680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_VISIBLE}, showing track and thumb 1690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_DRAGGING}, visible and showing preview 1700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 173e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 174f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette /** Whether the preview image is visible. */ 175f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette private boolean mShowingPreview; 176f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private BaseAdapter mListAdapter; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether decorations should be laid out from right to left. */ 1810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mLayoutFromRight; 18220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 183447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** Whether the fast scroller is enabled. */ 184447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette private boolean mEnabled; 185447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the scrollbar and decorations should always be shown. */ 18720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private boolean mAlwaysShow; 18820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Position for the preview image and text. One of: 1910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_AT_THUMB} 1930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_FLOATING} 1940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 19620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private int mOverlayPosition; 19720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 19826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** Current scrollbar style, including inset and overlay properties. */ 19926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette private int mScrollBarStyle; 20026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether to precisely match the thumb position to the list. */ 202568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell private boolean mMatchDragPosition; 203568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 2040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float mInitialTouchY; 2054cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette private long mPendingDrag = -1; 206af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private int mScaledTouchSlop; 207af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to delay hiding fast scroll decorations. 2100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Runnable mDeferHide = new Runnable() { 2120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void run() { 2140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 2150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to effect a transition from primary to secondary text. 2200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() { 2220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onAnimationEnd(Animator animation) { 2240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mShowingPrimary = !mShowingPrimary; 225af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 226af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell }; 227af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2288636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette public FastScroller(AbsListView listView, int styleResId) { 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 2300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 23139bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette final Context context = listView.getContext(); 2320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 2338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollBarStyle = listView.getScrollBarStyle(); 2348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2358636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mScrollCompleted = true; 2368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mState = STATE_VISIBLE; 2378636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mMatchDragPosition = 2388636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; 2398636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2408636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage = new ImageView(context); 2418636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setScaleType(ScaleType.FIT_XY); 2428636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage = new ImageView(context); 2438636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setScaleType(ScaleType.FIT_XY); 2448636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage = new View(context); 2458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setAlpha(0f); 2468636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2478636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText = createPreviewTextView(context); 2488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText = createPreviewTextView(context); 2498636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 2508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setStyle(styleResId); 2510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final ViewGroupOverlay overlay = listView.getOverlay(); 2538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlay = overlay; 2548636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mTrackImage); 2558636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mThumbImage); 2568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPreviewImage); 2578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mPrimaryText); 2588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette overlay.add(mSecondaryText); 2590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette getSectionsFromIndexer(); 2618636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette updateLongList(listView.getChildCount(), listView.getCount()); 2628636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette setScrollbarPosition(listView.getVerticalScrollbarPosition()); 2638636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette postAutoHide(); 2648636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 26526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2668636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private void updateAppearance() { 2678636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final Context context = mList.getContext(); 26826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette int width = 0; 2690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add track to overlay if it has an image. 2718636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackImage.setImageDrawable(mTrackDrawable); 2728636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTrackDrawable != null) { 2738636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mTrackDrawable.getIntrinsicWidth()); 2740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add thumb to overlay if it has an image. 2778636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setImageDrawable(mThumbDrawable); 2788636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumWidth(mThumbMinWidth); 2798636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbImage.setMinimumHeight(mThumbMinHeight); 2808636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mThumbDrawable != null) { 2818636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette width = Math.max(width, mThumbDrawable.getIntrinsicWidth()); 2820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2848636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette // Account for minimum thumb width. 2858636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mWidth = Math.max(width, mThumbMinWidth); 2860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2878636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setMinimumWidth(mPreviewMinWidth); 2888636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewImage.setMinimumHeight(mPreviewMinHeight); 28926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 2908636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextAppearance != 0) { 2918636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextAppearance(context, mTextAppearance); 2928636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextAppearance(context, mTextAppearance); 2938636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 2940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2958636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextColor != null) { 2968636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextColor(mTextColor); 2978636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextColor(mTextColor); 2988636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 2998636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette 3008636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette if (mTextSize > 0) { 3018636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPrimaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3028636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); 3038636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3058636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int textMinSize = Math.max(0, mPreviewMinHeight); 3066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumWidth(textMinSize); 3076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumHeight(textMinSize); 3086b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumWidth(textMinSize); 3096b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumHeight(textMinSize); 3100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3118636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette refreshDrawablePressedState(); 3128636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3148636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette public void setStyle(int resId) { 3158636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final Context context = mList.getContext(); 3168636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final TypedArray ta = context.obtainStyledAttributes(null, 3178636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette com.android.internal.R.styleable.FastScroll, android.R.attr.fastScrollStyle, resId); 3188636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int N = ta.getIndexCount(); 3198636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette for (int i = 0; i < N; i++) { 3208636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int index = ta.getIndex(i); 3218636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette switch (index) { 3228636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_position: 3238636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mOverlayPosition = ta.getInt(index, OVERLAY_FLOATING); 3248636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3258636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_backgroundLeft: 3268636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(index, 0); 3278636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3288636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_backgroundRight: 3298636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(index, 0); 3308636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3318636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbDrawable: 3328636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbDrawable = ta.getDrawable(index); 3338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_trackDrawable: 3358636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTrackDrawable = ta.getDrawable(index); 3368636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3378636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textAppearance: 3388636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextAppearance = ta.getResourceId(index, 0); 3398636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3408636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textColor: 3418636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextColor = ta.getColorStateList(index); 3428636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3438636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_textSize: 3448636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mTextSize = ta.getDimensionPixelSize(index, 0); 3458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3468636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_minWidth: 3478636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinWidth = ta.getDimensionPixelSize(index, 0); 3488636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3498636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_minHeight: 3508636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewMinHeight = ta.getDimensionPixelSize(index, 0); 3518636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3528636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbMinWidth: 3538636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinWidth = ta.getDimensionPixelSize(index, 0); 3548636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3558636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_thumbMinHeight: 3568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mThumbMinHeight = ta.getDimensionPixelSize(index, 0); 3578636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette case com.android.internal.R.styleable.FastScroll_padding: 3598636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette mPreviewPadding = ta.getDimensionPixelSize(index, 0); 3608636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette break; 3618636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3628636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette } 3630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3648636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette updateAppearance(); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 368447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * Removes this FastScroller overlay from the host view. 369447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 370447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void remove() { 371447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mTrackImage); 372447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mThumbImage); 373447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPreviewImage); 374447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPrimaryText); 375447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mSecondaryText); 376447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 377447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 378447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 379447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @param enabled Whether the fast scroll thumb is enabled. 380447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 381447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void setEnabled(boolean enabled) { 382b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mEnabled != enabled) { 383b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mEnabled = enabled; 384447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 3858ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(true); 386447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 387447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 388447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 389447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 390447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @return Whether the fast scroll thumb is enabled. 391447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 392447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public boolean isEnabled() { 393b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return mEnabled && (mLongList || mAlwaysShow); 394447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 395447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 396447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 3970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param alwaysShow Whether the fast scroll thumb should always be shown 3980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 39920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setAlwaysShow(boolean alwaysShow) { 400b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mAlwaysShow != alwaysShow) { 401b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mAlwaysShow = alwaysShow; 4020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4038ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 40420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 40520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 40620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the fast scroll thumb will always be shown 4090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #setAlwaysShow(boolean) 4100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 41120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public boolean isAlwaysShowEnabled() { 41220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell return mAlwaysShow; 41320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 41420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 415b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette /** 416b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette * Called when one of the variables affecting enabled state changes. 4178ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * 4188ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette * @param peekIfEnabled whether the thumb should peek, if enabled 419b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette */ 4208ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette private void onStateDependencyChanged(boolean peekIfEnabled) { 421b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isEnabled()) { 422b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (isAlwaysShowEnabled()) { 423b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette setState(STATE_VISIBLE); 424b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else if (mState == STATE_VISIBLE) { 425b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette postAutoHide(); 4268ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette } else if (peekIfEnabled) { 4278ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette setState(STATE_VISIBLE); 4288ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette postAutoHide(); 429b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 430b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } else { 431b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette stop(); 432b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 433b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 434b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mList.resolvePadding(); 435b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 436b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 43726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void setScrollBarStyle(int style) { 43826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollBarStyle != style) { 43926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollBarStyle = style; 44026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 44126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 44226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 44326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 44426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 4450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Immediately transitions the fast scroller decorations to a hidden state. 4470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void stop() { 4490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 4500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 45120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 45220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setScrollbarPosition(int position) { 453c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio if (position == View.SCROLLBAR_POSITION_DEFAULT) { 454c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio position = mList.isLayoutRtl() ? 455c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; 456c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio } 4570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 45826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition != position) { 45926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mScrollbarPosition = position; 46026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; 4610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 46226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; 46326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setBackgroundResource(previewResId); 4640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 46526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Add extra padding for text. 46626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Drawable background = mPreviewImage.getBackground(); 46726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (background != null) { 46826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final Rect padding = mTempBounds; 46926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette background.getPadding(padding); 47026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette padding.offset(mPreviewPadding, mPreviewPadding); 47126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); 47226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 4730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 47426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // Requires re-layout. 47526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette updateLayout(); 47626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 47720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 47820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 47920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public int getWidth() { 48026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette return mWidth; 48120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 48220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 4830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onSizeChanged(int w, int h, int oldw, int oldh) { 4840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 4850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 4860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4875db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell public void onItemCountChanged(int totalItemCount) { 4880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int visibleItemCount = mList.getChildCount(); 4890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 4900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 4910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int firstVisibleItem = mList.getFirstVisiblePosition(); 4920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 494b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 495b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette updateLongList(visibleItemCount, totalItemCount); 496b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 497b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 498b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette private void updateLongList(int visibleItemCount, int totalItemCount) { 499b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette final boolean longList = visibleItemCount > 0 500b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette && totalItemCount / visibleItemCount >= MIN_PAGES; 501b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (mLongList != longList) { 502b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mLongList = longList; 503b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette 5048ac22b0ada459d8f97787d4f12973894778f03e1Alan Viverette onStateDependencyChanged(false); 505b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 507e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Creates a view into which preview text can be placed. 5100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5118636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette private TextView createPreviewTextView(Context context) { 5120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final LayoutParams params = new LayoutParams( 5130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 5140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView textView = new TextView(context); 5150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutParams(params); 5160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setSingleLine(true); 5170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setEllipsize(TruncateAt.MIDDLE); 5180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setGravity(Gravity.CENTER); 5190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setAlpha(0f); 5200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Manually propagate inherited layout direction. 5220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutDirection(mList.getLayoutDirection()); 5230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return textView; 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 526e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures and layouts the scrollbar and decorations. 5290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 53026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette public void updateLayout() { 531fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // Prevent re-entry when RTL properties change as a side-effect of 532fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette // resolving padding. 533fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (mUpdatingLayout) { 534fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette return; 535fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 536fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 537fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = true; 538fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 539fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette updateContainerRect(); 540fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 5410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutThumb(); 5420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutTrack(); 5430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 5450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mPrimaryText, bounds); 5460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPrimaryText, bounds); 5470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mSecondaryText, bounds); 5480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mSecondaryText, bounds); 5490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewImage != null) { 5510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding. 5520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 5530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 5540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 5550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 5560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPreviewImage, bounds); 55720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 558fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 559fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette mUpdatingLayout = false; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 561e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Layouts a view within the specified bounds and pins the pivot point to 5640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the appropriate edge. 5650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to layout. 5670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param bounds Bounds at which to layout the view. 5680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void applyLayout(View view, Rect bounds) { 5700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom); 5710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0); 5720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the preview text bounds, taking preview image padding into 5760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * account. This method should only be called after {@link #layoutThumb()} 5770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * and {@link #layoutTrack()} have both been called at least once. 5780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 5790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param v The preview text view to measure. 5800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 5810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measurePreview(View v, Rect out) { 5830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply the preview image's padding as layout margins. 5840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect margins = mTempMargins; 5850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.left = mPreviewImage.getPaddingLeft(); 5860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.top = mPreviewImage.getPaddingTop(); 5870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.right = mPreviewImage.getPaddingRight(); 5880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.bottom = mPreviewImage.getPaddingBottom(); 5890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mOverlayPosition == OVERLAY_AT_THUMB) { 5910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(v, mThumbImage, margins, out); 59220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } else { 5930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureFloating(v, margins, out); 59420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the bounds for a view that should be laid out against the edge 5990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * of an adjacent view. If no adjacent view is provided, lays out against 6000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the list edge. 6010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 6020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to measure for layout. 6030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param adjacent (Optional) The adjacent view, may be null to align to the 6040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * list edge. 6050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param margins Layout margins to apply to the view. 6060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 6070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) { 6090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 6211ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 622fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 623fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 6240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int maxWidth; 6250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (adjacent == null) { 626fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth; 6270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (mLayoutFromRight) { 6280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = adjacent.getLeft(); 6290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 630fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette maxWidth = containerWidth - adjacent.getRight(); 6310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 63220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int adjMaxWidth = maxWidth - marginLeft - marginRight; 6340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 6350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 6360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.measure(widthMeasureSpec, heightMeasureSpec); 6370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align to the left or right. 6398636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final int width = Math.min(adjMaxWidth, view.getMeasuredWidth()); 6400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left; 6410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right; 6420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 643fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette right = (adjacent == null ? container.right : adjacent.getLeft()) - marginRight; 6440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = right - width; 6450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 646fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette left = (adjacent == null ? container.left : adjacent.getRight()) + marginLeft; 6470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = left + width; 6480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 64920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Don't adjust the vertical position. 6510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = marginTop; 6520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + view.getMeasuredHeight(); 6530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 655af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 6560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureFloating(View preview, Rect margins, Rect out) { 6570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 6580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 6590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 6600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 6610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 6620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 6630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 6640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 6650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 6660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 6670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 6680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 669568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 670fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 671fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 672fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int adjMaxWidth = containerWidth - marginLeft - marginRight; 6730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 6740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 6750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette preview.measure(widthMeasureSpec, heightMeasureSpec); 6760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align at the vertical center, 10% from the top. 678fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerHeight = container.height(); 6790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = preview.getMeasuredWidth(); 680fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = containerHeight / 10 + marginTop + container.top; 6810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + preview.getMeasuredHeight(); 682fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = (containerWidth - width) / 2 + container.left; 6830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + width; 6840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 686e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 68726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette /** 68826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette * Updates the container rectangle used for layout. 68926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette */ 690fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette private void updateContainerRect() { 691fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final AbsListView list = mList; 69226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette list.resolvePadding(); 69326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 694fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 695fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left = 0; 696fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top = 0; 697fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right = list.getWidth(); 698fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom = list.getHeight(); 699fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 70026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int scrollbarStyle = mScrollBarStyle; 701fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET 702fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { 703fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.left += list.getPaddingLeft(); 704fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.top += list.getPaddingTop(); 705fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.right -= list.getPaddingRight(); 706fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette container.bottom -= list.getPaddingBottom(); 70726bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette 70826bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette // In inset mode, we need to adjust for padded scrollbar width. 70926bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { 71026bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette final int width = getWidth(); 71126bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { 71226bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.right += width; 71326bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } else { 71426bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette container.left -= width; 71526bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 71626bb253b4001b7d4d876656b0c6bd11b6aab4131Alan Viverette } 717fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 718fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette } 719fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 7200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the thumb according to the current scrollbar position. 7220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutThumb() { 7240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 7250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(mThumbImage, null, null, bounds); 7260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mThumbImage, bounds); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 728e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 730fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * Lays out the track centered on the thumb. Must be called after 731fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette * {@link #layoutThumb}. 7320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutTrack() { 7340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View track = mTrackImage; 7350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View thumb = mThumbImage; 736fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 737fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int containerWidth = container.width(); 738fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(containerWidth, MeasureSpec.AT_MOST); 7390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 7400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.measure(widthMeasureSpec, heightMeasureSpec); 7410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackWidth = track.getMeasuredWidth(); 7430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int thumbHalfHeight = thumb == null ? 0 : thumb.getHeight() / 2; 744fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2; 7450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + trackWidth; 746fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top + thumbHalfHeight; 747fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom - thumbHalfHeight; 7480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.layout(left, top, right, bottom); 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 750e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setState(int state) { 7520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.removeCallbacks(mDeferHide); 753e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mAlwaysShow && state == STATE_NONE) { 7550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette state = STATE_VISIBLE; 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (state == mState) { 7590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return; 7600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (state) { 7630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_NONE: 7640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToHidden(); 7650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_VISIBLE: 7670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToVisible(); 7680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_DRAGGING: 7706b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(mCurrentSection)) { 7716b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToDragging(); 7726b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 7736b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 7746b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 7750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 7760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 77720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 7780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = state; 779e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 7810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 782e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void refreshDrawablePressedState() { 7840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean isPressed = mState == STATE_DRAGGING; 7850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setPressed(isPressed); 7860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setPressed(isPressed); 7870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 788e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 7890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows nothing. 7910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToHidden() { 7930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 7940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage, 7980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT); 7990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Push the thumb and track outside the list bounds. 8010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth(); 8020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideOut = groupAnimatorOfFloat( 8030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, offset, mThumbImage, mTrackImage) 8040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeOut, slideOut); 8080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 809f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 810f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb and track. 8150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToVisible() { 8170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage) 8220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat( 8240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText) 8250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 8260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn); 8310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 832f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 833f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = false; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8352c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 8360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 8370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb, preview, and track. 8380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 8390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToDragging() { 8400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 8410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 8422c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat( 8450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage) 8460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 8470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 8480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 8490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 8510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, slideIn); 8520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 853f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 854f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette mShowingPreview = true; 8552c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 8562c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 857a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette private void postAutoHide() { 858a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.removeCallbacks(mDeferHide); 859a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.postDelayed(mDeferHide, FADE_TIMEOUT); 860a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 861a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 8620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 863b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 8640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 8690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 8700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mFirstVisibleItem != firstVisibleItem) { 8760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mFirstVisibleItem = firstVisibleItem; 877d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 8780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Show the thumb, if necessary, and set up auto-fade. 8790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState != STATE_DRAGGING) { 8800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 881a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 8820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 883d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 884d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 885d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 8860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void getSectionsFromIndexer() { 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 8880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Adapter adapter = mList.getAdapter(); 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 8910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount(); 8920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 8960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter) 8970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .getAdapter(); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (adapter instanceof SectionIndexer) { 9040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 9050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSectionIndexer = (SectionIndexer) adapter; 9060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = mSectionIndexer.getSections(); 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 9090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = null; 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 913b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell public void onSectionsChanged() { 914b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell mListAdapter = null; 915b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell } 916b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell 9170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Scrolls to a specific position within the section 9190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position 9200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void scrollTo(float position) { 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 9230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int count = mList.getCount(); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 9260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int sectionCount = sections == null ? 0 : sections.length; 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 9280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (sections != null && sectionCount > 1) { 9290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int exactSection = MathUtils.constrain( 9300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette (int) (position * sectionCount), 0, sectionCount - 1); 9310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetSection = exactSection; 9320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetIndex = mSectionIndexer.getPositionForSection(targetSection); 9330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 9340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 9420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevIndex = targetIndex; 9430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevSection = targetSection; 9440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int nextSection = targetSection + 1; 9450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 9470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetSection < sectionCount - 1) { 9480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1); 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 950e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 9520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (nextIndex == targetIndex) { 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 9540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (targetSection > 0) { 9550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetSection--; 9560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevIndex = mSectionIndexer.getPositionForSection(targetSection); 9570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevIndex != targetIndex) { 9580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevSection = targetSection; 9590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 960b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 9610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (targetSection == 0) { 962b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 963b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 964b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 965b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 966b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 971e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // unique. For instance, if there is no P, then request for P's 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 973e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // sure that there is really a Q at Q's position. If not, move 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 9760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (nextNextSection < sectionCount && 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 9830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // currently visible section. This could be equal to or greater than 9840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // (1 / nSections). If the target position is near the previous 9850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // position, snap to the previous position. 9860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float prevPosition = (float) prevSection / sectionCount; 9870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float nextPosition = (float) nextSection / sectionCount; 9880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count; 9890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevSection == exactSection && position - prevPosition < snapThreshold) { 9900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex; 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition) 9930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette / (nextPosition - prevPosition)); 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Clamp to valid positions. 9970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = MathUtils.constrain(targetIndex, 0, count - 1); 998e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListView expList = (ExpandableListView) mList; 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)), 10030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0); 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0); 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(targetIndex + mHeaderCount); 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int index = MathUtils.constrain((int) (position * count), 0, count - 1); 10117ee1ff1450a3ff83b6b8663bd7f44dc6f30775afAdam Powell 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 10150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0); 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 10170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0); 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(index + mHeaderCount); 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10256b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (mCurrentSection != sectionIndex) { 10266b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mCurrentSection = sectionIndex; 10276b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1028f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final boolean hasPreview = transitionPreviewLayout(sectionIndex); 1029f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (!mShowingPreview && hasPreview) { 10300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToDragging(); 1031f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } else if (mShowingPreview && !hasPreview) { 10326b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 10330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 10386b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * Transitions the preview text to a new section. Handles animation, 10396b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * measurement, and layout. If the new preview text is empty, returns false. 10400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 10416b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @param sectionIndex The section index to which the preview should 10426b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * transition. 10436b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @return False if the new preview text is empty. 10440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 10456b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette private boolean transitionPreviewLayout(int sectionIndex) { 10466b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object[] sections = mSections; 10476b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette String text = null; 10486b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) { 10496b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object section = sections[sectionIndex]; 10506b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section != null) { 10516b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette text = section.toString(); 10526b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10536b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10546b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 10568636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View preview = mPreviewImage; 10570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView showing; 10580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView target; 10590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mShowingPrimary) { 10600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mPrimaryText; 10610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mSecondaryText; 10620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 10630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mSecondaryText; 10640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mPrimaryText; 10650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Set and layout target immediately. 10680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setText(text); 10690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(target, bounds); 10700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(target, bounds); 10710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewAnimation != null) { 10730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.cancel(); 10740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Cross-fade preview text. 10770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE); 10780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE); 10790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette hideShowing.addListener(mSwitchPrimaryListener); 10800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding and animate bounds, if necessary. 10828636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.left -= preview.getPaddingLeft(); 10838636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.top -= preview.getPaddingTop(); 10848636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.right += preview.getPaddingRight(); 10858636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette bounds.bottom += preview.getPaddingBottom(); 10860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator resizePreview = animateBounds(preview, bounds); 10870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette resizePreview.setDuration(DURATION_RESIZE); 10880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation = new AnimatorSet(); 10900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget); 10910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(resizePreview); 10920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // The current preview size is unaffected by hidden or showing. It's 10940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // used to set starting scales for things that need to be scaled down. 10950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewWidth = preview.getWidth() - preview.getPaddingLeft() 10960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette - preview.getPaddingRight(); 10970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If target is too large, shrink it immediately to fit and expand to 10990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // target size. Otherwise, start at target size. 11000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int targetWidth = target.getWidth(); 11010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetWidth > previewWidth) { 11020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX((float) previewWidth / targetWidth); 11030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE); 11040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 11060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX(1f); 11070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If showing is larger than target, shrink to target size. 11100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int showingWidth = showing.getWidth(); 11110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (showingWidth > targetWidth) { 11120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float scale = (float) targetWidth / showingWidth; 11130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE); 11140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 11150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.start(); 11186b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 1119f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return !TextUtils.isEmpty(text); 11200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Positions the thumb and preview widgets. 11240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 11250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position The position, between 0 and 1, along the track at which 11260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * to place the thumb. 11270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setThumbPos(float position) { 1129fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final Rect container = mContainerRect; 1130fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int top = container.top; 1131fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final int bottom = container.bottom; 1132fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette 11338636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View trackImage = mTrackImage; 11348636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View thumbImage = mThumbImage; 1135fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1136fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 11370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 11380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 11390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbMiddle = position * range + offset; 1140fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2); 11410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11425db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell final float previewPos = mOverlayPosition == OVERLAY_AT_THUMB ? thumbMiddle : 0; 11435db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell 11440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Center the preview on the thumb, constrained to the list bounds. 11458636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View previewImage = mPreviewImage; 1146fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float previewHalfHeight = previewImage.getHeight() / 2f; 11470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float minP = top + previewHalfHeight; 11480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float maxP = bottom - previewHalfHeight; 11495db566f16a1b8f36e84a9be00cde40482d48466bAdam Powell final float previewMiddle = MathUtils.constrain(previewPos, minP, maxP); 11500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewTop = previewMiddle - previewHalfHeight; 1151fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette previewImage.setTranslationY(previewTop); 11520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText.setTranslationY(previewTop); 11540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText.setTranslationY(previewTop); 11550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromMotionEvent(float y) { 11588636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette final View trackImage = mTrackImage; 1159fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float min = trackImage.getTop(); 1160fb66415655c288be2ac2078cd0a5e20c7040266eAlan Viverette final float max = trackImage.getBottom(); 11610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 11620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 11630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the list is the same height as the thumbnail or shorter, 11650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // effectively disable scrolling. 11660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (range <= 0) { 11670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return 0f; 11680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return MathUtils.constrain((y - offset) / range, 0f, 1f); 11710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 11720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromItemCount( 11740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int firstVisibleItem, int visibleItemCount, int totalItemCount) { 117535948b7ed502d3f126acc8f2d61e099fa5deb0c7Adam Powell if (mSectionIndexer == null || mListAdapter == null) { 117632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell getSectionsFromIndexer(); 117732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 11780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasSections = mSectionIndexer != null && mSections != null 11800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette && mSections.length > 0; 11810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (!hasSections || !mMatchDragPosition) { 11826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette return (float) firstVisibleItem / (totalItemCount - visibleItemCount); 118332c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 118432c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11856b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Ignore headers. 11860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette firstVisibleItem -= mHeaderCount; 118732c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell if (firstVisibleItem < 0) { 118832c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell return 0; 118932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 11900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette totalItemCount -= mHeaderCount; 119132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 11926b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Hidden portion of the first visible row. 11936b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final View child = mList.getChildAt(0); 11946b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float incrementalPos; 11956b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (child == null || child.getHeight() == 0) { 11966b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = 0; 11976b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 11986b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight(); 11996b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 12006b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 12016b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Number of rows in this section. 120232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem); 120332c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int sectionPos = mSectionIndexer.getPositionForSection(section); 1204f49971ec06e65ee2a0f0fd48a615b89c677086e7Adam Powell final int sectionCount = mSections.length; 12056b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int positionsInSection; 12066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section < sectionCount - 1) { 1207414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru final int nextSectionPos; 1208414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru if (section + 1 < sectionCount) { 1209414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = mSectionIndexer.getPositionForSection(section + 1); 1210414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } else { 1211414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = totalItemCount - 1; 1212414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } 12136b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = nextSectionPos - sectionPos; 12146b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12156b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = totalItemCount - sectionPos; 12166b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 12176b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 12186b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Position within this section. 12196b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float posWithinSection; 12206b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (positionsInSection == 0) { 12216b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = 0; 12226b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 12236b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = (firstVisibleItem + incrementalPos - sectionPos) 12246b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette / positionsInSection; 12256b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 122632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 1227f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette float result = (section + posWithinSection) / sectionCount; 1228f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1229f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // Fake out the scroll bar for the last item. Since the section indexer 1230f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // won't ever actually move the list in this end space, make scrolling 1231f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette // across the last item account for whatever space is remaining. 1232f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette if (firstVisibleItem > 0 && firstVisibleItem + visibleItemCount == totalItemCount) { 1233f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final View lastChild = mList.getChildAt(visibleItemCount - 1); 1234f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette final float lastItemVisible = (float) (mList.getHeight() - mList.getPaddingBottom() 1235f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette - lastChild.getTop()) / lastChild.getHeight(); 1236f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette result += (1 - result) * lastItemVisible; 1237f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette } 1238f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette 1239f9af7b250e9f12bd6955101919f3fd603d135e01Alan Viverette return result; 124032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 124132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 12420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels an ongoing fling event by injecting a 12440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link MotionEvent#ACTION_CANCEL} into the host view. 12450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 12470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final MotionEvent cancelFling = MotionEvent.obtain( 12480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1252e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 12530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels a pending drag. 12550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 12560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #startPendingDrag() 12570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void cancelPendingDrag() { 12594cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 1260af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1261af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Delays dragging until after the framework has determined that the user is 12640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * scrolling, rather than tapping. 12650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void startPendingDrag() { 12674cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = SystemClock.uptimeMillis() + TAP_TIMEOUT; 1268af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1269af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void beginDrag() { 12714cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette mPendingDrag = -1; 12724cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 1273af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 12740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1275af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1276af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1277af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 12780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1279af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1280af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1281af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1282af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1283af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1284af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1285af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1286af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 12870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onInterceptTouchEvent(MotionEvent ev) { 1288b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1289447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1290447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1291447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1292af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell switch (ev.getActionMasked()) { 1293af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_DOWN: 12940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(ev.getX(), ev.getY())) { 12950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the parent has requested that its children delay 12960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // pressed state (e.g. is a scrolling container) then we 12970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // need to allow the parent time to decide whether it wants 12980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // to intercept events. If it does, we will receive a CANCEL 12990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // event. 1300b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!mList.isInScrollingContainer()) { 1301b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette beginDrag(); 1302b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette return true; 1303af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1305b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette mInitialTouchY = ev.getY(); 1306b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette startPendingDrag(); 1307b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette } 1308b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette break; 1309b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette case MotionEvent.ACTION_MOVE: 1310b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isPointInside(ev.getX(), ev.getY())) { 1311b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette cancelPendingDrag(); 13124cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette } else if (mPendingDrag >= 0 && mPendingDrag <= SystemClock.uptimeMillis()) { 13134cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 13144cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 13154cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette final float pos = getPosFromMotionEvent(mInitialTouchY); 13164cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette scrollTo(pos); 13174cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette 13184cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette return onTouchEvent(ev); 1319af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1320af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 1321af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_UP: 1322af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_CANCEL: 1323af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1324af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1330a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette public boolean onInterceptHoverEvent(MotionEvent ev) { 1331b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1332a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1333a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1334a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1335a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette final int actionMasked = ev.getActionMasked(); 1336a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER 1337a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE 1338a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette && isPointInside(ev.getX(), ev.getY())) { 1339a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette setState(STATE_VISIBLE); 1340a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 1341a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1342a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1343a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1344a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1345a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 13460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onTouchEvent(MotionEvent me) { 1347b9f2722f6f32b275731fc7e4aeb367cdf9c30dd3Alan Viverette if (!isEnabled()) { 1348447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1349447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1350447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 13510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (me.getActionMasked()) { 13520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_UP: { 13534cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0) { 13540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Allow a tap to scroll. 13550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 13580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 13590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 13600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Will hit the STATE_DRAGGING check below 1362d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 13630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 13650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList != null) { 13660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // ViewGroup does the right thing already, but there might 13670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // be other classes that don't properly reset on touch-up, 13680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // so do this explicitly just in case. 13690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.requestDisallowInterceptTouchEvent(false); 13700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 13710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 1374a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 13750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 137720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 13780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 137920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 13800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_MOVE: { 13814cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette if (mPendingDrag >= 0 && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) { 13824cfeedb6aea057606cbc461fd1019f71b8aca843Alan Viverette beginDrag(); 1383af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1384af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell // Will hit the STATE_DRAGGING check below 1385af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 13860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 13880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // TODO: Ignore jitter. 13890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 13900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 13910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the previous scrollTo is still pending 13930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mScrollCompleted) { 13940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 13950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 14000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_CANCEL: { 14020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 14030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1408d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 14090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns whether a coordinate is inside the scroller's activation area. If 14110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * there is a track image, touching anywhere within the thumb-width of the 14120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * track activates scrolling. Otherwise, the user has to touch inside thumb 14130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * itself. 14140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 14150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param x The x-coordinate. 14160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param y The y-coordinate. 14170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the coordinate is inside the scroller's activation area. 14180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInside(float x, float y) { 14208636ace69640566768f89c2d92d2851ff064a2e9Alan Viverette return isPointInsideX(x) && (mTrackDrawable != null || isPointInsideY(y)); 14210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideX(float x) { 14240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 14250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x >= mThumbImage.getLeft(); 14260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 14270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x <= mThumbImage.getRight(); 14280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideY(float y) { 1432d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float offset = mThumbImage.getTranslationY(); 1433d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float top = mThumbImage.getTop() + offset; 1434d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell final float bottom = mThumbImage.getBottom() + offset; 1435d8273896843b20ac70eea06abdf7378f132dfa4bAdam Powell return y >= top && y <= bottom; 14360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 14370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Constructs an animator for the specified property on a group of views. 14400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for 14410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * implementation details. 14420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 14430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param property The property being animated. 14440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param value The value to which that property should animate. 14450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param views The target views to animate. 14460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return An animator for all the specified views. 14470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator groupAnimatorOfFloat( 14490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Property<View, Float> property, float value, View... views) { 14500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet animSet = new AnimatorSet(); 14510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet.Builder builder = null; 14520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 14530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette for (int i = views.length - 1; i >= 0; i--) { 14540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator anim = ObjectAnimator.ofFloat(views[i], property, value); 14550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (builder == null) { 14560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder = animSet.play(anim); 14570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 14580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(anim); 14590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 146020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 146120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 14620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return animSet; 146382f3495b146b267f3786997752cef25310176349Romain Guy } 146482f3495b146b267f3786997752cef25310176349Romain Guy 14650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's scaleX value. 14670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateScaleX(View v, float target) { 14690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.SCALE_X, target); 14700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1471e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's alpha value. 14740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateAlpha(View v, float alpha) { 14760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.ALPHA, alpha); 14770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1478e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>left</code> functionality handled by the 14810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setLeft(int)} and {@link View#getLeft()} methods. 14820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> LEFT = new IntProperty<View>("left") { 14840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 14860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setLeft(value); 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1488e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 14900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 14910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getLeft(); 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 1494e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 14950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 14960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>top</code> functionality handled by the 14970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setTop(int)} and {@link View#getTop()} methods. 14980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> TOP = new IntProperty<View>("top") { 1500e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 15010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setTop(value); 15030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1504e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 15050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getTop(); 15080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 15100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>right</code> functionality handled by the 15130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setRight(int)} and {@link View#getRight()} methods. 15140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> RIGHT = new IntProperty<View>("right") { 15160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setRight(value); 15190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getRight(); 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 15260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>bottom</code> functionality handled by the 15290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setBottom(int)} and {@link View#getBottom()} methods. 15300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") { 15320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 15340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setBottom(value); 15350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 15380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 15390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getBottom(); 15400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 15410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 15420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 15430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 15440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's bounds. 15450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 15460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateBounds(View v, Rect bounds) { 15470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left); 15480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top); 15490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right); 15500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom); 15510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom); 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1554