From cee6ddf3deaed339e6d6df7f1682c725a00197b9 Mon Sep 17 00:00:00 2001 From: Hui Kang Date: Mon, 17 Oct 2022 18:27:18 +0000 Subject: [PATCH] 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 --- .../launcher3/FastScrollRecyclerView.java | 56 +++++- src/com/android/launcher3/Launcher.java | 2 +- .../launcher3/allapps/AllAppsGridAdapter.java | 15 +- .../allapps/AllAppsRecyclerView.java | 99 +++++++++- .../allapps/BaseAllAppsContainerView.java | 3 +- .../launcher3/allapps/FloatingHeaderView.java | 2 +- .../testing/TestInformationHandler.java | 4 +- .../util/ScrollableLayoutManager.java | 183 ------------------ .../views/RecyclerViewFastScroller.java | 6 + .../widget/picker/WidgetsRecyclerView.java | 49 ++++- .../launcher3/ui/AbstractLauncherUiTest.java | 2 +- .../launcher3/ui/TaplTestsLauncher3.java | 2 +- 12 files changed, 211 insertions(+), 212 deletions(-) delete mode 100644 src/com/android/launcher3/util/ScrollableLayoutManager.java diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java index 2f927d3142..747b755263 100644 --- a/src/com/android/launcher3/FastScrollRecyclerView.java +++ b/src/com/android/launcher3/FastScrollRecyclerView.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; 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 @@ public abstract class FastScrollRecyclerView extends RecyclerView { 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 @@ public abstract class FastScrollRecyclerView extends RecyclerView { // 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; } /** @@ -154,6 +159,53 @@ public abstract class FastScrollRecyclerView extends RecyclerView { return true; } + /** + * @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. + * + *

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. *

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 c85924e439..6bdfa1c8b0 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2779,7 +2779,7 @@ public class Launcher extends StatefulActivity 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 e0b4951caf..33d2f2b1df 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.AccessibilityNodeInfoCompat; 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 @@ public class AllAppsGridAdapter extends /** * 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 @@ public class AllAppsGridAdapter extends } 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 3d06fb5d41..21a7dfbb41 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.content.Context; 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 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { 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 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { 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) { @@ -162,6 +199,17 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { mFastScrollHelper.onFastScrollCompleted(); } + @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 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { List 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 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { } } + @Override + protected int getItemsHeight(int position) { + List 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 7660e16a4c..879a159987 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java @@ -103,8 +103,7 @@ public abstract class BaseAllAppsContainerView 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 17eaefda18..0000000000 --- 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. - * - *

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 3af2e3c9dc..40e4ce1c04 100644 --- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java +++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java @@ -119,6 +119,7 @@ public class RecyclerViewFastScroller extends View { // 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 class RecyclerViewFastScroller extends View { 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 5969e3e154..35fa7a42cc 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -19,6 +19,7 @@ package com.android.launcher3.widget.picker; 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 androidx.recyclerview.widget.RecyclerView.OnItemTouchListener; import com.android.launcher3.FastScrollRecyclerView; import com.android.launcher3.R; -import com.android.launcher3.util.ScrollableLayoutManager; /** * The widgets recycler view. @@ -42,6 +42,14 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte 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 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte @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 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte } // Skip early if, there no child laid out in the container. - int scrollY = computeVerticalScrollOffset(); + int scrollY = getCurrentScrollY(); if (scrollY < 0) { mScrollbar.setThumbOffsetY(-1); return; @@ -153,6 +163,39 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte mHeaderViewDimensionsProvider = headerViewDimensionsProvider; } + /** + * Returns the sum of the height, in pixels, of this list adapter's items from index 0 until + * {@code untilIndex}. + * + *

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 df3cbff7e0..a66b09a87d 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -525,7 +525,7 @@ public abstract class AbstractLauncherUiTest { } 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 07bfe4c971..be49974574 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -303,7 +303,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } private int getWidgetsScroll(Launcher launcher) { - return getWidgetsView(launcher).computeVerticalScrollOffset(); + return getWidgetsView(launcher).getCurrentScrollY(); } private boolean isOptionsPopupVisible(Launcher launcher) {