summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2015-03-24 17:33:30 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-03-24 17:33:30 +0000
commitdcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a (patch)
tree6e36274efd690e8a9657f88cb1d0bc3541b600c8
parent10451a967f65c577010d359e1226fd0b5897dbe6 (diff)
parentf819dc2bc782e93ac9ecc163a99af0da62821d31 (diff)
downloadandroid_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.tar.gz
android_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.tar.bz2
android_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.zip
Merge "Making the scrollbar scrubbable." into ub-launcher3-burnaby
-rw-r--r--res/drawable-ldrtl/apps_list_fastscroll_bg.xml27
-rw-r--r--res/drawable/apps_list_scrollbar_thumb.xml2
-rw-r--r--res/layout/apps_list_view.xml5
-rw-r--r--res/values/dimens.xml5
-rw-r--r--src/com/android/launcher3/AppsContainerRecyclerView.java227
-rw-r--r--src/com/android/launcher3/AppsContainerView.java10
6 files changed, 221 insertions, 55 deletions
diff --git a/res/drawable-ldrtl/apps_list_fastscroll_bg.xml b/res/drawable-ldrtl/apps_list_fastscroll_bg.xml
new file mode 100644
index 000000000..772975a71
--- /dev/null
+++ b/res/drawable-ldrtl/apps_list_fastscroll_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/apps_view_scrollbar_thumb_color" />
+ <size
+ android:width="64dp"
+ android:height="64dp" />
+ <corners
+ android:topLeftRadius="64dp"
+ android:topRightRadius="64dp"
+ android:bottomRightRadius="64dp" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/apps_list_scrollbar_thumb.xml b/res/drawable/apps_list_scrollbar_thumb.xml
index 59383a5bb..318d40678 100644
--- a/res/drawable/apps_list_scrollbar_thumb.xml
+++ b/res/drawable/apps_list_scrollbar_thumb.xml
@@ -17,5 +17,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/apps_view_scrollbar_thumb_color" />
- <size android:width="@dimen/apps_view_fast_scroll_bar_size" />
+ <size android:width="@dimen/apps_view_fast_scroll_bar_width" />
</shape> \ No newline at end of file
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index 59c04103f..3e42f8489 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -36,7 +36,7 @@
android:textSize="16sp"
android:textColor="#4c4c4c"
android:textColorHint="#9c9c9c"
- android:imeOptions="flagNoExtractUi"
+ android:imeOptions="actionDone|flagNoExtractUi"
android:background="@drawable/apps_list_search_bg"
android:elevation="4dp" />
<com.android.launcher3.AppsContainerRecyclerView
@@ -47,9 +47,6 @@
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:clipToPadding="false"
- android:fadeScrollbars="false"
- android:scrollbars="vertical"
- android:scrollbarThumbVertical="@drawable/apps_list_scrollbar_thumb"
android:focusable="true"
android:descendantFocusability="afterDescendants"
android:background="@drawable/apps_list_bg" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b9b9a2412..c327ec2d4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -52,8 +52,9 @@
<dimen name="apps_grid_view_start_margin">52dp</dimen>
<dimen name="apps_view_row_height">64dp</dimen>
<dimen name="apps_view_section_text_size">24sp</dimen>
- <dimen name="apps_view_fast_scroll_bar_size">6dp</dimen>
- <dimen name="apps_view_fast_scroll_gutter_size">40dp</dimen>
+ <dimen name="apps_view_fast_scroll_bar_width">6dp</dimen>
+ <dimen name="apps_view_fast_scroll_bar_min_height">64dp</dimen>
+ <dimen name="apps_view_fast_scroll_scrubber_touch_inset">-16dp</dimen>
<dimen name="apps_view_fast_scroll_popup_size">64dp</dimen>
<dimen name="apps_view_fast_scroll_text_size">40dp</dimen>
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index c5a508c9c..4d6b9d412 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
import android.view.ViewConfiguration;
import java.util.List;
@@ -42,7 +43,9 @@ public class AppsContainerRecyclerView extends RecyclerView
private AlphabeticalAppsList mApps;
private int mNumAppsPerRow;
+ private Drawable mScrollbar;
private Drawable mFastScrollerBg;
+ private Rect mVerticalScrollbarBounds = new Rect();
private boolean mDraggingFastScroller;
private String mFastScrollSectionName;
private Paint mFastScrollTextPaint;
@@ -52,7 +55,9 @@ public class AppsContainerRecyclerView extends RecyclerView
private int mDownY;
private int mLastX;
private int mLastY;
- private int mGutterSize;
+ private int mScrollbarWidth;
+ private int mScrollbarMinHeight;
+ private int mScrollbarInset;
public AppsContainerRecyclerView(Context context) {
this(context, null);
@@ -72,14 +77,19 @@ public class AppsContainerRecyclerView extends RecyclerView
Resources res = context.getResources();
int fastScrollerSize = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_popup_size);
- mFastScrollerBg = res.getDrawable(R.drawable.apps_list_fastscroll_bg);
+ mScrollbar = context.getDrawable(R.drawable.apps_list_scrollbar_thumb);
+ mFastScrollerBg = context.getDrawable(R.drawable.apps_list_fastscroll_bg);
mFastScrollerBg.setBounds(0, 0, fastScrollerSize, fastScrollerSize);
mFastScrollTextPaint = new Paint();
mFastScrollTextPaint.setColor(Color.WHITE);
mFastScrollTextPaint.setAntiAlias(true);
mFastScrollTextPaint.setTextSize(res.getDimensionPixelSize(
R.dimen.apps_view_fast_scroll_text_size));
- mGutterSize = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_gutter_size);
+ mScrollbarWidth = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_bar_width);
+ mScrollbarMinHeight =
+ res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_bar_min_height);
+ mScrollbarInset =
+ res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_scrubber_touch_inset);
setFastScrollerAlpha(getFastScrollerAlpha());
}
@@ -112,6 +122,13 @@ public class AppsContainerRecyclerView extends RecyclerView
return mFastScrollAlpha;
}
+ /**
+ * Returns the scroll bar width.
+ */
+ public int getScrollbarWidth() {
+ return mScrollbarWidth;
+ }
+
@Override
protected void onFinishInflate() {
addOnItemTouchListener(this);
@@ -120,38 +137,13 @@ public class AppsContainerRecyclerView extends RecyclerView
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
-
- if (mFastScrollAlpha > 0f) {
- boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
- LAYOUT_DIRECTION_RTL);
- Rect bgBounds = mFastScrollerBg.getBounds();
- int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- int x;
- if (isRtl) {
- x = getPaddingLeft() + getScrollBarSize();
- } else {
- x = getWidth() - getPaddingRight() - getScrollBarSize() - bgBounds.width();
- }
- int y = mLastY - (int) (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * bgBounds.height());
- y = Math.max(getPaddingTop(), Math.min(y, getHeight() - getPaddingBottom() -
- bgBounds.height()));
- canvas.translate(x, y);
- mFastScrollerBg.setAlpha((int) (mFastScrollAlpha * 255));
- mFastScrollerBg.draw(canvas);
- mFastScrollTextPaint.setAlpha((int) (mFastScrollAlpha * 255));
- mFastScrollTextPaint.getTextBounds(mFastScrollSectionName, 0,
- mFastScrollSectionName.length(), mFastScrollTextBounds);
- canvas.drawText(mFastScrollSectionName,
- (bgBounds.width() - mFastScrollTextBounds.width()) / 2,
- bgBounds.height() - (bgBounds.height() - mFastScrollTextBounds.height()) / 2,
- mFastScrollTextPaint);
- canvas.restoreToCount(restoreCount);
- }
+ drawVerticalScrubber(canvas);
+ drawFastScrollerPopup(canvas);
}
/**
* We intercept the touch handling only to support fast scrolling when initiated from the
- * gutter. Otherwise, we fall back to the default RecyclerView touch handling.
+ * scroll bar. Otherwise, we fall back to the default RecyclerView touch handling.
*/
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
@@ -182,15 +174,7 @@ public class AppsContainerRecyclerView extends RecyclerView
break;
case MotionEvent.ACTION_MOVE:
// Check if we are scrolling
- boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
- LAYOUT_DIRECTION_RTL);
- boolean isInGutter;
- if (isRtl) {
- isInGutter = mDownX < mGutterSize;
- } else {
- isInGutter = mDownX >= (getWidth() - mGutterSize);
- }
- if (!mDraggingFastScroller && isInGutter &&
+ if (!mDraggingFastScroller && isPointNearScrollbar(mDownX, mDownY) &&
Math.abs(y - mDownY) > config.getScaledTouchSlop()) {
getParent().requestDisallowInterceptTouchEvent(true);
mDraggingFastScroller = true;
@@ -230,6 +214,67 @@ public class AppsContainerRecyclerView extends RecyclerView
}
/**
+ * Returns whether a given point is near the scrollbar.
+ */
+ private boolean isPointNearScrollbar(int x, int y) {
+ // Check if we are scrolling
+ updateVerticalScrollbarBounds();
+ mVerticalScrollbarBounds.inset(mScrollbarInset, mScrollbarInset);
+ return mVerticalScrollbarBounds.contains(x, y);
+ }
+
+ /**
+ * Draws the fast scroller popup.
+ */
+ private void drawFastScrollerPopup(Canvas canvas) {
+ int x;
+ int y;
+ boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+ LAYOUT_DIRECTION_RTL);
+
+ if (mFastScrollAlpha > 0f) {
+ // Calculate the position for the fast scroller popup
+ Rect bgBounds = mFastScrollerBg.getBounds();
+ if (isRtl) {
+ x = getPaddingLeft() + getScrollBarSize();
+ } else {
+ x = getWidth() - getPaddingRight() - getScrollBarSize() - bgBounds.width();
+ }
+ y = mLastY - (int) (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * bgBounds.height());
+ y = Math.max(getPaddingTop(), Math.min(y, getHeight() - getPaddingBottom() -
+ bgBounds.height()));
+
+ // Draw the fast scroller popup
+ int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.translate(x, y);
+ mFastScrollerBg.setAlpha((int) (mFastScrollAlpha * 255));
+ mFastScrollerBg.draw(canvas);
+ mFastScrollTextPaint.setAlpha((int) (mFastScrollAlpha * 255));
+ mFastScrollTextPaint.getTextBounds(mFastScrollSectionName, 0,
+ mFastScrollSectionName.length(), mFastScrollTextBounds);
+ canvas.drawText(mFastScrollSectionName,
+ (bgBounds.width() - mFastScrollTextBounds.width()) / 2,
+ bgBounds.height() - (bgBounds.height() - mFastScrollTextBounds.height()) / 2,
+ mFastScrollTextPaint);
+ canvas.restoreToCount(restoreCount);
+ }
+ }
+
+ /**
+ * Draws the vertical scrollbar.
+ */
+ private void drawVerticalScrubber(Canvas canvas) {
+ updateVerticalScrollbarBounds();
+
+ // Draw the scroll bar
+ int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.translate(mVerticalScrollbarBounds.left, mVerticalScrollbarBounds.top);
+ mScrollbar.setBounds(0, 0, mScrollbarWidth, mVerticalScrollbarBounds.height());
+ mScrollbar.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+
+ /**
* Invalidates the fast scroller popup.
*/
private void invalidateFastScroller() {
@@ -243,11 +288,7 @@ public class AppsContainerRecyclerView extends RecyclerView
private String scrollToPositionAtProgress(float progress) {
List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections();
// Get the total number of rows
- int rowCount = 0;
- for (AlphabeticalAppsList.SectionInfo info : sections) {
- int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow);
- rowCount += numRowsInSection;
- }
+ int rowCount = getNumRows();
// Find the index of the first app in that row and scroll to that position
int rowAtProgress = (int) (progress * rowCount);
@@ -270,4 +311,100 @@ public class AppsContainerRecyclerView extends RecyclerView
// Returns the section name of the row
return mApps.getSectionNameForApp(appInfo);
}
+
+ /**
+ * Returns the bounds for the scrollbar.
+ */
+ private void updateVerticalScrollbarBounds() {
+ int x;
+ int y;
+ boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+ LAYOUT_DIRECTION_RTL);
+
+ // Skip early if there are no items
+ if (mApps.getApps().isEmpty()) {
+ mVerticalScrollbarBounds.setEmpty();
+ return;
+ }
+
+ // Find the index and height of the first visible row (all rows have the same height)
+ int rowIndex = -1;
+ int rowTopOffset = -1;
+ int rowHeight = -1;
+ int rowCount = getNumRows();
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ int position = getChildPosition(child);
+ if (position != NO_POSITION) {
+ AppInfo info = mApps.getApps().get(position);
+ if (info != AlphabeticalAppsList.SECTION_BREAK_INFO) {
+ int appIndex = mApps.getAppsWithoutSectionBreaks().indexOf(info);
+ rowIndex = findRowForAppIndex(appIndex);
+ rowTopOffset = getLayoutManager().getDecoratedTop(child);
+ rowHeight = child.getHeight();
+ break;
+ }
+ }
+ }
+
+ if (rowIndex != -1) {
+ int height = getHeight() - getPaddingTop() - getPaddingBottom();
+ int totalScrollHeight = rowCount * rowHeight;
+ if (totalScrollHeight > height) {
+ int scrollbarHeight = Math.max(mScrollbarMinHeight,
+ (int) (height / ((float) totalScrollHeight / height)));
+
+ // Calculate the position and size of the scroll bar
+ if (isRtl) {
+ x = getPaddingLeft();
+ } else {
+ x = getWidth() - getPaddingRight() - mScrollbarWidth;
+ }
+
+ // To calculate the offset, we compute the percentage of the total scrollable height
+ // that the user has already scrolled and then map that to the scroll bar bounds
+ int availableY = totalScrollHeight - height;
+ int availableScrollY = height - scrollbarHeight;
+ y = (rowIndex * rowHeight) - rowTopOffset;
+ y = getPaddingTop() +
+ (int) (((float) (getPaddingTop() + y) / availableY) * availableScrollY);
+
+ mVerticalScrollbarBounds.set(x, y, x + mScrollbarWidth, y + scrollbarHeight);
+ return;
+ }
+ }
+ mVerticalScrollbarBounds.setEmpty();
+ }
+
+ /**
+ * Returns the row index for a given position in the list.
+ */
+ private int findRowForAppIndex(int position) {
+ List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections();
+ int appIndex = 0;
+ int rowCount = 0;
+ for (AlphabeticalAppsList.SectionInfo info : sections) {
+ int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow);
+ if (appIndex + info.numAppsInSection > position) {
+ return rowCount + ((position - appIndex) / mNumAppsPerRow);
+ }
+ appIndex += info.numAppsInSection;
+ rowCount += numRowsInSection;
+ }
+ return appIndex;
+ }
+
+ /**
+ * Returns the total number of rows in the list.
+ */
+ private int getNumRows() {
+ List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections();
+ int rowCount = 0;
+ for (AlphabeticalAppsList.SectionInfo info : sections) {
+ int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow);
+ rowCount += numRowsInSection;
+ }
+ return rowCount;
+ }
}
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index ea12fa361..e7b6628cc 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -168,12 +168,16 @@ public class AppsContainerView extends FrameLayout implements DragSource, Insett
mAppsListView.setAdapter(mAdapter);
mAppsListView.setHasFixedSize(true);
if (isRtl) {
- mAppsListView.setPadding(mAppsListView.getPaddingLeft(), mAppsListView.getPaddingTop(),
+ mAppsListView.setPadding(
+ mAppsListView.getPaddingLeft(),
+ mAppsListView.getPaddingTop(),
mAppsListView.getPaddingRight() + mContentMarginStart,
mAppsListView.getPaddingBottom());
} else {
- mAppsListView.setPadding(mAppsListView.getPaddingLeft() + mContentMarginStart,
- mAppsListView.getPaddingTop(), mAppsListView.getPaddingRight(),
+ mAppsListView.setPadding(
+ mAppsListView.getPaddingLeft() + mContentMarginStart,
+ mAppsListView.getPaddingTop(),
+ mAppsListView.getPaddingRight(),
mAppsListView.getPaddingBottom());
}
if (mItemDecoration != null) {