Revert "Updating the scroll calculation from recyclerView to avoid view inflation"
This reverts commit 20bbe95ddbe0d93a50e18aba4623cc844ecfb9e5.
Reason for revert: Causing flake in Ironwood test: b/248295569
Test: ABTD
Before: Flaky, 14/50 PASSED
https://android-build.googleplex.com/builds/abtd/run/L33900000956890639
Revert: 50/50 PASSED
https://android-build.googleplex.com/builds/abtd/run/L49200000956887317
Change-Id: I41f4428c74e581323f90c716a7852b5e553ae27d
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 2f927d3..747b755 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -24,6 +24,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -91,7 +92,8 @@
protected int getAvailableScrollHeight() {
// AvailableScrollHeight = Total height of the all items - first page height
int firstPageHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
- int availableScrollHeight = computeVerticalScrollRange() - firstPageHeight;
+ int totalHeightOfAllItems = getItemsHeight(/* untilIndex= */ getAdapter().getItemCount());
+ int availableScrollHeight = totalHeightOfAllItems - firstPageHeight;
return Math.max(0, availableScrollHeight);
}
@@ -144,7 +146,10 @@
// IF scroller is at the very top OR there is no scroll bar because there is probably not
// enough items to scroll, THEN it's okay for the container to be pulled down.
- return computeVerticalScrollOffset() == 0;
+ if (getCurrentScrollY() == 0) {
+ return true;
+ }
+ return getAdapter() == null || getAdapter().getItemCount() == 0;
}
/**
@@ -155,6 +160,53 @@
}
/**
+ * @return the scroll top of this recycler view.
+ */
+ public int getCurrentScrollY() {
+ Adapter adapter = getAdapter();
+ if (adapter == null) {
+ return -1;
+ }
+ if (adapter.getItemCount() == 0 || getChildCount() == 0) {
+ return -1;
+ }
+
+ int itemPosition = NO_POSITION;
+ View child = null;
+
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager instanceof LinearLayoutManager) {
+ // Use the LayoutManager as the source of truth for visible positions. During
+ // animations, the view group child may not correspond to the visible views that appear
+ // at the top.
+ itemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+ child = layoutManager.findViewByPosition(itemPosition);
+ }
+
+ if (child == null) {
+ // If the layout manager returns null for any reason, which can happen before layout
+ // has occurred for the position, then look at the child of this view as a ViewGroup.
+ child = getChildAt(0);
+ itemPosition = getChildAdapterPosition(child);
+ }
+ if (itemPosition == NO_POSITION) {
+ return -1;
+ }
+ return getPaddingTop() + getItemsHeight(itemPosition)
+ - layoutManager.getDecoratedTop(child);
+ }
+
+ /**
+ * Returns the sum of the height, in pixels, of this list adapter's items from index
+ * 0 (inclusive) until {@code untilIndex} (exclusive). If untilIndex is same as the itemCount,
+ * it returns the full height of all the items.
+ *
+ * <p>If the untilIndex is larger than the total number of items in this adapter, returns the
+ * sum of all items' height.
+ */
+ protected abstract int getItemsHeight(int untilIndex);
+
+ /**
* Maps the touch (from 0..1) to the adapter position that should be visible.
* <p>Override in each subclass of this base class.
*/
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c85924e..6bdfa1c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2779,7 +2779,7 @@
View v = getFirstMatch(Collections.singletonList(activeRecyclerView),
preferredItem, packageAndUserAndApp);
- if (v != null && activeRecyclerView.computeVerticalScrollOffset() > 0) {
+ if (v != null && activeRecyclerView.getCurrentScrollY() > 0) {
RectF locationBounds = new RectF();
FloatingIconView.getLocationBoundsForView(this, v, false, locationBounds,
new Rect());
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index e0b4951..33d2f2b 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -26,9 +26,7 @@
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import com.android.launcher3.util.ScrollableLayoutManager;
import com.android.launcher3.views.ActivityContext;
import java.util.List;
@@ -64,10 +62,10 @@
/**
* A subclass of GridLayoutManager that overrides accessibility values during app search.
*/
- public class AppsGridLayoutManager extends ScrollableLayoutManager {
+ public class AppsGridLayoutManager extends GridLayoutManager {
public AppsGridLayoutManager(Context context) {
- super(context);
+ super(context, 1, GridLayoutManager.VERTICAL, false);
}
@Override
@@ -127,15 +125,6 @@
}
return extraRows;
}
-
- @Override
- protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
- AllAppsGridAdapter.AdapterItem item = mApps.getAdapterItems().get(position);
- // only account for the first icon in the row since they are the same size within a row
- return (isIconViewType(item.viewType) && item.rowAppIndex != 0)
- ? heightUntilLastPos
- : (heightUntilLastPos + mCachedSizes.get(item.viewType));
- }
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 3d06fb5..21a7dfb 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.allapps;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
@@ -24,6 +26,7 @@
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.SparseIntArray;
import androidx.recyclerview.widget.RecyclerView;
@@ -46,10 +49,40 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_LATENCY = Utilities.isPropertyEnabled(SEARCH_LOGGING);
+ protected AlphabeticalAppsList<?> mApps;
protected final int mNumAppsPerRow;
+
+ // The specific view heights that we use to calculate scroll
+ private final SparseIntArray mViewHeights = new SparseIntArray();
+ private final SparseIntArray mCachedScrollPositions = new SparseIntArray();
private final AllAppsFastScrollHelper mFastScrollHelper;
- protected AlphabeticalAppsList<?> mApps;
+
+ private final AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
+ public void onChanged() {
+ mCachedScrollPositions.clear();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ onChanged();
+ }
+ };
public AllAppsRecyclerView(Context context) {
this(context, null);
@@ -89,8 +122,12 @@
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows
* (mNumAppsPerRow + 1));
+
+ mViewHeights.clear();
+ mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, grid.allAppsCellHeightPx);
}
+
@Override
public void onDraw(Canvas c) {
if (DEBUG) {
@@ -163,6 +200,17 @@
}
@Override
+ public void setAdapter(Adapter adapter) {
+ if (getAdapter() != null) {
+ getAdapter().unregisterAdapterDataObserver(mObserver);
+ }
+ super.setAdapter(adapter);
+ if (adapter != null) {
+ adapter.registerAdapterDataObserver(mObserver);
+ }
+ }
+
+ @Override
protected boolean isPaddingOffsetRequired() {
return true;
}
@@ -183,13 +231,13 @@
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
// Skip early if there are no items or we haven't been measured
- if (items.isEmpty() || mNumAppsPerRow == 0 || getChildCount() == 0) {
+ if (items.isEmpty() || mNumAppsPerRow == 0) {
mScrollbar.setThumbOffsetY(-1);
return;
}
// Skip early if, there no child laid out in the container.
- int scrollY = computeVerticalScrollOffset();
+ int scrollY = getCurrentScrollY();
if (scrollY < 0) {
mScrollbar.setThumbOffsetY(-1);
return;
@@ -244,6 +292,51 @@
}
}
+ @Override
+ protected int getItemsHeight(int position) {
+ List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
+ AllAppsGridAdapter.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++) {
+ AllAppsGridAdapter.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
+ int elHeight = mViewHeights.get(item.viewType);
+ if (elHeight == 0) {
+ ViewHolder holder = findViewHolderForAdapterPosition(i);
+ if (holder == null) {
+ holder = getAdapter().createViewHolder(this, item.viewType);
+ getAdapter().onBindViewHolder(holder, i);
+ holder.itemView.measure(UNSPECIFIED, UNSPECIFIED);
+ elHeight = holder.itemView.getMeasuredHeight();
+
+ getRecycledViewPool().putRecycledView(holder);
+ } else {
+ elHeight = holder.itemView.getMeasuredHeight();
+ }
+ }
+ y += elHeight;
+ }
+ }
+ mCachedScrollPositions.put(position, y);
+ }
+ return y;
+ }
+
public int getScrollBarTop() {
return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding);
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 7660e16..879a159 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -103,8 +103,7 @@
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
- updateHeaderScroll(
- ((AllAppsRecyclerView) recyclerView).computeVerticalScrollOffset());
+ updateHeaderScroll(((AllAppsRecyclerView) recyclerView).getCurrentScrollY());
}
};
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 73efd3f..8ec2aeb 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -68,7 +68,7 @@
mAnimator.cancel();
}
- int current = -mCurrentRV.computeVerticalScrollOffset();
+ int current = -mCurrentRV.getCurrentScrollY();
boolean headerCollapsed = mHeaderCollapsed;
moved(current);
applyVerticalMove();
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 269baf0..d3c9bc9 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -112,12 +112,12 @@
case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
return getLauncherUIProperty(Bundle::putInt,
- l -> l.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset());
+ l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
}
case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
return getLauncherUIProperty(Bundle::putInt,
- l -> WidgetsFullSheet.getWidgetsView(l).computeVerticalScrollOffset());
+ l -> WidgetsFullSheet.getWidgetsView(l).getCurrentScrollY());
}
case TestProtocol.REQUEST_TARGET_INSETS: {
diff --git a/src/com/android/launcher3/util/ScrollableLayoutManager.java b/src/com/android/launcher3/util/ScrollableLayoutManager.java
deleted file mode 100644
index 17eaefd..0000000
--- a/src/com/android/launcher3/util/ScrollableLayoutManager.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2022 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.util;
-
-import android.content.Context;
-import android.util.SparseIntArray;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.State;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
-/**
- * Extension of {@link GridLayoutManager} with support for smooth scrolling
- */
-public class ScrollableLayoutManager extends GridLayoutManager {
-
- // keyed on item type
- protected final SparseIntArray mCachedSizes = new SparseIntArray();
-
- private RecyclerView mRv;
-
- /**
- * Precalculated total height keyed on the item position. This is always incremental.
- * Subclass can override {@link #incrementTotalHeight} to incorporate the layout logic.
- * For example all-apps should have same values for items in same row,
- * sample values: 0, 10, 10, 10, 10, 20, 20, 20, 20
- * whereas widgets will have strictly increasing values
- * sample values: 0, 10, 50, 60, 110
- */
-
- //
- private int[] mTotalHeightCache = new int[1];
- private int mLastValidHeightIndex = 0;
-
- public ScrollableLayoutManager(Context context) {
- super(context, 1, GridLayoutManager.VERTICAL, false);
- }
-
- @Override
- public void onAttachedToWindow(RecyclerView view) {
- super.onAttachedToWindow(view);
- mRv = view;
- }
-
- @Override
- public void layoutDecorated(@NonNull View child, int left, int top, int right, int bottom) {
- super.layoutDecorated(child, left, top, right, bottom);
- mCachedSizes.put(
- mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight());
- }
-
- @Override
- public void layoutDecoratedWithMargins(@NonNull View child, int left, int top, int right,
- int bottom) {
- super.layoutDecoratedWithMargins(child, left, top, right, bottom);
- mCachedSizes.put(
- mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight());
- }
-
- @Override
- public int computeVerticalScrollExtent(State state) {
- return mRv == null ? 0 : mRv.getHeight();
- }
-
- @Override
- public int computeVerticalScrollOffset(State state) {
- Adapter adapter = mRv == null ? null : mRv.getAdapter();
- if (adapter == null) {
- return 0;
- }
- if (adapter.getItemCount() == 0 || getChildCount() == 0) {
- return 0;
- }
- View child = getChildAt(0);
- ViewHolder holder = mRv.findContainingViewHolder(child);
- if (holder == null) {
- return 0;
- }
- int itemPosition = holder.getLayoutPosition();
- if (itemPosition < 0) {
- return 0;
- }
- return getPaddingTop() + getItemsHeight(adapter, itemPosition) - getDecoratedTop(child);
- }
-
- @Override
- public int computeVerticalScrollRange(State state) {
- Adapter adapter = mRv == null ? null : mRv.getAdapter();
- return adapter == null ? 0 : getItemsHeight(adapter, adapter.getItemCount());
- }
-
- /**
- * Returns the sum of the height, in pixels, of this list adapter's items from index
- * 0 (inclusive) until {@code untilIndex} (exclusive). If untilIndex is same as the itemCount,
- * it returns the full height of all the items.
- *
- * <p>If the untilIndex is larger than the total number of items in this adapter, returns the
- * sum of all items' height.
- */
- private int getItemsHeight(Adapter adapter, int untilIndex) {
- final int totalItems = adapter.getItemCount();
- if (mTotalHeightCache.length < (totalItems + 1)) {
- mTotalHeightCache = new int[totalItems + 1];
- mLastValidHeightIndex = 0;
- }
- if (untilIndex > totalItems) {
- untilIndex = totalItems;
- } else if (untilIndex < 0) {
- untilIndex = 0;
- }
- if (untilIndex <= mLastValidHeightIndex) {
- return mTotalHeightCache[untilIndex];
- }
-
- int totalItemsHeight = mTotalHeightCache[mLastValidHeightIndex];
- for (int i = mLastValidHeightIndex; i < untilIndex; i++) {
- totalItemsHeight = incrementTotalHeight(adapter, i, totalItemsHeight);
- mTotalHeightCache[i + 1] = totalItemsHeight;
- }
- mLastValidHeightIndex = untilIndex;
- return totalItemsHeight;
- }
-
- /**
- * The current implementation assumes a linear list with every item taking up the whole row.
- * Subclasses should override this method to account for any spanning logic
- */
- protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
- return heightUntilLastPos + mCachedSizes.get(adapter.getItemViewType(position));
- }
-
- private void invalidateScrollCache() {
- mLastValidHeightIndex = 0;
- }
-
- @Override
- public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
- super.onItemsAdded(recyclerView, positionStart, itemCount);
- invalidateScrollCache();
- }
-
- @Override
- public void onItemsChanged(RecyclerView recyclerView) {
- super.onItemsChanged(recyclerView);
- invalidateScrollCache();
- }
-
- @Override
- public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
- super.onItemsRemoved(recyclerView, positionStart, itemCount);
- invalidateScrollCache();
- }
-
- @Override
- public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
- super.onItemsMoved(recyclerView, from, to, itemCount);
- invalidateScrollCache();
- }
-
- @Override
- public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount,
- Object payload) {
- super.onItemsUpdated(recyclerView, positionStart, itemCount, payload);
- invalidateScrollCache();
- }
-}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 3af2e3c..40e4ce1 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -119,6 +119,7 @@
// prevent jumping, this offset is applied as the user scrolls.
protected int mTouchOffsetY;
protected int mThumbOffsetY;
+ protected int mRvOffsetY;
// Fast scroller popup
private TextView mPopupView;
@@ -206,11 +207,16 @@
public void setThumbOffsetY(int y) {
if (mThumbOffsetY == y) {
+ int rvCurrentOffsetY = mRv.getCurrentScrollY();
+ if (mRvOffsetY != rvCurrentOffsetY) {
+ mRvOffsetY = mRv.getCurrentScrollY();
+ }
return;
}
updatePopupY(y);
mThumbOffsetY = y;
invalidate();
+ mRvOffsetY = mRv.getCurrentScrollY();
}
public int getThumbOffsetY() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 5969e3e..35fa7a4 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
+import android.util.SparseIntArray;
import android.view.MotionEvent;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -27,7 +28,6 @@
import com.android.launcher3.FastScrollRecyclerView;
import com.android.launcher3.R;
-import com.android.launcher3.util.ScrollableLayoutManager;
/**
* The widgets recycler view.
@@ -42,6 +42,14 @@
private boolean mTouchDownOnScroller;
private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
+ /**
+ * There is always 1 or 0 item of VIEW_TYPE_WIDGETS_LIST. Other types have fixes sizes, so the
+ * the size can be used for all other items of same type. Caching the last know size for
+ * VIEW_TYPE_WIDGETS_LIST allows us to use it to estimate full size even when
+ * VIEW_TYPE_WIDGETS_LIST is not visible on the screen.
+ */
+ private final SparseIntArray mCachedSizes = new SparseIntArray();
+
public WidgetsRecyclerView(Context context) {
this(context, null);
}
@@ -60,7 +68,9 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- setLayoutManager(new ScrollableLayoutManager(getContext()));
+ // create a layout manager with Launcher's context so that scroll position
+ // can be preserved during screen rotation.
+ setLayoutManager(new LinearLayoutManager(getContext()));
}
@Override
@@ -104,7 +114,7 @@
}
// Skip early if, there no child laid out in the container.
- int scrollY = computeVerticalScrollOffset();
+ int scrollY = getCurrentScrollY();
if (scrollY < 0) {
mScrollbar.setThumbOffsetY(-1);
return;
@@ -154,6 +164,39 @@
}
/**
+ * Returns the sum of the height, in pixels, of this list adapter's items from index 0 until
+ * {@code untilIndex}.
+ *
+ * <p>If the untilIndex is larger than the total number of items in this adapter, returns the
+ * sum of all items' height.
+ */
+ @Override
+ protected int getItemsHeight(int untilIndex) {
+ // Initialize cache
+ int childCount = getChildCount();
+ int startPosition;
+ if (childCount > 0
+ && ((startPosition = getChildAdapterPosition(getChildAt(0))) != NO_POSITION)) {
+ int loopCount = Math.min(getChildCount(), getAdapter().getItemCount() - startPosition);
+ for (int i = 0; i < loopCount; i++) {
+ mCachedSizes.put(
+ mAdapter.getItemViewType(startPosition + i),
+ getChildAt(i).getMeasuredHeight());
+ }
+ }
+
+ if (untilIndex > mAdapter.getItems().size()) {
+ untilIndex = mAdapter.getItems().size();
+ }
+ int totalItemsHeight = 0;
+ for (int i = 0; i < untilIndex; i++) {
+ int type = mAdapter.getItemViewType(i);
+ totalItemsHeight += mCachedSizes.get(type);
+ }
+ return totalItemsHeight;
+ }
+
+ /**
* Provides dimensions of the header view that is shown at the top of a
* {@link WidgetsRecyclerView}.
*/
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index df3cbff..a66b09a 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -525,7 +525,7 @@
}
protected int getAllAppsScroll(Launcher launcher) {
- return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset();
+ return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
}
private void checkLauncherIntegrity(
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 07bfe4c..be49974 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -303,7 +303,7 @@
}
private int getWidgetsScroll(Launcher launcher) {
- return getWidgetsView(launcher).computeVerticalScrollOffset();
+ return getWidgetsView(launcher).getCurrentScrollY();
}
private boolean isOptionsPopupVisible(Launcher launcher) {