FastScroller.java revision 39bed695cecdbefc9fae785692fe468cd9007c35
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator; 200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.Animator.AnimatorListener; 210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorListenerAdapter; 220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.AnimatorSet; 230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.ObjectAnimator; 240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.animation.PropertyValuesHolder; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ColorStateList; 27e918a48df92fd16375c46624df74e6fd4609e016Alan Viveretteimport android.content.res.Resources; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 2920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.graphics.Rect; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.os.Build; 320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.text.TextUtils.TruncateAt; 330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.IntProperty; 340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.MathUtils; 350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.util.Property; 360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.Gravity; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 3820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powellimport android.view.View; 390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.View.MeasureSpec; 40af5280cc71e155758c2f6625eb999cabb37e937fAdam Powellimport android.view.ViewConfiguration; 410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroup.LayoutParams; 420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport android.view.ViewGroupOverlay; 43d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viveretteimport com.android.internal.R; 460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-out animation. */ 520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_OUT = 300; 530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of fade-in animation. */ 550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_FADE_IN = 150; 560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition cross-fade animation. */ 580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_CROSS_FADE = 50; 590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Duration of transition resize animation. */ 610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int DURATION_RESIZE = 100; 620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Inactivity timeout before fading controls. */ 640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long FADE_TIMEOUT = 1500; 65e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Minimum number of pages to justify showing a fast scroll thumb. */ 670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int MIN_PAGES = 4; 680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview not showing. */ 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 7120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb visible and moving along with the scrollbar. */ 730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_VISIBLE = 1; 740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Scroll thumb and preview being dragged by user. */ 760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int STATE_DRAGGING = 2; 7720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Styleable attributes. */ 7920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int[] ATTRS = new int[] { 80b2e551711aa93a3d296ced6368e895743d43da80Adam Powell android.R.attr.fastScrollTextColor, 81128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollThumbDrawable, 82128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollTrackDrawable, 83128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollPreviewBackgroundLeft, 84128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollPreviewBackgroundRight, 85128b6ba93d0549fd2beff4482678e1229dc1cf3dAdam Powell android.R.attr.fastScrollOverlayPosition 8620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell }; 8720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Styleable attribute indices. 89b2e551711aa93a3d296ced6368e895743d43da80Adam Powell private static final int TEXT_COLOR = 0; 9020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int THUMB_DRAWABLE = 1; 9120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int TRACK_DRAWABLE = 2; 9220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int PREVIEW_BACKGROUND_LEFT = 3; 9320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int PREVIEW_BACKGROUND_RIGHT = 4; 9420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_POSITION = 5; 9520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Positions for preview image and text. 9720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_FLOATING = 0; 9820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private static final int OVERLAY_AT_THUMB = 1; 99e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Indices for mPreviewResId. 1010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_LEFT = 0; 1020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final int PREVIEW_RIGHT = 1; 1030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Delay before considering a tap in the thumb area to be a drag. */ 1050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 1060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempBounds = new Rect(); 1080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Rect mTempMargins = new Rect(); 10920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AbsListView mList; 1110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ViewGroupOverlay mOverlay; 1120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mPrimaryText; 1130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final TextView mSecondaryText; 1140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mThumbImage; 1150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mTrackImage; 1160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final ImageView mPreviewImage; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Preview image resource IDs for left- and right-aligned layouts. See 1200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}. 1210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int[] mPreviewResId = new int[2]; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Padding in pixels around the preview text. Applied as layout margins to 1260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the preview text and padding to the preview image. 1270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final int mPreviewPadding; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether there is a track image to display. */ 1310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final boolean mHasTrackImage; 1320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing decoration transition animations. */ 1340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mDecorAnimation; 1350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Set containing preview text transition animations. */ 1370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private AnimatorSet mPreviewAnimation; 1380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the primary text is showing. */ 1400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mShowingPrimary; 1410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether we're waiting for completion of scrollTo(). */ 1430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mScrollCompleted; 1440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The position of the first visible item in the list. */ 1460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mFirstVisibleItem; 1470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of headers at the top of the view. */ 1490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mHeaderCount; 1500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The number of items in the list. */ 1524df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private int mItemCount = -1; 1530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** The index of the current section. */ 1550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private int mCurrentSection = -1; 1560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the list is long enough to need a fast scroller. */ 1584df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 159e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private Object[] mSections; 161e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Current decoration state, one of: 1640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_NONE}, nothing visible 1660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_VISIBLE}, showing track and thumb 1670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #STATE_DRAGGING}, visible and showing preview 1680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 171e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 1720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private BaseAdapter mListAdapter; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether decorations should be laid out from right to left. */ 1760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mLayoutFromRight; 17720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 178447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** Whether the fast scroller is enabled. */ 179447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette private boolean mEnabled; 180447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether the scrollbar and decorations should always be shown. */ 18220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private boolean mAlwaysShow; 18320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 1850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Position for the preview image and text. One of: 1860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <ul> 1870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_AT_THUMB} 1880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * <li>{@link #OVERLAY_FLOATING} 1890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * </ul> 1900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 19120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell private int mOverlayPosition; 19220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 1930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** Whether to precisely match the thumb position to the list. */ 194568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell private boolean mMatchDragPosition; 195568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 1960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float mInitialTouchY; 1970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean mHasPendingDrag; 198af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private int mScaledTouchSlop; 199af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 200af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell private final Runnable mDeferStartDrag = new Runnable() { 201e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 202af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell public void run() { 203af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList.mIsAttached) { 204af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell beginDrag(); 205af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(mInitialTouchY); 2070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 208af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 209af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 2100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = false; 2110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to delay hiding fast scroll decorations. 2160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final Runnable mDeferHide = new Runnable() { 2180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void run() { 2200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 2210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 2230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 2250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Used to effect a transition from primary to secondary text. 2260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 2270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private final AnimatorListener mSwitchPrimaryListener = new AnimatorListenerAdapter() { 2280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 2290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onAnimationEnd(Animator animation) { 2300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mShowingPrimary = !mShowingPrimary; 231af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 232af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell }; 233af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 23439bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette public FastScroller(AbsListView listView) { 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 2360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay = listView.getOverlay(); 2370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 23839bed695cecdbefc9fae785692fe468cd9007c35Alan Viverette final Context context = listView.getContext(); 2390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 2400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Resources res = context.getResources(); 2420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS); 2430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage = new ImageView(context); 2450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add track to overlay if it has an image. 2470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackResId = ta.getResourceId(TRACK_DRAWABLE, 0); 2480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (trackResId != 0) { 2490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasTrackImage = true; 2500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setBackgroundResource(trackResId); 2510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mTrackImage); 2520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 2530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasTrackImage = false; 2540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage = new ImageView(context); 2570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add thumb to overlay if it has an image. 2590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Drawable thumbDrawable = ta.getDrawable(THUMB_DRAWABLE); 2600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (thumbDrawable != null) { 2610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setImageDrawable(thumbDrawable); 2620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mThumbImage); 2630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If necessary, apply minimum thumb width and height. 2660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (thumbDrawable.getIntrinsicWidth() <= 0 || thumbDrawable.getIntrinsicHeight() <= 0) { 2670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setMinimumWidth(res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width)); 2680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setMinimumHeight( 2690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height)); 2700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 2710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); 2730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage = new ImageView(context); 2740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setMinimumWidth(previewSize); 2750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setMinimumHeight(previewSize); 2760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setAlpha(0f); 2770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mPreviewImage); 2780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewPadding = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_padding); 2800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2816b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int textMinSize = Math.max(0, previewSize - mPreviewPadding); 2820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText = createPreviewTextView(context, ta); 2836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumWidth(textMinSize); 2846b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mPrimaryText.setMinimumHeight(textMinSize); 2850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mPrimaryText); 2860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText = createPreviewTextView(context, ta); 2876b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumWidth(textMinSize); 2886b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mSecondaryText.setMinimumHeight(textMinSize); 2890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlay.add(mSecondaryText); 2900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(PREVIEW_BACKGROUND_LEFT, 0); 2920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(PREVIEW_BACKGROUND_RIGHT, 0); 2930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING); 2940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ta.recycle(); 2950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 2960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mScrollCompleted = true; 2970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = STATE_VISIBLE; 2980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mMatchDragPosition = 2990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; 3000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette getSectionsFromIndexer(); 3020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 3030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setScrollbarPosition(mList.getVerticalScrollbarPosition()); 304a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 308447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * Removes this FastScroller overlay from the host view. 309447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 310447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void remove() { 311447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mTrackImage); 312447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mThumbImage); 313447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPreviewImage); 314447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mPrimaryText); 315447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mOverlay.remove(mSecondaryText); 316447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 317447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 318447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 319447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @param enabled Whether the fast scroll thumb is enabled. 320447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 321447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public void setEnabled(boolean enabled) { 322447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette mEnabled = enabled; 323447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 324447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette if (enabled) { 325447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette if (mAlwaysShow) { 326447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette setState(STATE_VISIBLE); 327447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 328447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } else { 329447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette stop(); 330447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 331447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 332447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 333447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 334447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette * @return Whether the fast scroll thumb is enabled. 335447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette */ 336447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette public boolean isEnabled() { 337447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return mEnabled; 338447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 339447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 340447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette /** 3410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param alwaysShow Whether the fast scroll thumb should always be shown 3420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 34320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setAlwaysShow(boolean alwaysShow) { 34420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell mAlwaysShow = alwaysShow; 3450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 34620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell if (alwaysShow) { 34720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell setState(STATE_VISIBLE); 34820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } else if (mState == STATE_VISIBLE) { 349a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 35020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 35120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 35220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 3530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 3540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the fast scroll thumb will always be shown 3550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #setAlwaysShow(boolean) 3560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 35720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public boolean isAlwaysShowEnabled() { 35820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell return mAlwaysShow; 35920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 36020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 3610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 3620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Immediately transitions the fast scroller decorations to a hidden state. 3630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 3640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void stop() { 3650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 3660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 36720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 36820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public void setScrollbarPosition(int position) { 369c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio if (position == View.SCROLLBAR_POSITION_DEFAULT) { 370c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio position = mList.isLayoutRtl() ? 371c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; 372c23ee46c8fac06b1982d115368f772fea399a4e0Fabrice Di Meglio } 3730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; 3750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; 3770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setBackgroundResource(previewResId); 3780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Add extra padding for text. 3800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Drawable background = mPreviewImage.getBackground(); 3810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (background != null) { 3820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect padding = mTempBounds; 3830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette background.getPadding(padding); 3840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette padding.offset(mPreviewPadding, mPreviewPadding); 3850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); 38620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 3870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 38920232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 39020232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 39120232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell public int getWidth() { 3920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return mThumbImage.getWidth(); 39320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 39420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 3950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onSizeChanged(int w, int h, int oldw, int oldh) { 3960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette updateLayout(); 3970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 3980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 3990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onItemCountChanged(int oldTotalItemCount, int totalItemCount) { 4000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int visibleItemCount = mList.getChildCount(); 4010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 4020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 4030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int firstVisibleItem = mList.getFirstVisiblePosition(); 4040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 407e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 4080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Creates a view into which preview text can be placed. 4100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private TextView createPreviewTextView(Context context, TypedArray ta) { 4120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final LayoutParams params = new LayoutParams( 4130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 4140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Resources res = context.getResources(); 4150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int minSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); 4160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ColorStateList textColor = ta.getColorStateList(TEXT_COLOR); 4170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float textSize = res.getDimension(R.dimen.fastscroll_overlay_text_size); 4180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView textView = new TextView(context); 4190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutParams(params); 4200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setTextColor(textColor); 4210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setTextSize(textSize); 4220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setSingleLine(true); 4230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setEllipsize(TruncateAt.MIDDLE); 4240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setGravity(Gravity.CENTER); 4250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setAlpha(0f); 4260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Manually propagate inherited layout direction. 4280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette textView.setLayoutDirection(mList.getLayoutDirection()); 4290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return textView; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 432e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 4330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures and layouts the scrollbar and decorations. 4350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void updateLayout() { 4370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutThumb(); 4380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette layoutTrack(); 4390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 4410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mPrimaryText, bounds); 4420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPrimaryText, bounds); 4430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(mSecondaryText, bounds); 4440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mSecondaryText, bounds); 4450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewImage != null) { 4470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding. 4480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 4490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 4500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 4510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 4520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mPreviewImage, bounds); 45320232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 455e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 4560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Layouts a view within the specified bounds and pins the pivot point to 4580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the appropriate edge. 4590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 4600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to layout. 4610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param bounds Bounds at which to layout the view. 4620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void applyLayout(View view, Rect bounds) { 4640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom); 4650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.setPivotX(mLayoutFromRight ? bounds.right - bounds.left : 0); 4660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 4670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the preview text bounds, taking preview image padding into 4700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * account. This method should only be called after {@link #layoutThumb()} 4710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * and {@link #layoutTrack()} have both been called at least once. 4720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 4730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param v The preview text view to measure. 4740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 4750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 4760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measurePreview(View v, Rect out) { 4770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply the preview image's padding as layout margins. 4780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect margins = mTempMargins; 4790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.left = mPreviewImage.getPaddingLeft(); 4800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.top = mPreviewImage.getPaddingTop(); 4810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.right = mPreviewImage.getPaddingRight(); 4820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette margins.bottom = mPreviewImage.getPaddingBottom(); 4830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 4840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mOverlayPosition == OVERLAY_AT_THUMB) { 4850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(v, mThumbImage, margins, out); 48620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } else { 4870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureFloating(v, margins, out); 48820232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 4920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Measures the bounds for a view that should be laid out against the edge 4930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * of an adjacent view. If no adjacent view is provided, lays out against 4940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * the list edge. 4950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 4960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param view The view to measure for layout. 4970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param adjacent (Optional) The adjacent view, may be null to align to the 4980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * list edge. 4990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param margins Layout margins to apply to the view. 5000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param out Rectangle into which measured bounds are placed. 5010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureViewToSide(View view, View adjacent, Rect margins, Rect out) { 5030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 5040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 5050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 5060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 5070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 5080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 5090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 5100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 5110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 5120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 5130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 5140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 5151ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 5160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int listWidth = mList.getWidth(); 5170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int maxWidth; 5180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (adjacent == null) { 5190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = listWidth; 5200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (mLayoutFromRight) { 5210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = adjacent.getLeft(); 5220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 5230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette maxWidth = listWidth - adjacent.getRight(); 5240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 52520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 5260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int adjMaxWidth = maxWidth - marginLeft - marginRight; 5270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 5280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 5290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette view.measure(widthMeasureSpec, heightMeasureSpec); 5300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align to the left or right. 5320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = view.getMeasuredWidth(); 5330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left; 5340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right; 5350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 5360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = (adjacent == null ? listWidth : adjacent.getLeft()) - marginRight; 5370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = right - width; 5380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 5390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette left = (adjacent == null ? 0 : adjacent.getRight()) + marginLeft; 5400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette right = left + width; 5410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 54220232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 5430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Don't adjust the vertical position. 5440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = marginTop; 5450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + view.getMeasuredHeight(); 5460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 5470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 548af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 5490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void measureFloating(View preview, Rect margins, Rect out) { 5500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginLeft; 5510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginTop; 5520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int marginRight; 5530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (margins == null) { 5540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = 0; 5550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = 0; 5560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = 0; 5570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 5580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginLeft = margins.left; 5590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginTop = margins.top; 5600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette marginRight = margins.right; 5610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 562568ccd88d7efd33da0c535e07b7ea7cf476be22aAdam Powell 5630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View list = mList; 5640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int listWidth = list.getWidth(); 5650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int adjMaxWidth = listWidth - marginLeft - marginRight; 5660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); 5670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 5680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette preview.measure(widthMeasureSpec, heightMeasureSpec); 5690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 5700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Align at the vertical center, 10% from the top. 5710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int width = preview.getMeasuredWidth(); 5720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = list.getHeight() / 10 + marginTop; 5730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = top + preview.getMeasuredHeight(); 5740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left = (listWidth - width) / 2; 5750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + width; 5760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette out.set(left, top, right, bottom); 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 578e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the thumb according to the current scrollbar position. 5810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutThumb() { 5830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 5840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measureViewToSide(mThumbImage, null, null, bounds); 5850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(mThumbImage, bounds); 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 587e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 5880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 5890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Lays out the track centered on the thumb, if available, or against the 5900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * edge if no thumb is available. Must be called after {@link #layoutThumb}. 5910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 5920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void layoutTrack() { 5930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View track = mTrackImage; 5940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View thumb = mThumbImage; 5950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final View list = mList; 5960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int listWidth = list.getWidth(); 5970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(listWidth, MeasureSpec.AT_MOST); 5980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 5990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.measure(widthMeasureSpec, heightMeasureSpec); 6000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int trackWidth = track.getMeasuredWidth(); 6020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int thumbHalfHeight = thumb == null ? 0 : thumb.getHeight() / 2; 6030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int left = thumb == null ? listWidth - trackWidth : 6040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2; 6050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int right = left + trackWidth; 6060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = thumbHalfHeight; 6070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = list.getHeight() - thumbHalfHeight; 6080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette track.layout(left, top, right, bottom); 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 610e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setState(int state) { 6120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.removeCallbacks(mDeferHide); 613e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mAlwaysShow && state == STATE_NONE) { 6150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette state = STATE_VISIBLE; 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (state == mState) { 6190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return; 6200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (state) { 6230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_NONE: 6240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToHidden(); 6250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 6260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_VISIBLE: 6270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToVisible(); 6280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 6290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case STATE_DRAGGING: 6306b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(mCurrentSection)) { 6316b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToDragging(); 6326b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 6336b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 6346b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 6350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette break; 6360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 63720232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 6380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mState = state; 639e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette refreshDrawablePressedState(); 6410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 642e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void refreshDrawablePressedState() { 6440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean isPressed = mState == STATE_DRAGGING; 6450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setPressed(isPressed); 6460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mTrackImage.setPressed(isPressed); 6470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 648e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 6490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows nothing. 6510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToHidden() { 6530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 6540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat(View.ALPHA, 0f, mThumbImage, mTrackImage, 6580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage, mPrimaryText, mSecondaryText).setDuration(DURATION_FADE_OUT); 6590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Push the thumb and track outside the list bounds. 6610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = mLayoutFromRight ? mThumbImage.getWidth() : -mThumbImage.getWidth(); 6620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideOut = groupAnimatorOfFloat( 6630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, offset, mThumbImage, mTrackImage) 6640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 6650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 6670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeOut, slideOut); 6680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb and track. 6730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToVisible() { 6750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 6760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat(View.ALPHA, 1f, mThumbImage, mTrackImage) 6800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 6810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeOut = groupAnimatorOfFloat( 6820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 0f, mPreviewImage, mPrimaryText, mSecondaryText) 6830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_OUT); 6840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 6850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 6860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 6870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 6880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, fadeOut, slideIn); 6890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6912c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 6920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 6930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Shows the thumb, preview, and track. 6940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 6950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void transitionToDragging() { 6960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mDecorAnimation != null) { 6970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.cancel(); 6982c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 6990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator fadeIn = groupAnimatorOfFloat( 7010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.ALPHA, 1f, mThumbImage, mTrackImage, mPreviewImage) 7020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .setDuration(DURATION_FADE_IN); 7030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator slideIn = groupAnimatorOfFloat( 7040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette View.TRANSLATION_X, 0f, mThumbImage, mTrackImage).setDuration(DURATION_FADE_IN); 7050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation = new AnimatorSet(); 7070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.playTogether(fadeIn, slideIn); 7080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mDecorAnimation.start(); 7092c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell } 7102c6196aa557e4eaf09d1ec3ad1347742f7f9f7b5Adam Powell 711a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette private void postAutoHide() { 712a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.removeCallbacks(mDeferHide); 713a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette mList.postDelayed(mDeferHide, FADE_TIMEOUT); 714a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 715a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 7160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isLongList(int visibleItemCount, int totalItemCount) { 7170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Are there enough pages to require fast scroll? Recompute only if 7180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // total count changes. 7194df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (mItemCount != totalItemCount && visibleItemCount > 0) { 7204df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project mItemCount = totalItemCount; 72132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell mLongList = mItemCount / visibleItemCount >= MIN_PAGES; 72232c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 7230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return mLongList; 7250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 7260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 728447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette if (!mEnabled || !mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) { 7290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_NONE); 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; 7340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (hasMoreItems && mState != STATE_DRAGGING) { 7350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mFirstVisibleItem != firstVisibleItem) { 7410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mFirstVisibleItem = firstVisibleItem; 742d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 7430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Show the thumb, if necessary, and set up auto-fade. 7440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState != STATE_DRAGGING) { 7450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 746a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 7470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 748d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 749d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 750d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 7510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void getSectionsFromIndexer() { 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 7530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Adapter adapter = mList.getAdapter(); 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 7560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHeaderCount = ((HeaderViewListAdapter) adapter).getHeadersCount(); 7570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 7610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter) 7620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette .getAdapter(); 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (adapter instanceof SectionIndexer) { 7690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 7700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSectionIndexer = (SectionIndexer) adapter; 7710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = mSectionIndexer.getSections(); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mListAdapter = (BaseAdapter) adapter; 7740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSections = null; 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 778b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell public void onSectionsChanged() { 779b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell mListAdapter = null; 780b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell } 781b1f498afc379ec84b86137e91afda6eccb8f4c0aAdam Powell 7820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 7830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Scrolls to a specific position within the section 7840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position 7850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 7860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void scrollTo(float position) { 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 7880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 7890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int count = mList.getCount(); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 7910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int sectionCount = sections == null ? 0 : sections.length; 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 7930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (sections != null && sectionCount > 1) { 7940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int exactSection = MathUtils.constrain( 7950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette (int) (position * sectionCount), 0, sectionCount - 1); 7960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetSection = exactSection; 7970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int targetIndex = mSectionIndexer.getPositionForSection(targetSection); 7980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 7990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 8070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevIndex = targetIndex; 8080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int prevSection = targetSection; 8090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int nextSection = targetSection + 1; 8100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 8120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetSection < sectionCount - 1) { 8130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette nextIndex = mSectionIndexer.getPositionForSection(targetSection + 1); 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 815e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 8170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (nextIndex == targetIndex) { 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 8190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (targetSection > 0) { 8200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetSection--; 8210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevIndex = mSectionIndexer.getPositionForSection(targetSection); 8220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevIndex != targetIndex) { 8230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette prevSection = targetSection; 8240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette sectionIndex = targetSection; 825b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 8260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else if (targetSection == 0) { 827b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 828b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 829b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 830b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 831b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 836e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // unique. For instance, if there is no P, then request for P's 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 838e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette // sure that there is really a Q at Q's position. If not, move 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 8410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette while (nextNextSection < sectionCount && 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 8480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // currently visible section. This could be equal to or greater than 8490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // (1 / nSections). If the target position is near the previous 8500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // position, snap to the previous position. 8510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float prevPosition = (float) prevSection / sectionCount; 8520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float nextPosition = (float) nextSection / sectionCount; 8530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float snapThreshold = (count == 0) ? Float.MAX_VALUE : .125f / count; 8540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (prevSection == exactSection && position - prevPosition < snapThreshold) { 8550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex; 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = prevIndex + (int) ((nextIndex - prevIndex) * (position - prevPosition) 8580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette / (nextPosition - prevPosition)); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Clamp to valid positions. 8620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette targetIndex = MathUtils.constrain(targetIndex, 0, count - 1); 863e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 8650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ExpandableListView expList = (ExpandableListView) mList; 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 8670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(targetIndex + mHeaderCount)), 8680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 8700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView) mList).setSelectionFromTop(targetIndex + mHeaderCount, 0); 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(targetIndex + mHeaderCount); 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int index = MathUtils.constrain((int) (position * count), 0, count - 1); 8767ee1ff1450a3ff83b6b8663bd7f44dc6f30775afAdam Powell 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 8800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ExpandableListView.getPackedPositionForGroup(index + mHeaderCount)), 0); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 8820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette ((ListView)mList).setSelectionFromTop(index + mHeaderCount, 0); 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.setSelection(index + mHeaderCount); 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8906b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (mCurrentSection != sectionIndex) { 8916b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette mCurrentSection = sectionIndex; 8926b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 8936b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (transitionPreviewLayout(sectionIndex)) { 8940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette transitionToDragging(); 8956b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 8966b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette transitionToVisible(); 8970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9026b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * Transitions the preview text to a new section. Handles animation, 9036b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * measurement, and layout. If the new preview text is empty, returns false. 9040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 9056b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @param sectionIndex The section index to which the preview should 9066b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * transition. 9076b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette * @return False if the new preview text is empty. 9080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9096b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette private boolean transitionPreviewLayout(int sectionIndex) { 9106b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object[] sections = mSections; 9116b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette String text = null; 9126b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (sections != null && sectionIndex >= 0 && sectionIndex < sections.length) { 9136b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final Object section = sections[sectionIndex]; 9146b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section != null) { 9156b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette text = section.toString(); 9166b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 9176b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 9186b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 9190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Rect bounds = mTempBounds; 9200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final ImageView preview = mPreviewImage; 9210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView showing; 9220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final TextView target; 9230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mShowingPrimary) { 9240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mPrimaryText; 9250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mSecondaryText; 9260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 9270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette showing = mSecondaryText; 9280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target = mPrimaryText; 9290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Set and layout target immediately. 9320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setText(text); 9330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette measurePreview(target, bounds); 9340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette applyLayout(target, bounds); 9350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mPreviewAnimation != null) { 9370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.cancel(); 9380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Cross-fade preview text. 9410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator showTarget = animateAlpha(target, 1f).setDuration(DURATION_CROSS_FADE); 9420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator hideShowing = animateAlpha(showing, 0f).setDuration(DURATION_CROSS_FADE); 9430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette hideShowing.addListener(mSwitchPrimaryListener); 9440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Apply preview image padding and animate bounds, if necessary. 9460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.left -= mPreviewImage.getPaddingLeft(); 9470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.top -= mPreviewImage.getPaddingTop(); 9480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.right += mPreviewImage.getPaddingRight(); 9490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette bounds.bottom += mPreviewImage.getPaddingBottom(); 9500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator resizePreview = animateBounds(preview, bounds); 9510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette resizePreview.setDuration(DURATION_RESIZE); 9520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation = new AnimatorSet(); 9540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final AnimatorSet.Builder builder = mPreviewAnimation.play(hideShowing).with(showTarget); 9550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(resizePreview); 9560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // The current preview size is unaffected by hidden or showing. It's 9580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // used to set starting scales for things that need to be scaled down. 9590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int previewWidth = preview.getWidth() - preview.getPaddingLeft() 9600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette - preview.getPaddingRight(); 9610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If target is too large, shrink it immediately to fit and expand to 9630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // target size. Otherwise, start at target size. 9640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int targetWidth = target.getWidth(); 9650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (targetWidth > previewWidth) { 9660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX((float) previewWidth / targetWidth); 9670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(target, 1f).setDuration(DURATION_RESIZE); 9680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 9690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 9700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette target.setScaleX(1f); 9710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If showing is larger than target, shrink to target size. 9740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int showingWidth = showing.getWidth(); 9750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (showingWidth > targetWidth) { 9760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float scale = (float) targetWidth / showingWidth; 9770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator scaleAnim = animateScaleX(showing, scale).setDuration(DURATION_RESIZE); 9780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(scaleAnim); 9790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewAnimation.start(); 9826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 9836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette return (text != null && text.length() > 0); 9840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 9850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 9870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Positions the thumb and preview widgets. 9880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 9890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param position The position, between 0 and 1, along the track at which 9900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * to place the thumb. 9910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 9920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void setThumbPos(float position) { 9930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = 0; 9940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = mList.getHeight(); 9950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 9960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbHalfHeight = mThumbImage.getHeight() / 2f; 9970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float min = top + thumbHalfHeight; 9980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float max = bottom - thumbHalfHeight; 9990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 10000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 10010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbMiddle = position * range + offset; 10020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mThumbImage.setTranslationY(thumbMiddle - thumbHalfHeight); 10030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Center the preview on the thumb, constrained to the list bounds. 10050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewHalfHeight = mPreviewImage.getHeight() / 2f; 10060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float minP = top + previewHalfHeight; 10070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float maxP = bottom - previewHalfHeight; 10080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewMiddle = MathUtils.constrain(thumbMiddle, minP, maxP); 10090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float previewTop = previewMiddle - previewHalfHeight; 10100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPreviewImage.setTranslationY(previewTop); 10120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mPrimaryText.setTranslationY(previewTop); 10130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mSecondaryText.setTranslationY(previewTop); 10140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromMotionEvent(float y) { 10170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int top = 0; 10180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final int bottom = mList.getHeight(); 10190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float thumbHalfHeight = mThumbImage.getHeight() / 2f; 10210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float min = top + thumbHalfHeight; 10220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float max = bottom - thumbHalfHeight; 10230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float offset = min; 10240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float range = max - min; 10250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10260ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the list is the same height as the thumbnail or shorter, 10270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // effectively disable scrolling. 10280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (range <= 0) { 10290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return 0f; 10300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return MathUtils.constrain((y - offset) / range, 0f, 1f); 10330ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 10340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private float getPosFromItemCount( 10360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette int firstVisibleItem, int visibleItemCount, int totalItemCount) { 103735948b7ed502d3f126acc8f2d61e099fa5deb0c7Adam Powell if (mSectionIndexer == null || mListAdapter == null) { 103832c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell getSectionsFromIndexer(); 103932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 10400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 10410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final boolean hasSections = mSectionIndexer != null && mSections != null 10420ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette && mSections.length > 0; 10430ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (!hasSections || !mMatchDragPosition) { 10446b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette return (float) firstVisibleItem / (totalItemCount - visibleItemCount); 104532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 104632c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 10476b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Ignore headers. 10480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette firstVisibleItem -= mHeaderCount; 104932c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell if (firstVisibleItem < 0) { 105032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell return 0; 105132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 10520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette totalItemCount -= mHeaderCount; 105332c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 10546b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Hidden portion of the first visible row. 10556b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final View child = mList.getChildAt(0); 10566b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float incrementalPos; 10576b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (child == null || child.getHeight() == 0) { 10586b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = 0; 10596b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 10606b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette incrementalPos = (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight(); 10616b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10626b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10636b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Number of rows in this section. 106432c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem); 106532c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell final int sectionPos = mSectionIndexer.getPositionForSection(section); 1066f49971ec06e65ee2a0f0fd48a615b89c677086e7Adam Powell final int sectionCount = mSections.length; 10676b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final int positionsInSection; 10686b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (section < sectionCount - 1) { 1069414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru final int nextSectionPos; 1070414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru if (section + 1 < sectionCount) { 1071414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = mSectionIndexer.getPositionForSection(section + 1); 1072414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } else { 1073414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru nextSectionPos = totalItemCount - 1; 1074414b02380d73a4ced03b1b51233ce9b339fb52cfJean-Baptiste Queru } 10756b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = nextSectionPos - sectionPos; 10766b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 10776b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette positionsInSection = totalItemCount - sectionPos; 10786b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 10796b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette 10806b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette // Position within this section. 10816b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette final float posWithinSection; 10826b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette if (positionsInSection == 0) { 10836b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = 0; 10846b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } else { 10856b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette posWithinSection = (firstVisibleItem + incrementalPos - sectionPos) 10866b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette / positionsInSection; 10876b40cc7f8a01ed31202aaf05c10bfac42ee87539Alan Viverette } 108832c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 10890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return (section + posWithinSection) / sectionCount; 109032c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell } 109132c3a6929af9d63de3bf45a61be6e1a4bde136d3Adam Powell 10920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 10930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels an ongoing fling event by injecting a 10940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link MotionEvent#ACTION_CANCEL} into the host view. 10950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 10970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final MotionEvent cancelFling = MotionEvent.obtain( 10980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1102e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 11030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Cancels a pending drag. 11050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 11060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @see #startPendingDrag() 11070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void cancelPendingDrag() { 1109af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.removeCallbacks(mDeferStartDrag); 11100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = false; 1111af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1112af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 11130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 11140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Delays dragging until after the framework has determined that the user is 11150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * scrolling, rather than tapping. 11160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 11170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void startPendingDrag() { 11180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mHasPendingDrag = true; 11190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.postDelayed(mDeferStartDrag, TAP_TIMEOUT); 1120af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1121af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 11220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private void beginDrag() { 1123af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 11240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1125af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1126af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1127af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 11280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1129af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1130af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1131af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1132af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1133af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1134af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1135af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1136af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 11370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onInterceptTouchEvent(MotionEvent ev) { 1138447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette if (!mEnabled) { 1139447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1140447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1141447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 1142af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell switch (ev.getActionMasked()) { 1143af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_DOWN: 11440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(ev.getX(), ev.getY())) { 11450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the parent has requested that its children delay 11460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // pressed state (e.g. is a scrolling container) then we 11470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // need to allow the parent time to decide whether it wants 11480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // to intercept events. If it does, we will receive a CANCEL 11490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // event. 11500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList.isInScrollingContainer()) { 11510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mInitialTouchY = ev.getY(); 11520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette startPendingDrag(); 11530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return false; 1154af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 11550ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 11570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 1158af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1159af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 1160af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_UP: 1161af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell case MotionEvent.ACTION_CANCEL: 1162af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1163af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell break; 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1169a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette public boolean onInterceptHoverEvent(MotionEvent ev) { 1170a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if (!mEnabled) { 1171a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1172a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1173a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1174a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette final int actionMasked = ev.getActionMasked(); 1175a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette if ((actionMasked == MotionEvent.ACTION_HOVER_ENTER 1176a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette || actionMasked == MotionEvent.ACTION_HOVER_MOVE) && mState == STATE_NONE 1177a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette && isPointInside(ev.getX(), ev.getY())) { 1178a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette setState(STATE_VISIBLE); 1179a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 1180a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1181a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 1182a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette return false; 1183a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette } 1184a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette 11850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public boolean onTouchEvent(MotionEvent me) { 1186447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette if (!mEnabled) { 1187447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette return false; 1188447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette } 1189447cdf2c069a05d9f8b5aaa4269be43e8f5e1d89Alan Viverette 11900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette switch (me.getActionMasked()) { 11910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_DOWN: { 11920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (isPointInside(me.getX(), me.getY())) { 1193af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell beginDrag(); 1194af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell return true; 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 1197af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 11980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_UP: { 11990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mHasPendingDrag) { 12000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Allow a tap to scroll. 12010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette beginDrag(); 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 12040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 12050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 12060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 12080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // Will hit the STATE_DRAGGING check below 1209d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 12100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 12120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mList != null) { 12130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // ViewGroup does the right thing already, but there might 12140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // be other classes that don't properly reset on touch-up, 12150ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // so do this explicitly just in case. 12160ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.requestDisallowInterceptTouchEvent(false); 12170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 12180ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12190ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setState(STATE_VISIBLE); 1221a709b37eab535180f41d2bb9d029244aa84ee1f6Alan Viverette postAutoHide(); 12220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return true; 122420232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 12250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 122620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 12270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_MOVE: { 12280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mHasPendingDrag && Math.abs(me.getY() - mInitialTouchY) > mScaledTouchSlop) { 1229af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell setState(STATE_DRAGGING); 12300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1231af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mListAdapter == null && mList != null) { 1232af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell getSectionsFromIndexer(); 1233af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 12340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 1235af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell if (mList != null) { 1236af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.requestDisallowInterceptTouchEvent(true); 1237af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 1238af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 1239af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell 1240af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelFling(); 1241af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell cancelPendingDrag(); 1242af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell // Will hit the STATE_DRAGGING check below 1243af5280cc71e155758c2f6625eb999cabb37e937fAdam Powell } 12440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mState == STATE_DRAGGING) { 12460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // TODO: Ignore jitter. 12470ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final float pos = getPosFromMotionEvent(me.getY()); 12480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette setThumbPos(pos); 12490ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette // If the previous scrollTo is still pending 12510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mScrollCompleted) { 12520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette scrollTo(pos); 12530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 12580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12590ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette case MotionEvent.ACTION_CANCEL: { 12600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette cancelPendingDrag(); 12610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } break; 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1266d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 12670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns whether a coordinate is inside the scroller's activation area. If 12690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * there is a track image, touching anywhere within the thumb-width of the 12700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * track activates scrolling. Otherwise, the user has to touch inside thumb 12710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * itself. 12720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 12730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param x The x-coordinate. 12740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param y The y-coordinate. 12750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return Whether the coordinate is inside the scroller's activation area. 12760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 12770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInside(float x, float y) { 12780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return isPointInsideX(x) && (mHasTrackImage || isPointInsideY(y)); 12790ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideX(float x) { 12820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (mLayoutFromRight) { 12830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x >= mThumbImage.getLeft(); 12840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 12850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return x <= mThumbImage.getRight(); 12860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private boolean isPointInsideY(float y) { 12900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return y >= mThumbImage.getTop() && y <= mThumbImage.getBottom(); 12910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 12920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 12930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 12940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Constructs an animator for the specified property on a group of views. 12950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * See {@link ObjectAnimator#ofFloat(Object, String, float...)} for 12960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * implementation details. 12970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * 12980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param property The property being animated. 12990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param value The value to which that property should animate. 13000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @param views The target views to animate. 13010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * @return An animator for all the specified views. 13020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator groupAnimatorOfFloat( 13040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette Property<View, Float> property, float value, View... views) { 13050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet animSet = new AnimatorSet(); 13060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette AnimatorSet.Builder builder = null; 13070ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13080ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette for (int i = views.length - 1; i >= 0; i--) { 13090ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final Animator anim = ObjectAnimator.ofFloat(views[i], property, value); 13100ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette if (builder == null) { 13110ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder = animSet.play(anim); 13120ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } else { 13130ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette builder.with(anim); 13140ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 131520232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell } 131620232d0f7ce2220df72dd78bed052f6b4a643f10Adam Powell 13170ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return animSet; 131882f3495b146b267f3786997752cef25310176349Romain Guy } 131982f3495b146b267f3786997752cef25310176349Romain Guy 13200ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13210ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's scaleX value. 13220ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13230ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateScaleX(View v, float target) { 13240ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.SCALE_X, target); 13250ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1326e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13270ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13280ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's alpha value. 13290ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13300ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateAlpha(View v, float alpha) { 13310ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofFloat(v, View.ALPHA, alpha); 13320ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1333e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13340ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13350ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>left</code> functionality handled by the 13360ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setLeft(int)} and {@link View#getLeft()} methods. 13370ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13380ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> LEFT = new IntProperty<View>("left") { 13390ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13400ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 13410ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setLeft(value); 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1343e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13440ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13450ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 13460ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getLeft(); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13480ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 1349e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13500ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13510ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>top</code> functionality handled by the 13520ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setTop(int)} and {@link View#getTop()} methods. 13530ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13540ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> TOP = new IntProperty<View>("top") { 1355e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette @Override 13560ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 13570ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setTop(value); 13580ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 1359e918a48df92fd16375c46624df74e6fd4609e016Alan Viverette 13600ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13610ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 13620ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getTop(); 13630ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13640ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 13650ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13660ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13670ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>right</code> functionality handled by the 13680ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setRight(int)} and {@link View#getRight()} methods. 13690ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13700ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> RIGHT = new IntProperty<View>("right") { 13710ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13720ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 13730ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setRight(value); 13740ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13750ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13760ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13770ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 13780ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getRight(); 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13800ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 13810ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13820ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13830ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * A Property wrapper around the <code>bottom</code> functionality handled by the 13840ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * {@link View#setBottom(int)} and {@link View#getBottom()} methods. 13850ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 13860ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Property<View, Integer> BOTTOM = new IntProperty<View>("bottom") { 13870ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13880ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public void setValue(View object, int value) { 13890ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette object.setBottom(value); 13900ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13910ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13920ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette @Override 13930ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette public Integer get(View object) { 13940ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return object.getBottom(); 13950ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette } 13960ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette }; 13970ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette 13980ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette /** 13990ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette * Returns an animator for the view's bounds. 14000ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette */ 14010ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette private static Animator animateBounds(View v, Rect bounds) { 14020ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder left = PropertyValuesHolder.ofInt(LEFT, bounds.left); 14030ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder top = PropertyValuesHolder.ofInt(TOP, bounds.top); 14040ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder right = PropertyValuesHolder.ofInt(RIGHT, bounds.right); 14050ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette final PropertyValuesHolder bottom = PropertyValuesHolder.ofInt(BOTTOM, bounds.bottom); 14060ebe81e8b1f2b9db8d41b72a6dae8d6848b51cc5Alan Viverette return ObjectAnimator.ofPropertyValuesHolder(v, left, top, right, bottom); 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1409