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 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ColorStateList; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.RectF; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 29a5e441525660765e0913140daff4d12a0d94e88cMitsuru Oshimaimport android.util.TypedValue; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 31d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powellimport android.widget.AbsListView.OnScrollListener; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for AbsListView to draw and control the Fast Scroll thumb 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass FastScroller { 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Minimum number of pages to justify showing a fast scroll thumb 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int MIN_PAGES = 4; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Scroll thumb not showing 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_NONE = 0; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Not implemented yet - fade-in transition 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_ENTER = 1; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Scroll thumb visible and moving along with the scrollbar 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_VISIBLE = 2; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Scroll thumb being dragged by user 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_DRAGGING = 3; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Scroll thumb fading out due to inactivity timeout 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int STATE_EXIT = 4; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Drawable mThumbDrawable; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Drawable mOverlayDrawable; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mThumbH; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mThumbW; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mThumbY; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RectF mOverlayPos; 591ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani private int mOverlaySize; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AbsListView mList; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mScrollCompleted; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVisibleItem; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Paint mPaint; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mListOffset; 664df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private int mItemCount = -1; 674df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project private boolean mLongList; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Object [] mSections; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mSectionText; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDrawOverlay; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ScrollFade mScrollFade; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mState; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Handler mHandler = new Handler(); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BaseAdapter mListAdapter; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SectionIndexer mSectionIndexer; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mChangedBounds; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public FastScroller(Context context, AbsListView listView) { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList = listView; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project init(context); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setState(int state) { 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (state) { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case STATE_NONE: 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeCallbacks(mScrollFade); 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.invalidate(); 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case STATE_VISIBLE: 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState != STATE_VISIBLE) { // Optimization 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetThumbPos(); 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Fall through 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case STATE_DRAGGING: 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeCallbacks(mScrollFade); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case STATE_EXIT: 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int viewWidth = mList.getWidth(); 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH); 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState = state; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getState() { 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mState; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetThumbPos() { 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int viewWidth = mList.getWidth(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bounds are always top right. Y coordinate get's translated during draw 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 121a5e441525660765e0913140daff4d12a0d94e88cMitsuru Oshima private void useThumbDrawable(Context context, Drawable drawable) { 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable = drawable; 1231ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani mThumbW = context.getResources().getDimensionPixelSize( 1241ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani com.android.internal.R.dimen.fastscroll_thumb_width); 1251ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani mThumbH = context.getResources().getDimensionPixelSize( 1261ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani com.android.internal.R.dimen.fastscroll_thumb_height); 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mChangedBounds = true; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void init(Context context) { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get both the scrollbar states drawables 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Resources res = context.getResources(); 133a5e441525660765e0913140daff4d12a0d94e88cMitsuru Oshima useThumbDrawable(context, res.getDrawable( 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2)); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOverlayDrawable = res.getDrawable( 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.drawable.menu_submenu_background); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 141d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy getSectionsFromIndexer(); 1421ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani 1431ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani mOverlaySize = context.getResources().getDimensionPixelSize( 1441ffaebc41bfd47472543d1ff86c8412c868fc4c9Amith Yamasani com.android.internal.R.dimen.fastscroll_overlay_size); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOverlayPos = new RectF(); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollFade = new ScrollFade(); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = new Paint(); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setAntiAlias(true); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextAlign(Paint.Align.CENTER); 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextSize(mOverlaySize / 2); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project android.R.attr.textColorPrimary }); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ColorStateList textColor = ta.getColorStateList(ta.getIndex(0)); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int textColorNormal = textColor.getDefaultColor(); 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setColor(textColorNormal); 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState = STATE_NONE; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void stop() { 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_NONE); 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean isVisible() { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !(mState == STATE_NONE); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void draw(Canvas canvas) { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_NONE) { 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No need to draw anything 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int y = mThumbY; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int viewWidth = mList.getWidth(); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final FastScroller.ScrollFade scrollFade = mScrollFade; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int alpha = -1; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_EXIT) { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = scrollFade.getAlpha(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (alpha < ScrollFade.ALPHA_MAX / 2) { 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.setAlpha(alpha * 2); 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.setBounds(left, 0, viewWidth, mThumbH); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mChangedBounds = true; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(0, y); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.draw(canvas); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(0, -y); 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If user is dragging the scroll bar, draw the alphabet overlay 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_DRAGGING && mDrawOverlay) { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOverlayDrawable.draw(canvas); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Paint paint = mPaint; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float descent = paint.descent(); 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final RectF rectF = mOverlayPos; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2, 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent, paint); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mState == STATE_EXIT) { 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (alpha == 0) { // Done with exit 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_NONE); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH); 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onSizeChanged(int w, int h, int oldw, int oldh) { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mThumbDrawable != null) { 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final RectF pos = mOverlayPos; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.left = (w - mOverlaySize) / 2; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.right = pos.left + mOverlaySize; 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.top = h / 10; // 10% from top 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.bottom = pos.top + mOverlaySize; 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOverlayDrawable != null) { 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOverlayDrawable.setBounds((int) pos.left, (int) pos.top, 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (int) pos.right, (int) pos.bottom); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int totalItemCount) { 2294df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project // Are there enough pages to require fast scroll? Recompute only if total count changes 2304df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (mItemCount != totalItemCount && visibleItemCount > 0) { 2314df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project mItemCount = totalItemCount; 2324df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project mLongList = mItemCount / visibleItemCount >= MIN_PAGES; 2334df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project } 2344df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (!mLongList) { 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState != STATE_NONE) { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_NONE); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) { 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbY = ((mList.getHeight() - mThumbH) * firstVisibleItem) 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project / (totalItemCount - visibleItemCount); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChangedBounds) { 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetThumbPos(); 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mChangedBounds = false; 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = true; 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (firstVisibleItem == mVisibleItem) { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVisibleItem = firstVisibleItem; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState != STATE_DRAGGING) { 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_VISIBLE); 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.postDelayed(mScrollFade, 1500); 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy SectionIndexer getSectionIndexer() { 260d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy return mSectionIndexer; 261d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 262d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 263d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy Object[] getSections() { 264d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy if (mListAdapter == null && mList != null) { 265d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy getSectionsFromIndexer(); 266d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 267d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy return mSections; 268d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 269d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 270d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private void getSectionsFromIndexer() { 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Adapter adapter = mList.getAdapter(); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = null; 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof HeaderViewListAdapter) { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount(); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof ExpandableListConnector) { 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListAdapter expAdapter = ((ExpandableListConnector)adapter).getAdapter(); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expAdapter instanceof SectionIndexer) { 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) expAdapter; 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof SectionIndexer) { 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer = (SectionIndexer) adapter; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = mSectionIndexer.getSections(); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mListAdapter = (BaseAdapter) adapter; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSections = new String[] { " " }; 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void scrollTo(float position) { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mList.getCount(); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mScrollCompleted = false; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float fThreshold = (1.0f / count) / 8; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Object[] sections = mSections; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sectionIndex; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sections != null && sections.length > 1) { 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int nSections = sections.length; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int section = (int) (position * nSections); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (section >= nSections) { 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project section = nSections - 1; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int exactSection = section; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = section; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int index = mSectionIndexer.getPositionForSection(section); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Given the expected section and index, the following code will 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try to account for missing sections (no names starting with..) 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It will compute the scroll space of surrounding empty sections 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and interpolate the currently visible letter's range across the 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available space, so that there is always some list movement while 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user moves the thumb. 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextIndex = count; 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int prevIndex = index; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int prevSection = section; 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextSection = section + 1; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Assume the next section is unique 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (section < nSections - 1) { 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextIndex = mSectionIndexer.getPositionForSection(section + 1); 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the previous index if we're slicing the previous section 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextIndex == index) { 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Non-existent letter 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (section > 0) { 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project section--; 332b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project prevIndex = mSectionIndexer.getPositionForSection(section); 333b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (prevIndex != index) { 334b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project prevSection = section; 335b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = section; 336b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 337b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } else if (section == 0) { 338b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // When section reaches 0 here, sectionIndex must follow it. 339b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // Assuming mSectionIndexer.getPositionForSection(0) == 0. 340b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project sectionIndex = 0; 341b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 342b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next index, in case the assumed next index is not 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unique. For instance, if there is no P, then request for P's 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // position actually returns Q's. So we need to look ahead to make 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // sure that there is really a Q at Q's position. If not, move 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // further down... 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextNextSection = nextSection + 1; 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (nextNextSection < nSections && 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextNextSection++; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextSection++; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Compute the beginning and ending scroll range percentage of the 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // currently visible letter. This could be equal to or greater than 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // (1 / nSections). 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float fPrev = (float) prevSection / nSections; 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float fNext = (float) nextSection / nSections; 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prevSection == exactSection && position - fPrev < fThreshold) { 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index = prevIndex; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project / (fNext - fPrev)); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't overflow 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index > count - 1) index = count - 1; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.setSelection(index + mListOffset); 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int index = (int) (position * count); 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mList instanceof ExpandableListView) { 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView expList = (ExpandableListView) mList; 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project expList.setSelectionFromTop(expList.getFlatListPosition( 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mList instanceof ListView) { 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.setSelection(index + mListOffset); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex = -1; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sectionIndex >= 0) { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String text = mSectionText = sections[sectionIndex].toString(); 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') && 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sectionIndex < sections.length; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDrawOverlay = false; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cancelFling() { 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Cancel the list fling 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.onTouchEvent(cancelFling); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling.recycle(); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean onInterceptTouchEvent(MotionEvent ev) { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState > STATE_NONE && ev.getAction() == MotionEvent.ACTION_DOWN) { 41182f3495b146b267f3786997752cef25310176349Romain Guy if (isPointInside(ev.getX(), ev.getY())) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_DRAGGING); 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean onTouchEvent(MotionEvent me) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_NONE) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 42382f3495b146b267f3786997752cef25310176349Romain Guy 42482f3495b146b267f3786997752cef25310176349Romain Guy final int action = me.getAction(); 42582f3495b146b267f3786997752cef25310176349Romain Guy 42682f3495b146b267f3786997752cef25310176349Romain Guy if (action == MotionEvent.ACTION_DOWN) { 42782f3495b146b267f3786997752cef25310176349Romain Guy if (isPointInside(me.getX(), me.getY())) { 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_DRAGGING); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mListAdapter == null && mList != null) { 430d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy getSectionsFromIndexer(); 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 432d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen if (mList != null) { 433d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen mList.requestDisallowInterceptTouchEvent(true); 434d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 435d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelFling(); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 440cd3e4ad4fb526c5f36f64f1d1a39a0b3c5e4c462Marco Nelissen } else if (action == MotionEvent.ACTION_UP) { // don't add ACTION_CANCEL here 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_DRAGGING) { 442d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen if (mList != null) { 443d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen // ViewGroup does the right thing already, but there might 444d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen // be other classes that don't properly reset on touch-up, 445d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen // so do this explicitly just in case. 446d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen mList.requestDisallowInterceptTouchEvent(false); 447d43bd48fe311fa6320e46ca9b9ce25241c476ac6Adam Powell mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 448d43fe07852a23c78da3b51b45469687c20be919aMarco Nelissen } 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_VISIBLE); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Handler handler = mHandler; 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.removeCallbacks(mScrollFade); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.postDelayed(mScrollFade, 1000); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 45582f3495b146b267f3786997752cef25310176349Romain Guy } else if (action == MotionEvent.ACTION_MOVE) { 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mState == STATE_DRAGGING) { 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int viewHeight = mList.getHeight(); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Jitter 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newThumbY = (int) me.getY() - mThumbH + 10; 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newThumbY < 0) { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newThumbY = 0; 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (newThumbY + mThumbH > viewHeight) { 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newThumbY = viewHeight - mThumbH; 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(mThumbY - newThumbY) < 2) { 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbY = newThumbY; 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the previous scrollTo is still pending 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mScrollCompleted) { 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scrollTo((float) mThumbY / (viewHeight - mThumbH)); 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 478d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 47982f3495b146b267f3786997752cef25310176349Romain Guy boolean isPointInside(float x, float y) { 48082f3495b146b267f3786997752cef25310176349Romain Guy return x > mList.getWidth() - mThumbW && y >= mThumbY && y <= mThumbY + mThumbH; 48182f3495b146b267f3786997752cef25310176349Romain Guy } 48282f3495b146b267f3786997752cef25310176349Romain Guy 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class ScrollFade implements Runnable { 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mStartTime; 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mFadeDuration; 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int ALPHA_MAX = 208; 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final long FADE_DURATION = 200; 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void startFade() { 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFadeDuration = FADE_DURATION; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartTime = SystemClock.uptimeMillis(); 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_EXIT); 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int getAlpha() { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getState() != STATE_EXIT) { 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ALPHA_MAX; 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int alpha; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long now = SystemClock.uptimeMillis(); 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (now > mStartTime + mFadeDuration) { 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = 0; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return alpha; 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getState() != STATE_EXIT) { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project startFade(); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getAlpha() > 0) { 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mList.invalidate(); 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setState(STATE_NONE); 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 524