summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2017-06-23 16:12:50 -0700
committerSunny Goyal <sunnygoyal@google.com>2017-06-26 14:56:36 -0700
commit89d5c5a31bd6cf4caf815b680ec670896b91803d (patch)
treeb9d0a9a9fd6dec880fb6076bc2b8d4f38870839f
parentbbe504d24d5e0757d1a7772af822b7a6e274c9b4 (diff)
downloadandroid_packages_apps_Trebuchet-89d5c5a31bd6cf4caf815b680ec670896b91803d.tar.gz
android_packages_apps_Trebuchet-89d5c5a31bd6cf4caf815b680ec670896b91803d.tar.bz2
android_packages_apps_Trebuchet-89d5c5a31bd6cf4caf815b680ec670896b91803d.zip
Updating fast scrollbar UI in Landscape
Creating a separate view for FastScrollBar and moving all the relavant logic in the view. For protrait, the touch handling is delegated by the recycler view just like before. For landscape, the dcrollbar does not overlay with recyclerView and handles the touch itself Bug: 37015359 Change-Id: Ie1981326457ba739bdf0ac8063db1065f395f133
-rw-r--r--res/layout-land/all_apps_fast_scroller.xml38
-rw-r--r--res/layout-sw720dp/all_apps_fast_scroller.xml37
-rw-r--r--res/layout/all_apps.xml15
-rw-r--r--res/layout/all_apps_fast_scroller.xml37
-rw-r--r--res/layout/all_apps_search_container.xml28
-rw-r--r--res/layout/all_apps_search_divider.xml25
-rw-r--r--res/layout/widgets_view.xml25
-rw-r--r--res/values/attrs.xml4
-rw-r--r--res/values/dimens.xml10
-rw-r--r--src/com/android/launcher3/BaseRecyclerView.java116
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java12
-rw-r--r--src/com/android/launcher3/allapps/AllAppsGridAdapter.java14
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerView.java10
-rw-r--r--src/com/android/launcher3/allapps/AlphabeticalAppsList.java18
-rw-r--r--src/com/android/launcher3/allapps/LandscapeFastScroller.java63
-rw-r--r--src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java12
-rw-r--r--src/com/android/launcher3/allapps/search/HeaderElevationController.java32
-rw-r--r--src/com/android/launcher3/views/RecyclerViewFastScroller.java (renamed from src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java)204
18 files changed, 427 insertions, 273 deletions
diff --git a/res/layout-land/all_apps_fast_scroller.xml b/res/layout-land/all_apps_fast_scroller.xml
new file mode 100644
index 000000000..957c33174
--- /dev/null
+++ b/res/layout-land/all_apps_fast_scroller.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <!-- Fast scroller popup -->
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="-5dp" />
+
+ <com.android.launcher3.allapps.LandscapeFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="-48dp"
+ android:layout_marginTop="-8dp"
+ launcher:canThumbDetach="true" />
+
+</merge> \ No newline at end of file
diff --git a/res/layout-sw720dp/all_apps_fast_scroller.xml b/res/layout-sw720dp/all_apps_fast_scroller.xml
new file mode 100644
index 000000000..12c15cca9
--- /dev/null
+++ b/res/layout-sw720dp/all_apps_fast_scroller.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <!-- Fast scroller popup -->
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin"
+ launcher:canThumbDetach="true" />
+
+</merge> \ No newline at end of file
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index a3c253537..93662fc08 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -16,7 +16,8 @@
<!-- The top and bottom paddings are defined in this container, but since we want
the list view to span the full width (for touch interception purposes), we
will bake the left/right padding into that view's background itself. -->
-<com.android.launcher3.allapps.AllAppsContainerView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.allapps.AllAppsContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/apps_view"
android:layout_width="match_parent"
@@ -39,6 +40,8 @@
android:layout_height="match_parent"
android:layout_gravity="center"
android:focusable="true"
+ android:clipToPadding="false"
+ android:clipChildren="true"
android:focusableInTouchMode="true"
android:saveEnabled="false"
android:visibility="gone">
@@ -55,20 +58,14 @@
android:descendantFocusability="afterDescendants"
android:focusable="true" />
- <!-- Fast scroller popup -->
- <TextView
- style="@style/FastScrollerPopup"
- android:layout_alignTop="@+id/apps_list_view"
- android:id="@+id/fast_scroller_popup"
- android:layout_alignParentEnd="true"
- android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
-
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag -->
<include
layout="?android:attr/keyboardLayout"
android:id="@+id/search_container" />
+ <include layout="@layout/all_apps_fast_scroller" />
+
</com.android.launcher3.allapps.AllAppsRecyclerViewContainerView>
<View
style="@style/AllAppsNavBarProtection"
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
new file mode 100644
index 000000000..12c15cca9
--- /dev/null
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <!-- Fast scroller popup -->
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/apps_list_view"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin"
+ launcher:canThumbDetach="true" />
+
+</merge> \ No newline at end of file
diff --git a/res/layout/all_apps_search_container.xml b/res/layout/all_apps_search_container.xml
index c79360f66..2528034eb 100644
--- a/res/layout/all_apps_search_container.xml
+++ b/res/layout/all_apps_search_container.xml
@@ -20,13 +20,24 @@
android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_gravity="center|top"
android:gravity="center|bottom"
- android:saveEnabled="false">
+ android:saveEnabled="false"
+ android:paddingLeft="@dimen/dynamic_grid_edge_margin"
+ android:paddingRight="@dimen/dynamic_grid_edge_margin"
+ android:layout_marginBottom="-8dp" >
+ <!--
+ Note: The following relation should always be true so that the shadows are aligned properly
+ search_box_input.layout_marginBottom
+ == search_divider.layout_marginBottom
+ == - (search_container.layout_marginBottom)
+ >= 5dp
+ -->
<com.android.launcher3.ExtendedEditText
android:id="@+id/search_box_input"
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_search_bar_field_height"
android:layout_gravity="bottom"
+ android:layout_marginBottom="8dp"
android:background="@android:color/transparent"
android:focusableInTouchMode="true"
android:gravity="center"
@@ -39,4 +50,19 @@
android:textColor="?android:attr/textColorSecondary"
android:textColorHint="@drawable/all_apps_search_hint"
android:textSize="16sp" />
+
+ <!-- This needs to be a container with a view, to simulate a scrolling effect for the header.
+ We translate the header down, and its content up by the same amount, so that it gets
+ clipped by the parent, making it look like the divider was scrolled out of the view. -->
+ <FrameLayout
+ android:id="@+id/search_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_gravity="bottom"
+ android:layout_marginBottom="8dp" >
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@drawable/all_apps_search_divider"/>
+ </FrameLayout>
</com.android.launcher3.allapps.search.AppsSearchContainerLayout> \ No newline at end of file
diff --git a/res/layout/all_apps_search_divider.xml b/res/layout/all_apps_search_divider.xml
deleted file mode 100644
index c052c6635..000000000
--- a/res/layout/all_apps_search_divider.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
--->
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:importantForAccessibility="no"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="@dimen/all_apps_divider_margin_vertical"
- android:paddingLeft="@dimen/dynamic_grid_edge_margin"
- android:paddingRight="@dimen/dynamic_grid_edge_margin"
- android:src="@drawable/all_apps_search_divider"
- android:scaleType="fitXY"
- android:focusable="false" /> \ No newline at end of file
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 558556ad8..4f3c7c8df 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -23,25 +23,25 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="afterDescendants"
- launcher:revealBackground="@drawable/round_rect_primary"
- android:theme="?attr/widgetsTheme">
+ android:theme="?attr/widgetsTheme"
+ launcher:revealBackground="@drawable/round_rect_primary">
<View
android:id="@+id/reveal_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:focusable="false"
android:elevation="2dp"
+ android:focusable="false"
android:visibility="invisible" />
<FrameLayout
android:id="@+id/main_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:layout_gravity="center"
android:elevation="15dp"
- android:visibility="gone"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:visibility="gone">
<com.android.launcher3.widget.WidgetsRecyclerView
android:id="@+id/widgets_list_view"
@@ -50,17 +50,24 @@
<!-- Fast scroller popup -->
<TextView
- style="@style/FastScrollerPopup"
android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
android:layout_gravity="top|end"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<ProgressBar
+ android:id="@+id/loader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/loader"
android:layout_gravity="center" />
- </FrameLayout>
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+
+ </FrameLayout>
</com.android.launcher3.widget.WidgetsContainerView> \ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 3839eb130..7b52dae5d 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -138,4 +138,8 @@
<attr name="android:elevation" />
<attr name="darkTintColor" format="color"/>
</declare-styleable>
+
+ <declare-styleable name="RecyclerViewFastScroller">
+ <attr name="canThumbDetach" format="boolean" />
+ </declare-styleable>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 71f9edc91..a4dff7190 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -65,7 +65,15 @@
<dimen name="fastscroll_popup_text_size">32dp</dimen>
<dimen name="fastscroll_popup_margin">19dp</dimen>
-<!-- All Apps -->
+ <!--
+ Fast scroller draws the content horizontally centered. The end of the track should be
+ aligned at the end of the container.
+ fastscroll_end_margin = - (fastscroll_width - fastscroll_track_min_width) / 2
+ -->
+ <dimen name="fastscroll_width">58dp</dimen>
+ <dimen name="fastscroll_end_margin">-26dp</dimen>
+
+ <!-- All Apps -->
<dimen name="all_apps_button_scale_down">0dp</dimen>
<dimen name="all_apps_search_bar_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_height">60dp</dimen>
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 84358ea37..3ee6e51b8 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -22,8 +22,9 @@ import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
+import android.widget.TextView;
-import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.RecyclerViewFastScroller;
/**
@@ -36,19 +37,7 @@ import com.android.launcher3.util.Thunk;
public abstract class BaseRecyclerView extends RecyclerView
implements RecyclerView.OnItemTouchListener {
- private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
-
- /** Keeps the last known scrolling delta/velocity along y-axis. */
- @Thunk int mDy = 0;
- private float mDeltaThreshold;
-
- protected final BaseRecyclerViewFastScrollBar mScrollbar;
-
- private int mDownX;
- private int mDownY;
- private int mLastY;
-
- private boolean mScrollBarVisible = true;
+ protected RecyclerViewFastScroller mScrollbar;
public BaseRecyclerView(Context context) {
this(context, null);
@@ -60,28 +49,6 @@ public abstract class BaseRecyclerView extends RecyclerView
public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mDeltaThreshold = getResources().getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
- mScrollbar = new BaseRecyclerViewFastScrollBar(this, getResources());
-
- ScrollListener listener = new ScrollListener();
- setOnScrollListener(listener);
- }
-
- private class ScrollListener extends OnScrollListener {
- public ScrollListener() {
- // Do nothing
- }
-
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- mDy = dy;
-
- // TODO(winsonc): If we want to animate the section heads while scrolling, we can
- // initiate that here if the recycler view scroll state is not
- // RecyclerView.SCROLL_STATE_IDLE.
-
- onUpdateScrollbar(dy);
- }
}
@Override
@@ -93,7 +60,9 @@ public abstract class BaseRecyclerView extends RecyclerView
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mScrollbar.setPopupView(((ViewGroup) getParent()).findViewById(R.id.fast_scroller_popup));
+ ViewGroup parent = (ViewGroup) getParent();
+ mScrollbar = parent.findViewById(R.id.fast_scroller);
+ mScrollbar.setRecyclerView(this, (TextView) parent.findViewById(R.id.fast_scroller_popup));
}
/**
@@ -115,32 +84,15 @@ public abstract class BaseRecyclerView extends RecyclerView
* it is already showing).
*/
private boolean handleTouchEvent(MotionEvent ev) {
- ev.offsetLocation(0, -getPaddingTop());
- int action = ev.getAction();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- // Keep track of the down positions
- mDownX = x;
- mDownY = mLastY = y;
- if (shouldStopScroll(ev)) {
- stopScroll();
- }
- mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
- break;
- case MotionEvent.ACTION_MOVE:
- mLastY = y;
- mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- onFastScrollCompleted();
- mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
- break;
+ // Move to mScrollbar's coordinate system.
+ int left = getLeft() - mScrollbar.getLeft();
+ int top = getTop() - mScrollbar.getTop();
+ ev.offsetLocation(left, top);
+ try {
+ return mScrollbar.handleTouchEvent(ev);
+ } finally {
+ ev.offsetLocation(-left, -top);
}
- ev.offsetLocation(0, getPaddingTop());
- return mScrollbar.isDraggingThumb();
}
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
@@ -148,24 +100,9 @@ public abstract class BaseRecyclerView extends RecyclerView
}
/**
- * Returns whether this {@link MotionEvent} should trigger the scroll to be stopped.
- */
- protected boolean shouldStopScroll(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if ((Math.abs(mDy) < mDeltaThreshold &&
- getScrollState() != RecyclerView.SCROLL_STATE_IDLE)) {
- // now the touch events are being passed to the {@link WidgetCell} until the
- // touch sequence goes over the touch slop.
- return true;
- }
- }
- return false;
- }
-
- /**
* Returns the height of the fast scroll bar
*/
- protected int getScrollbarTrackHeight() {
+ public int getScrollbarTrackHeight() {
return getHeight() - getPaddingTop() - getPaddingBottom();
}
@@ -187,25 +124,14 @@ public abstract class BaseRecyclerView extends RecyclerView
/**
* Returns the scrollbar for this recycler view.
*/
- public BaseRecyclerViewFastScrollBar getScrollBar() {
+ public RecyclerViewFastScroller getScrollBar() {
return mScrollbar;
}
@Override
protected void dispatchDraw(Canvas canvas) {
+ onUpdateScrollbar(0);
super.dispatchDraw(canvas);
- if (mScrollBarVisible) {
- onUpdateScrollbar(0);
- mScrollbar.draw(canvas);
- }
- }
-
- /**
- * Sets the scrollbar visibility. The call does not refresh the UI, its the responsibility
- * of the caller to call {@link #invalidate()}.
- */
- public void setScrollBarVisible(boolean visible) {
- mScrollBarVisible = visible;
}
/**
@@ -236,7 +162,7 @@ public abstract class BaseRecyclerView extends RecyclerView
/**
* @return whether fast scrolling is supported in the current state.
*/
- protected boolean supportsFastScrolling() {
+ public boolean supportsFastScrolling() {
return true;
}
@@ -252,16 +178,16 @@ public abstract class BaseRecyclerView extends RecyclerView
* Maps the touch (from 0..1) to the adapter position that should be visible.
* <p>Override in each subclass of this base class.
*/
- protected abstract String scrollToPositionAtProgress(float touchFraction);
+ public abstract String scrollToPositionAtProgress(float touchFraction);
/**
* Updates the bounds for the scrollbar.
* <p>Override in each subclass of this base class.
*/
- protected abstract void onUpdateScrollbar(int dy);
+ public abstract void onUpdateScrollbar(int dy);
/**
* <p>Override in each subclass of this base class.
*/
- protected void onFastScrollCompleted() {}
+ public void onFastScrollCompleted() {}
} \ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 4954e0c44..47b68a2ee 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -171,19 +171,19 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* Returns whether the view itself will handle the touch event or not.
*/
public boolean shouldContainerScroll(MotionEvent ev) {
- int[] point = new int[2];
- point[0] = (int) ev.getX();
- point[1] = (int) ev.getY();
- Utilities.mapCoordInSelfToDescendant(mAppsRecyclerView, this, point);
-
// IF the MotionEvent is inside the search box, and the container keeps on receiving
// touch input, container should move down.
if (mLauncher.getDragLayer().isEventOverView(mSearchContainer, ev)) {
return true;
}
+ int[] point = new int[2];
+ point[0] = (int) ev.getX();
+ point[1] = (int) ev.getY();
+ Utilities.mapCoordInSelfToDescendant(
+ mAppsRecyclerView.getScrollBar(), mLauncher.getDragLayer(), point);
// IF the MotionEvent is inside the thumb, container should not be pulled down.
- if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])) {
+ if (mAppsRecyclerView.getScrollBar().shouldBlockIntercept(point[0], point[1])) {
return false;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index d6514a83f..1054a5633 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -69,16 +69,13 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
// A divider that separates the apps list and the search market button
public static final int VIEW_TYPE_SEARCH_MARKET_DIVIDER = 1 << 5;
- // The divider under the search field
- public static final int VIEW_TYPE_SEARCH_DIVIDER = 1 << 6;
// The divider that separates prediction icons from the app list
- public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 7;
- public static final int VIEW_TYPE_APPS_LOADING_DIVIDER = 1 << 8;
- public static final int VIEW_TYPE_DISCOVERY_ITEM = 1 << 9;
+ public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 6;
+ public static final int VIEW_TYPE_APPS_LOADING_DIVIDER = 1 << 7;
+ public static final int VIEW_TYPE_DISCOVERY_ITEM = 1 << 8;
// Common view type masks
- public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_DIVIDER
- | VIEW_TYPE_SEARCH_MARKET_DIVIDER
+ public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_MARKET_DIVIDER
| VIEW_TYPE_PREDICTION_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
| VIEW_TYPE_PREDICTION_ICON;
@@ -319,9 +316,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
}
});
return new ViewHolder(searchMarketView);
- case VIEW_TYPE_SEARCH_DIVIDER:
- return new ViewHolder(mLayoutInflater.inflate(
- R.layout.all_apps_search_divider, parent, false));
case VIEW_TYPE_APPS_LOADING_DIVIDER:
View loadingDividerView = mLayoutInflater.inflate(
R.layout.all_apps_discovery_loading_divider, parent, false);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 0607a1e5d..2b2fddcdd 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -72,7 +72,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
super(context, attrs, defStyleAttr);
Resources res = getResources();
addOnItemTouchListener(this);
- mScrollbar.setDetachThumbOnFastScroll();
mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
R.dimen.all_apps_empty_search_bg_top_offset);
}
@@ -110,7 +109,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
RecyclerView.RecycledViewPool pool = getRecycledViewPool();
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
- pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
@@ -137,8 +135,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER,
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER);
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
- AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER);
- putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET);
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH);
@@ -164,7 +160,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
*/
public void scrollToTop() {
// Ensure we reattach the scrollbar if it was previously detached while fast-scrolling
- mScrollbar.reattachThumbToScroll();
+ if (mScrollbar != null) {
+ mScrollbar.reattachThumbToScroll();
+ }
scrollToPosition(0);
}
@@ -356,7 +354,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
}
@Override
- protected boolean supportsFastScrolling() {
+ public boolean supportsFastScrolling() {
// Only allow fast scrolling when the user is not searching, since the results are not
// grouped in a meaningful order
return !mApps.hasFilter();
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 7bf66510a..608e898ae 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -138,13 +138,6 @@ public class AlphabeticalAppsList {
return item;
}
- public static AdapterItem asSearchDivider(int pos) {
- AdapterItem item = new AdapterItem();
- item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER;
- item.position = pos;
- return item;
- }
-
public static AdapterItem asMarketDivider(int pos) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER;
@@ -195,8 +188,6 @@ public class AlphabeticalAppsList {
private int mNumPredictedAppsPerRow;
private int mNumAppRowsInAdapter;
- private boolean mHasSearchDivider = true;
-
public AlphabeticalAppsList(Context context) {
mLauncher = Launcher.getLauncher(context);
mIndexer = new AlphabeticIndexCompat(context);
@@ -352,10 +343,6 @@ public class AlphabeticalAppsList {
onAppsUpdated();
}
- public void disableSearchDivider() {
- mHasSearchDivider = false;
- }
-
/**
* Updates internals when the set of apps are updated.
*/
@@ -442,11 +429,6 @@ public class AlphabeticalAppsList {
}
}
- if (mHasSearchDivider) {
- // Add the search divider
- mAdapterItems.add(AdapterItem.asSearchDivider(position++));
- }
-
// Process the predicted app components
mPredictedApps.clear();
if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
diff --git a/src/com/android/launcher3/allapps/LandscapeFastScroller.java b/src/com/android/launcher3/allapps/LandscapeFastScroller.java
new file mode 100644
index 000000000..cdde65760
--- /dev/null
+++ b/src/com/android/launcher3/allapps/LandscapeFastScroller.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.launcher3.views.RecyclerViewFastScroller;
+
+/**
+ * Extension of {@link RecyclerViewFastScroller} to be used in landscape layout.
+ */
+public class LandscapeFastScroller extends RecyclerViewFastScroller {
+
+ public LandscapeFastScroller(Context context) {
+ super(context);
+ }
+
+ public LandscapeFastScroller(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LandscapeFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public boolean handleTouchEvent(MotionEvent ev) {
+ // We handle our own touch event, no need to handle recycler view touch delegates.
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ event.offsetLocation(0, -mRv.getPaddingTop());
+ if (super.handleTouchEvent(event)) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ event.offsetLocation(0, mRv.getPaddingTop());
+ return true;
+ }
+
+ @Override
+ public boolean shouldBlockIntercept(int x, int y) {
+ // If the user touched the scroll bar area, block swipe
+ return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
+ }
+}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 3f06ec9dd..5cb12d592 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -54,12 +54,13 @@ public class AppsSearchContainerLayout extends FrameLayout
private final int mSearchBoxHeight;
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
- private final HeaderElevationController mElevationController;
private ExtendedEditText mSearchInput;
private AlphabeticalAppsList mApps;
private AllAppsRecyclerView mAppsRecyclerView;
private AllAppsGridAdapter mAdapter;
+ private View mDivider;
+ private HeaderElevationController mElevationController;
public AppsSearchContainerLayout(Context context) {
this(context, null);
@@ -77,7 +78,6 @@ public class AppsSearchContainerLayout extends FrameLayout
mSearchBoxHeight = getResources()
.getDimensionPixelSize(R.dimen.all_apps_search_bar_field_height);
mSearchBarController = new AllAppsSearchBarController();
- mElevationController = new HeaderElevationController(this);
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
@@ -87,6 +87,8 @@ public class AppsSearchContainerLayout extends FrameLayout
protected void onFinishInflate() {
super.onFinishInflate();
mSearchInput = findViewById(R.id.search_box_input);
+ mDivider = findViewById(R.id.search_divider);
+ mElevationController = new HeaderElevationController(mDivider);
// Update the hint to contain the icon.
// Prefix the original hint with two spaces. The first space gets replaced by the icon
@@ -96,6 +98,12 @@ public class AppsSearchContainerLayout extends FrameLayout
spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search),
0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
mSearchInput.setHint(spanned);
+
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ if (!dp.isVerticalBarLayout()) {
+ LayoutParams lp = (LayoutParams) mDivider.getLayoutParams();
+ lp.leftMargin = lp.rightMargin = dp.edgeMarginPx;
+ }
}
@Override
diff --git a/src/com/android/launcher3/allapps/search/HeaderElevationController.java b/src/com/android/launcher3/allapps/search/HeaderElevationController.java
index ab4e88fc8..7cd32b26e 100644
--- a/src/com/android/launcher3/allapps/search/HeaderElevationController.java
+++ b/src/com/android/launcher3/allapps/search/HeaderElevationController.java
@@ -4,11 +4,11 @@ import android.content.res.Resources;
import android.graphics.Outline;
import android.support.v7.widget.RecyclerView;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
/**
* Helper class for controlling the header elevation in response to RecyclerView scroll.
@@ -16,6 +16,7 @@ import com.android.launcher3.Utilities;
public class HeaderElevationController extends RecyclerView.OnScrollListener {
private final View mHeader;
+ private final View mHeaderChild;
private final float mMaxElevation;
private final float mScrollToElevation;
@@ -28,23 +29,27 @@ public class HeaderElevationController extends RecyclerView.OnScrollListener {
mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
// We need to provide a custom outline so the shadow only appears on the bottom edge.
- // The top, left and right edges are all extended out, and the shadow is clipped
- // by the parent.
+ // The top, left and right edges are all extended out to match parent's edge, so that
+ // the shadow is clipped by the parent.
final ViewOutlineProvider vop = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- final View parent = (View) mHeader.getParent();
+ // Set the left and top to be at the parents edge. Since the coordinates are
+ // relative to this view,
+ // (x = -view.getLeft()) for this view => (x = 0) for parent
+ final int left = -view.getLeft();
+ final int top = -view.getTop();
- final int left = parent.getLeft(); // Use the parent to account for offsets
- final int top = view.getTop();
- final int right = left + view.getWidth();
- final int bottom = view.getBottom();
-
- final int offset = Utilities.pxFromDp(mMaxElevation, res.getDisplayMetrics());
+ // Since the view is centered align, the spacing on left and right are same.
+ // Add same spacing on the right to reach parent's edge.
+ final int right = view.getWidth() - left;
+ final int bottom = view.getHeight();
+ final int offset = (int) mMaxElevation;
outline.setRect(left - offset, top - offset, right + offset, bottom);
}
};
mHeader.setOutlineProvider(vop);
+ mHeaderChild = ((ViewGroup) mHeader).getChildAt(0);
}
public void reset() {
@@ -63,6 +68,13 @@ public class HeaderElevationController extends RecyclerView.OnScrollListener {
float newElevation = mMaxElevation * elevationPct;
if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
mHeader.setElevation(newElevation);
+
+ // To simulate a scrolling effect for the header, we translate the header down, and
+ // its content up by the same amount, so that it gets clipped by the parent, making it
+ // look like the content was scrolled out of the view.
+ int shift = Math.min(mHeader.getHeight(), scrollY);
+ mHeader.setTranslationY(-shift);
+ mHeaderChild.setTranslationY(shift);
}
}
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 9e8d300ae..7b5bcdbd4 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -13,21 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3;
+
+package com.android.launcher3.views;
import android.animation.ObjectAnimator;
+import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.TextView;
+import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
import com.android.launcher3.util.Themes;
@@ -35,18 +40,20 @@ import com.android.launcher3.util.Themes;
/**
* The track and scrollbar that shows when you scroll the list.
*/
-public class BaseRecyclerViewFastScrollBar {
+public class RecyclerViewFastScroller extends View {
+
+ private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
- private static final Property<BaseRecyclerViewFastScrollBar, Integer> TRACK_WIDTH =
- new Property<BaseRecyclerViewFastScrollBar, Integer>(Integer.class, "width") {
+ private static final Property<RecyclerViewFastScroller, Integer> TRACK_WIDTH =
+ new Property<RecyclerViewFastScroller, Integer>(Integer.class, "width") {
@Override
- public Integer get(BaseRecyclerViewFastScrollBar scrollBar) {
+ public Integer get(RecyclerViewFastScroller scrollBar) {
return scrollBar.mWidth;
}
@Override
- public void set(BaseRecyclerViewFastScrollBar scrollBar, Integer value) {
+ public void set(RecyclerViewFastScroller scrollBar, Integer value) {
scrollBar.setTrackWidth(value);
}
};
@@ -55,93 +62,113 @@ public class BaseRecyclerViewFastScrollBar {
private final static int SCROLL_BAR_VIS_DURATION = 150;
private static final float FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR = 0.75f;
- private final Rect mTmpRect = new Rect();
- private final BaseRecyclerView mRv;
-
- private final boolean mIsRtl;
-
- // The inset is the buffer around which a point will still register as a click on the scrollbar
- private final int mTouchInset;
-
private final int mMinWidth;
private final int mMaxWidth;
private final int mThumbPadding;
+ /** Keeps the last known scrolling delta/velocity along y-axis. */
+ private int mDy = 0;
+ private final float mDeltaThreshold;
+
+ private final ViewConfiguration mConfig;
+
// Current width of the track
private int mWidth;
private ObjectAnimator mWidthAnimator;
private final Paint mThumbPaint;
- private final int mThumbHeight;
+ protected final int mThumbHeight;
private final Paint mTrackPaint;
private float mLastTouchY;
private boolean mIsDragging;
private boolean mIsThumbDetached;
- private boolean mCanThumbDetach;
+ private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
// This is the offset from the top of the scrollbar when the user first starts touching. To
// prevent jumping, this offset is applied as the user scrolls.
- private int mTouchOffsetY;
- private int mThumbOffsetY;
+ protected int mTouchOffsetY;
+ protected int mThumbOffsetY;
// Fast scroller popup
private TextView mPopupView;
private boolean mPopupVisible;
private String mPopupSectionName;
- public BaseRecyclerViewFastScrollBar(BaseRecyclerView rv, Resources res) {
- mRv = rv;
+ protected BaseRecyclerView mRv;
+
+ private int mDownX;
+ private int mDownY;
+ private int mLastY;
+
+ public RecyclerViewFastScroller(Context context) {
+ this(context, null);
+ }
+
+ public RecyclerViewFastScroller(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RecyclerViewFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
mTrackPaint = new Paint();
- mTrackPaint.setColor(Themes.getAttrColor(rv.getContext(), android.R.attr.textColorPrimary));
+ mTrackPaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
mTrackPaint.setAlpha(MAX_TRACK_ALPHA);
mThumbPaint = new Paint();
mThumbPaint.setAntiAlias(true);
- mThumbPaint.setColor(Themes.getColorAccent(rv.getContext()));
+ mThumbPaint.setColor(Themes.getColorAccent(context));
mThumbPaint.setStyle(Paint.Style.FILL);
+ Resources res = getResources();
mWidth = mMinWidth = res.getDimensionPixelSize(R.dimen.fastscroll_track_min_width);
mMaxWidth = res.getDimensionPixelSize(R.dimen.fastscroll_track_max_width);
mThumbPadding = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_padding);
mThumbHeight = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height);
- mTouchInset = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_touch_inset);
- mIsRtl = Utilities.isRtl(res);
- }
+ mConfig = ViewConfiguration.get(context);
+ mDeltaThreshold = res.getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
- public void setPopupView(View popup) {
- mPopupView = (TextView) popup;
- mPopupView.setBackground(new FastScrollThumbDrawable(mThumbPaint, mIsRtl));
+ TypedArray ta =
+ context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewFastScroller, defStyleAttr, 0);
+ mCanThumbDetach = ta.getBoolean(R.styleable.RecyclerViewFastScroller_canThumbDetach, false);
+ ta.recycle();
}
- public void setDetachThumbOnFastScroll() {
- mCanThumbDetach = true;
+ public void setRecyclerView(BaseRecyclerView rv, TextView popupView) {
+ mRv = rv;
+ mRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ mDy = dy;
+
+ // TODO(winsonc): If we want to animate the section heads while scrolling, we can
+ // initiate that here if the recycler view scroll state is not
+ // RecyclerView.SCROLL_STATE_IDLE.
+
+ mRv.onUpdateScrollbar(dy);
+ }
+ });
+
+ mPopupView = popupView;
+ mPopupView.setBackground(
+ new FastScrollThumbDrawable(mThumbPaint, Utilities.isRtl(getResources())));
}
public void reattachThumbToScroll() {
mIsThumbDetached = false;
}
- private int getDrawLeft() {
- return mIsRtl ? 0 : (mRv.getWidth() - mMaxWidth);
- }
-
public void setThumbOffsetY(int y) {
if (mThumbOffsetY == y) {
return;
}
-
- // Invalidate the previous and new thumb area
- int drawLeft = getDrawLeft();
- mTmpRect.set(drawLeft, mThumbOffsetY, drawLeft + mMaxWidth, mThumbOffsetY + mThumbHeight);
mThumbOffsetY = y;
- mTmpRect.union(drawLeft, mThumbOffsetY, drawLeft + mMaxWidth, mThumbOffsetY + mThumbHeight);
- mTmpRect.offset(0, mRv.getPaddingTop());
- mRv.invalidate(mTmpRect);
+ invalidate();
}
public int getThumbOffsetY() {
@@ -152,12 +179,8 @@ public class BaseRecyclerViewFastScrollBar {
if (mWidth == width) {
return;
}
- int left = getDrawLeft();
- int top = mRv.getPaddingTop();
- // Invalidate the whole scroll bar area.
- mRv.invalidate(left, top, left + mMaxWidth, top + mRv.getScrollbarTrackHeight());
-
mWidth = width;
+ invalidate();
}
public int getThumbHeight() {
@@ -176,37 +199,48 @@ public class BaseRecyclerViewFastScrollBar {
* Handles the touch event and determines whether to show the fast scroller (or updates it if
* it is already showing).
*/
- public void handleTouchEvent(MotionEvent ev, int downX, int downY, int lastY) {
- ViewConfiguration config = ViewConfiguration.get(mRv.getContext());
-
- int action = ev.getAction();
+ public boolean handleTouchEvent(MotionEvent ev) {
+ int x = (int) ev.getX();
int y = (int) ev.getY();
- switch (action) {
+ switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
- if (isNearThumb(downX, downY)) {
- mTouchOffsetY = downY - mThumbOffsetY;
+ // Keep track of the down positions
+ mDownX = x;
+ mDownY = mLastY = y;
+
+ if ((Math.abs(mDy) < mDeltaThreshold &&
+ mRv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE)) {
+ // now the touch events are being passed to the {@link WidgetCell} until the
+ // touch sequence goes over the touch slop.
+ mRv.stopScroll();
+ }
+ if (isNearThumb(x, y)) {
+ mTouchOffsetY = mDownY - mThumbOffsetY;
} else if (FeatureFlags.LAUNCHER3_DIRECT_SCROLL
&& mRv.supportsFastScrolling()
- && isNearScrollBar(downX)) {
- calcTouchOffsetAndPrepToFastScroll(downY, lastY);
- updateFastScrollSectionNameAndThumbOffset(lastY, y);
+ && isNearScrollBar(mDownX)) {
+ calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY);
+ updateFastScrollSectionNameAndThumbOffset(mLastY, y);
}
break;
case MotionEvent.ACTION_MOVE:
+ mLastY = y;
+
// Check if we should start scrolling, but ignore this fastscroll gesture if we have
// exceeded some fixed movement
- mIgnoreDragGesture |= Math.abs(y - downY) > config.getScaledPagingTouchSlop();
+ mIgnoreDragGesture |= Math.abs(y - mDownY) > mConfig.getScaledPagingTouchSlop();
if (!mIsDragging && !mIgnoreDragGesture && mRv.supportsFastScrolling() &&
- isNearThumb(downX, lastY) &&
- Math.abs(y - downY) > config.getScaledTouchSlop()) {
- calcTouchOffsetAndPrepToFastScroll(downY, lastY);
+ isNearThumb(mDownX, mLastY) &&
+ Math.abs(y - mDownY) > mConfig.getScaledTouchSlop()) {
+ calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY);
}
if (mIsDragging) {
- updateFastScrollSectionNameAndThumbOffset(lastY, y);
+ updateFastScrollSectionNameAndThumbOffset(mLastY, y);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mRv.onFastScrollCompleted();
mTouchOffsetY = 0;
mLastTouchY = 0;
mIgnoreDragGesture = false;
@@ -217,6 +251,7 @@ public class BaseRecyclerViewFastScrollBar {
}
break;
}
+ return mIsDragging;
}
private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
@@ -245,25 +280,25 @@ public class BaseRecyclerViewFastScrollBar {
setThumbOffsetY((int) mLastTouchY);
}
- public void draw(Canvas canvas) {
+ public void onDraw(Canvas canvas) {
if (mThumbOffsetY < 0) {
return;
}
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- if (!mIsRtl) {
- canvas.translate(mRv.getWidth() - mWidth, 0);
- }
- canvas.translate(0, mRv.getPaddingTop());
+ canvas.translate(getWidth() / 2, mRv.getPaddingTop());
// Draw the track
- canvas.drawRoundRect(0, 0, mWidth, mRv.getScrollbarTrackHeight(),
+ float halfW = mWidth / 2;
+ canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
mWidth, mWidth, mTrackPaint);
- canvas.translate(-mThumbPadding, mThumbOffsetY);
+ canvas.translate(0, mThumbOffsetY);
+ halfW += mThumbPadding;
float r = mWidth + mThumbPadding + mThumbPadding;
- canvas.drawRoundRect(0, 0, r, mThumbHeight, r, r, mThumbPaint);
+ canvas.drawRoundRect(-halfW, 0, halfW, mThumbHeight, r, r, mThumbPaint);
canvas.restoreToCount(saveCount);
}
+
/**
* Animates the width of the scrollbar.
*/
@@ -281,19 +316,25 @@ public class BaseRecyclerViewFastScrollBar {
/**
* Returns whether the specified point is inside the thumb bounds.
*/
- public boolean isNearThumb(int x, int y) {
- int left = getDrawLeft();
- mTmpRect.set(left, mThumbOffsetY, left + mMaxWidth, mThumbOffsetY + mThumbHeight);
- mTmpRect.inset(mTouchInset, mTouchInset);
- return mTmpRect.contains(x, y);
+ private boolean isNearThumb(int x, int y) {
+ int offset = y - mRv.getPaddingTop() - mThumbOffsetY;
+
+ return x >= 0 && x < getWidth() && offset >= 0 && offset <= mThumbHeight;
+ }
+
+ /**
+ * Returns true if AllAppsTransitionController can handle vertical motion
+ * beginning at this point.
+ */
+ public boolean shouldBlockIntercept(int x, int y) {
+ return isNearThumb(x, y);
}
/**
* Returns whether the specified x position is near the scroll bar.
*/
public boolean isNearScrollBar(int x) {
- int left = getDrawLeft();
- return x >= left && x <= left + mMaxWidth;
+ return x >= (getWidth() - mMaxWidth) / 2 && x <= (getWidth() + mMaxWidth) / 2;
}
private void animatePopupVisibility(boolean visible) {
@@ -306,7 +347,8 @@ public class BaseRecyclerViewFastScrollBar {
private void updatePopupY(int lastTouchY) {
int height = mPopupView.getHeight();
- float top = lastTouchY - (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * height);
+ float top = lastTouchY - (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * height)
+ + mRv.getPaddingTop();
top = Utilities.boundToRange(top,
mMaxWidth, mRv.getScrollbarTrackHeight() - mMaxWidth - height);
mPopupView.setTranslationY(top);