diff --git a/res/drawable/all_apps_divider.xml b/res/drawable/all_apps_divider.xml
new file mode 100644
index 0000000000..3fe5295566
--- /dev/null
+++ b/res/drawable/all_apps_divider.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/all_apps_search_divider.xml b/res/drawable/all_apps_search_divider.xml
new file mode 100644
index 0000000000..99905e4233
--- /dev/null
+++ b/res/drawable/all_apps_search_divider.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/all_apps_divider.xml b/res/layout/all_apps_divider.xml
index b2ee7c1b48..1eaf685c46 100644
--- a/res/layout/all_apps_divider.xml
+++ b/res/layout/all_apps_divider.xml
@@ -13,13 +13,14 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
\ No newline at end of file
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_search_divider.xml
similarity index 62%
rename from res/layout/all_apps_prediction_bar_icon.xml
rename to res/layout/all_apps_search_divider.xml
index 3836fed897..d2ef691ead 100644
--- a/res/layout/all_apps_prediction_bar_icon.xml
+++ b/res/layout/all_apps_search_divider.xml
@@ -13,16 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
+ android:paddingBottom="@dimen/all_apps_divider_margin_vertical"
+ android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
+ android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
+ android:src="@drawable/all_apps_search_divider"
+ android:scaleType="fitXY"
+ android:focusable="false" />
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9abe3e601a..1775d098f1 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -80,7 +80,6 @@
16dp
6dp
- 1dp
8dp
24dp
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 4cb050e246..8bd5eba000 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -41,21 +41,6 @@ public abstract class BaseRecyclerView extends RecyclerView
@Thunk int mDy = 0;
private float mDeltaThreshold;
- /**
- * The current scroll state of the recycler view. We use this in onUpdateScrollbar()
- * and scrollToPositionAtProgress() to determine the scroll position of the recycler view so
- * that we can calculate what the scroll bar looks like, and where to jump to from the fast
- * scroller.
- */
- public static class ScrollPositionState {
- // The index of the first visible row
- public int rowIndex;
- // The offset of the first visible row
- public int rowTopOffset;
- // The adapter position of the first visible item
- public int itemPos;
- }
-
protected BaseRecyclerViewFastScrollBar mScrollbar;
private int mDownX;
@@ -199,11 +184,7 @@ public abstract class BaseRecyclerView extends RecyclerView
* Returns the available scroll height:
* AvailableScrollHeight = Total height of the all items - last page height
*/
- protected int getAvailableScrollHeight(int rowCount) {
- int totalHeight = getPaddingTop() + getTop(rowCount) + getPaddingBottom();
- int availableScrollHeight = totalHeight - getVisibleHeight();
- return availableScrollHeight;
- }
+ protected abstract int getAvailableScrollHeight();
/**
* Returns the available scroll bar height:
@@ -247,15 +228,12 @@ public abstract class BaseRecyclerView extends RecyclerView
* this by mapping the available scroll area of the recycler view to the available space for the
* scroll bar.
*
- * @param scrollPosState the current scroll position
- * @param rowCount the number of rows, used to calculate the total scroll height (assumes that
- * all rows are the same height)
+ * @param scrollY the current scroll y
*/
- protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState,
- int rowCount) {
+ protected void synchronizeScrollBarThumbOffsetToViewScroll(int scrollY,
+ int availableScrollHeight) {
// Only show the scrollbar if there is height to be scrolled
int availableScrollBarHeight = getAvailableScrollBarHeight();
- int availableScrollHeight = getAvailableScrollHeight(rowCount);
if (availableScrollHeight <= 0) {
mScrollbar.setThumbOffset(-1, -1);
return;
@@ -264,7 +242,6 @@ public abstract class BaseRecyclerView extends RecyclerView
// Calculate the current scroll position, the scrollY of the recycler view accounts for the
// view padding, while the scrollBarY is drawn right up to the background padding (ignoring
// padding)
- int scrollY = Math.max(0, getScrollTop(scrollPosState));
int scrollBarY = mBackgroundPadding.top +
(int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
@@ -291,20 +268,7 @@ public abstract class BaseRecyclerView extends RecyclerView
*
* @return the scroll top of this recycler view.
*/
- protected int getScrollTop(ScrollPositionState scrollPosState) {
- return getPaddingTop() + getTop(scrollPosState.rowIndex) -
- scrollPosState.rowTopOffset;
- }
-
- /**
- * Returns information about the item that the recycler view is currently scrolled to.
- */
- protected abstract void getCurScrollState(ScrollPositionState stateOut, int viewTypeMask);
-
- /**
- * Returns the top (or y position) of the row at the specified index.
- */
- protected abstract int getTop(int rowIndex);
+ protected abstract int getCurrentScrollY();
/**
* Maps the touch (from 0..1) to the adapter position that should be visible.
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 717ce74c71..a9cc8f3798 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -364,26 +364,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
+ mAppsRecyclerView.preMeasureViews(mAdapter);
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
- // Precalculate the prediction icon and normal icon sizes
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- getResources().getDisplayMetrics().widthPixels, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- getResources().getDisplayMetrics().heightPixels, MeasureSpec.AT_MOST);
-
- BubbleTextView icon = (BubbleTextView) layoutInflater.inflate(
- R.layout.all_apps_icon, this, false);
- icon.applyDummyInfo();
- icon.measure(widthMeasureSpec, heightMeasureSpec);
- BubbleTextView predIcon = (BubbleTextView) layoutInflater.inflate(
- R.layout.all_apps_prediction_bar_icon, this, false);
- predIcon.applyDummyInfo();
- predIcon.measure(widthMeasureSpec, heightMeasureSpec);
- mAppsRecyclerView.setPremeasuredIconHeights(predIcon.getMeasuredHeight(),
- icon.getMeasuredHeight());
-
// TODO(hyunyoungs): clean up setting the content and the reveal view.
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
getContentView().setBackground(null);
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 73de45e397..6d9094f783 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -18,7 +18,6 @@ package com.android.launcher3.allapps;
import android.support.v7.widget.RecyclerView;
import android.view.View;
-import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.BaseRecyclerViewFastScrollBar;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.util.Thunk;
@@ -144,8 +143,8 @@ public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallb
// Calculate the full animation from the current scroll position to the final scroll
// position, and then run the animation for the duration.
- int newScrollY = Math.min(availableScrollHeight,
- mRv.getPaddingTop() + mRv.getTop(info.fastScrollToItem.rowIndex));
+ int newPosition = info.fastScrollToItem.position;
+ int newScrollY = Math.min(availableScrollHeight, mRv.getCurrentScrollY(newPosition, 0));
int numFrames = mFastScrollFrames.length;
for (int i = 0; i < numFrames; i++) {
// TODO(winsonc): We can interpolate this as well.
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 7d856c04f1..2680197727 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -334,7 +334,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter items = mApps.getAdapterItems();
- if (items.isEmpty() || mNumAppsPerRow == 0) {
- return;
- }
-
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- int position = getChildPosition(child);
- if (position != NO_POSITION) {
- AlphabeticalAppsList.AdapterItem item = items.get(position);
- if (AllAppsGridAdapter.isViewType(item.viewType, viewTypeMask)) {
- stateOut.rowIndex = item.rowIndex;
- stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
- stateOut.itemPos = position;
- return;
- }
- }
- }
- return;
- }
-
@Override
protected boolean supportsFastScrolling() {
// Only allow fast scrolling when the user is not searching, since the results are not
@@ -372,13 +384,63 @@ public class AllAppsRecyclerView extends BaseRecyclerView
return !mApps.hasFilter();
}
- protected int getTop(int rowIndex) {
- if (getChildCount() == 0 || rowIndex <= 0) {
- return 0;
+ @Override
+ protected int getCurrentScrollY() {
+ // Return early if there are no items or we haven't been measured
+ List items = mApps.getAdapterItems();
+ if (items.isEmpty() || mNumAppsPerRow == 0 || getChildCount() == 0) {
+ return -1;
}
- // The prediction bar icons have more padding, so account for that in the row offset
- return mPredictionIconHeight + (rowIndex - 1) * mIconHeight;
+ // Calculate the y and offset for the item
+ View child = getChildAt(0);
+ int position = getChildPosition(child);
+ if (position == NO_POSITION) {
+ return -1;
+ }
+ return getCurrentScrollY(position, getLayoutManager().getDecoratedTop(child));
+ }
+
+ public int getCurrentScrollY(int position, int offset) {
+ List items = mApps.getAdapterItems();
+ AlphabeticalAppsList.AdapterItem posItem = position < items.size() ?
+ items.get(position) : null;
+ int y = mCachedScrollPositions.get(position, -1);
+ if (y < 0) {
+ y = 0;
+ for (int i = 0; i < position; i++) {
+ AlphabeticalAppsList.AdapterItem item = items.get(i);
+ if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
+ // Break once we reach the desired row
+ if (posItem != null && posItem.viewType == item.viewType &&
+ posItem.rowIndex == item.rowIndex) {
+ break;
+ }
+ // Otherwise, only account for the first icon in the row since they are the same
+ // size within a row
+ if (item.rowAppIndex == 0) {
+ y += mViewHeights.get(item.viewType, 0);
+ }
+ } else {
+ // Rest of the views span the full width
+ y += mViewHeights.get(item.viewType, 0);
+ }
+ }
+ mCachedScrollPositions.put(position, y);
+ }
+
+ return getPaddingTop() + y - offset;
+ }
+
+ /**
+ * Returns the available scroll height:
+ * AvailableScrollHeight = Total height of the all items - last page height
+ */
+ @Override
+ protected int getAvailableScrollHeight() {
+ int paddedHeight = getCurrentScrollY(mApps.getAdapterItems().size(), 0);
+ int totalHeight = paddedHeight + getPaddingBottom();
+ return totalHeight - getVisibleHeight();
}
/**
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 2e3cc1aa14..0975206059 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -33,7 +33,6 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
private static final String TAG = "WidgetsRecyclerView";
private WidgetsModel mWidgets;
- private ScrollPositionState mScrollPosState = new ScrollPositionState();
public WidgetsRecyclerView(Context context) {
this(context, null);
@@ -99,9 +98,8 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
stopScroll();
int rowCount = mWidgets.getPackageSize();
- getCurScrollState(mScrollPosState, -1);
float pos = rowCount * touchFraction;
- int availableScrollHeight = getAvailableScrollHeight(rowCount);
+ int availableScrollHeight = getAvailableScrollHeight();
LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
@@ -121,45 +119,41 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
}
// Skip early if, there no child laid out in the container.
- getCurScrollState(mScrollPosState, -1);
- if (mScrollPosState.rowIndex < 0) {
+ int scrollY = getCurrentScrollY();
+ if (scrollY < 0) {
mScrollbar.setThumbOffset(-1, -1);
return;
}
- synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, mWidgets.getPackageSize());
- }
-
- /**
- * Returns the current scroll state.
- */
- protected void getCurScrollState(ScrollPositionState stateOut, int viewTypeMask) {
- stateOut.rowIndex = -1;
- stateOut.rowTopOffset = -1;
- stateOut.itemPos = -1;
-
- // Skip early if widgets are not bound.
- if (isModelNotReady()) {
- return;
- }
-
- View child = getChildAt(0);
- int position = getChildPosition(child);
-
- stateOut.rowIndex = position;
- stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
- stateOut.itemPos = position;
+ synchronizeScrollBarThumbOffsetToViewScroll(scrollY, getAvailableScrollHeight());
}
@Override
- protected int getTop(int rowIndex) {
- if (getChildCount() == 0) {
- return 0;
+ protected int getCurrentScrollY() {
+ // Skip early if widgets are not bound.
+ if (isModelNotReady() || getChildCount() == 0) {
+ return -1;
}
- // All the rows are the same height, return any child height
View child = getChildAt(0);
- return child.getMeasuredHeight() * rowIndex;
+ int rowIndex = getChildPosition(child);
+ int y = (child.getMeasuredHeight() * rowIndex);
+ int offset = getLayoutManager().getDecoratedTop(child);
+
+ return getPaddingTop() + y - offset;
+ }
+
+ /**
+ * Returns the available scroll height:
+ * AvailableScrollHeight = Total height of the all items - last page height
+ */
+ @Override
+ protected int getAvailableScrollHeight() {
+ View child = getChildAt(0);
+ int height = child.getMeasuredHeight() * mWidgets.getPackageSize();
+ int totalHeight = getPaddingTop() + height + getPaddingBottom();
+ int availableScrollHeight = totalHeight - getVisibleHeight();
+ return availableScrollHeight;
}
private boolean isModelNotReady() {