Merge "Removing non-launcher engineers from the Launcher OWNERS file" into tm-qpr-dev
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 7b297af..4013a71 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -86,7 +86,7 @@
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string>
<string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
- <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
+ <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index a206a49..75f0933 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -97,7 +97,7 @@
<string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Префрлувајте се меѓу апликации преку лентата за задачи"</string>
<string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Повлечете кон страната за да користите две апликации одеднаш"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Допрете и задржете за да се сокрие лентата за задачи"</string>
- <string name="taskbar_edu_next" msgid="4007618274426775841">"Следна"</string>
+ <string name="taskbar_edu_next" msgid="4007618274426775841">"Следно"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 591b32f..ff11f67 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -183,10 +183,8 @@
mTaskBarRecentsAnimationListener = new TaskBarRecentsAnimationListener(callbacks);
callbacks.addListener(mTaskBarRecentsAnimationListener);
- RecentsView recentsView = mLauncher.getOverviewPanel();
- recentsView.setTaskLaunchListener(() -> {
- mTaskBarRecentsAnimationListener.endGestureStateOverride(true);
- });
+ ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(() ->
+ mTaskBarRecentsAnimationListener.endGestureStateOverride(true));
return animatorSet;
}
@@ -491,6 +489,7 @@
private void endGestureStateOverride(boolean finishedToApp) {
mCallbacks.removeListener(this);
mTaskBarRecentsAnimationListener = null;
+ ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(null);
// Update the resumed state immediately to ensure a seamless handoff
boolean launcherResumed = !finishedToApp;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b3e2d91..b3ef71e 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -166,11 +166,7 @@
if (mActivity != activity) {
return;
}
- if (mTaskAnimationManager != null) {
- mTaskAnimationManager.finishRunningRecentsAnimation(true);
- }
mRecentsView = null;
- mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
mActivity = null;
}
};
@@ -1600,6 +1596,9 @@
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ if (mActivity != null) {
+ mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index db402af..a030568 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -468,7 +468,6 @@
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
finishCallback.run();
}
});
@@ -530,7 +529,6 @@
for (SurfaceControl leash: closingTargets) {
t.hide(leash);
}
- super.onAnimationEnd(animation);
finishCallback.run();
}
});
@@ -599,9 +597,14 @@
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
- // Make sure recents gets fixed up by resetting task alphas and scales, etc.
windowAnimEndListener = new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ recentsView.onTaskLaunchedInLiveTileMode();
+ }
+
+ // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+ @Override
public void onAnimationEnd(Animator animation) {
recentsView.finishRecentsAnimation(false /* toRecents */, () -> {
recentsView.post(() -> {
@@ -677,7 +680,6 @@
dockFadeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
if (shown) {
for (SurfaceControl leash : auxiliarySurfaces) {
t.setAlpha(leash, 0);
@@ -689,7 +691,6 @@
@Override
public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
if (!shown) {
for (SurfaceControl leash : auxiliarySurfaces) {
t.hide(leash);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 417473f..bf1c998 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -151,6 +151,8 @@
*/
public class TISBinder extends IOverviewProxy.Stub {
+ @Nullable private Runnable mOnOverviewTargetChangeListener = null;
+
@BinderThread
public void onInitialize(Bundle bundle) {
ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
@@ -331,6 +333,18 @@
public void setGestureBlockedTaskId(int taskId) {
mDeviceState.setGestureBlockingTaskId(taskId);
}
+
+ /** Sets a listener to be run on Overview Target updates. */
+ public void setOverviewTargetChangeListener(@Nullable Runnable listener) {
+ mOnOverviewTargetChangeListener = listener;
+ }
+
+ protected void onOverviewTargetChange() {
+ if (mOnOverviewTargetChangeListener != null) {
+ mOnOverviewTargetChangeListener.run();
+ mOnOverviewTargetChangeListener = null;
+ }
+ }
}
private static boolean sConnected = false;
@@ -491,6 +505,7 @@
if (newOverviewActivity != null) {
mTaskbarManager.setActivity(newOverviewActivity);
}
+ mTISBinder.onOverviewTargetChange();
}
@UiThread
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 66ed056..aa52789 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -208,6 +208,7 @@
mBinder = binder;
mBinder.getTaskbarManager().setSetupUIVisible(isResumed());
mBinder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
+ mBinder.setOverviewTargetChangeListener(mBinder::preloadOverviewForSUWAllSet);
mBinder.preloadOverviewForSUWAllSet();
}
@@ -224,6 +225,7 @@
if (mBinder != null) {
mBinder.getTaskbarManager().setSetupUIVisible(false);
mBinder.setSwipeUpProxy(null);
+ mBinder.setOverviewTargetChangeListener(null);
}
}
diff --git a/res/values/id.xml b/res/values/id.xml
index af21b27..9fc0ff8 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -16,7 +16,6 @@
-->
<resources>
<item type="id" name="apps_list_view_work" />
- <item type="id" name="tag_widget_entry" />
<item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index f117069..94903f2 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;
@@ -86,15 +87,20 @@
* Returns the available scroll height:
* AvailableScrollHeight = Total height of the all items - last page height
*/
- protected abstract int getAvailableScrollHeight();
+ protected int getAvailableScrollHeight() {
+ // AvailableScrollHeight = Total height of the all items - first page height
+ int firstPageHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
+ int totalHeightOfAllItems = getItemsHeight(/* untilIndex= */ getAdapter().getItemCount());
+ int availableScrollHeight = totalHeightOfAllItems - firstPageHeight;
+ return Math.max(0, availableScrollHeight);
+ }
/**
* Returns the available scroll bar height:
* AvailableScrollBarHeight = Total height of the visible view - thumb height
*/
protected int getAvailableScrollBarHeight() {
- int availableScrollBarHeight = getScrollbarTrackHeight() - mScrollbar.getThumbHeight();
- return availableScrollBarHeight;
+ return getScrollbarTrackHeight() - mScrollbar.getThumbHeight();
}
/**
@@ -152,12 +158,51 @@
}
/**
- * Maps the touch (from 0..1) to the adapter position that should be visible.
- * <p>Override in each subclass of this base class.
- *
* @return the scroll top of this recycler view.
*/
- public abstract int getCurrentScrollY();
+ 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.
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 73ca4a3..dacbe92 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -61,8 +61,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -634,18 +632,6 @@
float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
int rotation = WindowManagerProxy.INSTANCE.get(context).getRotation(context);
- if (Utilities.IS_DEBUG_DEVICE) {
- StringWriter stringWriter = new StringWriter();
- PrintWriter printWriter = new PrintWriter(stringWriter);
- DisplayController.INSTANCE.get(context).dump(printWriter);
- printWriter.flush();
- Log.d("b/231312158", "getDeviceProfile -"
- + "\nconfig: " + config
- + "\ndisplayMetrics: " + res.getDisplayMetrics()
- + "\nrotation: " + rotation
- + "\n" + stringWriter,
- new Exception());
- }
return getBestMatch(screenWidth, screenHeight, rotation);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index af17cf7..de34416 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -31,7 +31,6 @@
import android.util.Log;
import android.util.SparseIntArray;
import android.view.MotionEvent;
-import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
@@ -342,24 +341,7 @@
}
@Override
- public int getCurrentScrollY() {
- // Return early if there are no items or we haven't been measured
- List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
- if (items.isEmpty() || mNumAppsPerRow == 0 || getChildCount() == 0) {
- return -1;
- }
-
- // Calculate the y and offset for the item
- View child = getChildAt(0);
- int position = getChildAdapterPosition(child);
- if (position == NO_POSITION) {
- return -1;
- }
- return getPaddingTop() +
- getCurrentScrollY(position, getLayoutManager().getDecoratedTop(child));
- }
-
- public int getCurrentScrollY(int position, int offset) {
+ protected int getItemsHeight(int position) {
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
AllAppsGridAdapter.AdapterItem posItem = position < items.size()
? items.get(position) : null;
@@ -400,17 +382,7 @@
}
mCachedScrollPositions.put(position, y);
}
- return y - offset;
- }
-
- /**
- * Returns the available scroll height:
- * AvailableScrollHeight = Total height of the all items - last page height
- */
- @Override
- protected int getAvailableScrollHeight() {
- return getPaddingTop() + getCurrentScrollY(getAdapter().getItemCount(), 0)
- - getHeight() + getPaddingBottom();
+ return y;
}
public int getScrollBarTop() {
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index 35fcb78..46f0b0b 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -134,10 +134,13 @@
* DeviceGridState without migration, or false otherwise.
*/
public boolean isCompatible(DeviceGridState other) {
- if (this == other) return true;
- if (other == null) return false;
- return mNumHotseat == other.mNumHotseat
- && Objects.equals(mGridSizeString, other.mGridSizeString);
+ if (this == other) {
+ return true;
+ }
+ if (other == null) {
+ return false;
+ }
+ return Objects.equals(mDbFile, other.mDbFile);
}
public Integer getColumns() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 0e5a7d7..e6b9dca 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.recyclerview.ViewHolderBinder.POSITION_LAST;
import android.content.Context;
-import android.graphics.Rect;
import android.os.Process;
import android.util.Log;
import android.util.SparseArray;
@@ -36,7 +35,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.LayoutParams;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.launcher3.R;
@@ -80,10 +78,10 @@
private static final boolean DEBUG = false;
/** Uniquely identifies widgets list view type within the app. */
- private static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
- private static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
- private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
- private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
+ public static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
+ public static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
+ public static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
+ public static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
private final Context mContext;
private final WidgetsDiffReporter mDiffReporter;
@@ -103,7 +101,6 @@
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@Nullable private RecyclerView mRecyclerView;
@Nullable private PackageUserKey mPendingClickHeader;
- private final int mSpacingBetweenEntries;
private int mMaxSpanSize = 4;
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
@@ -133,28 +130,11 @@
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SPACE,
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
- mSpacingBetweenEntries =
- context.getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing);
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
mRecyclerView = recyclerView;
-
- mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
- @Override
- public void getItemOffsets(
- @NonNull Rect outRect,
- @NonNull View view,
- @NonNull RecyclerView parent,
- @NonNull RecyclerView.State state) {
- super.getItemOffsets(outRect, view, parent, state);
- int position = ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
- boolean isHeader =
- view.getTag(R.id.tag_widget_entry) instanceof WidgetsListBaseEntry.Header;
- outRect.top += position > 0 && isHeader ? mSpacingBetweenEntries : 0;
- }
- });
}
@Override
@@ -286,7 +266,6 @@
listPos |= POSITION_LAST;
}
viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), listPos, payloads);
- holder.itemView.setTag(R.id.tag_widget_entry, entry);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index bdf646b..daa67a9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -16,27 +16,24 @@
package com.android.launcher3.widget.picker;
+import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_HEADER;
+import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_SEARCH_HEADER;
+
import android.content.Context;
import android.graphics.Point;
+import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.TableLayout;
+import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.FastScrollRecyclerView;
import com.android.launcher3.R;
-import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.widget.model.WidgetListSpaceEntry;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-import com.android.launcher3.widget.picker.WidgetsSpaceViewHolderBinder.EmptySpaceView;
/**
* The widgets recycler view.
@@ -51,12 +48,14 @@
private boolean mTouchDownOnScroller;
private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
- // Cached sizes
- private int mLastVisibleWidgetContentTableHeight = 0;
- private int mWidgetHeaderHeight = 0;
- private int mWidgetEmptySpaceHeight = 0;
-
- private final int mSpacingBetweenEntries;
+ /**
+ * 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();
+ private final SpacingDecoration mSpacingDecoration;
public WidgetsRecyclerView(Context context) {
this(context, null);
@@ -72,12 +71,8 @@
mScrollbarTop = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
addOnItemTouchListener(this);
- ActivityContext activity = ActivityContext.lookupContext(getContext());
- DeviceProfile grid = activity.getDeviceProfile();
-
- // The spacing used between entries.
- mSpacingBetweenEntries =
- getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing);
+ mSpacingDecoration = new SpacingDecoration(context);
+ addItemDecoration(mSpacingDecoration);
}
@Override
@@ -138,67 +133,6 @@
synchronizeScrollBarThumbOffsetToViewScroll(scrollY, getAvailableScrollHeight());
}
- @Override
- public int getCurrentScrollY() {
- // Skip early if widgets are not bound.
- if (isModelNotReady() || getChildCount() == 0) {
- return -1;
- }
-
- int rowIndex = -1;
- 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.
- rowIndex = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
- child = layoutManager.findViewByPosition(rowIndex);
- }
-
- 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);
- rowIndex = getChildPosition(child);
- }
-
- for (int i = 0; i < getChildCount(); i++) {
- View view = getChildAt(i);
- if (view instanceof TableLayout) {
- // This assumes there is ever only one content shown in this recycler view.
- mLastVisibleWidgetContentTableHeight = view.getMeasuredHeight();
- } else if (view instanceof WidgetsListHeader
- && mWidgetHeaderHeight == 0
- && view.getMeasuredHeight() > 0) {
- // This assumes all header views are of the same height.
- mWidgetHeaderHeight = view.getMeasuredHeight();
- } else if (view instanceof EmptySpaceView && view.getMeasuredHeight() > 0) {
- mWidgetEmptySpaceHeight = view.getMeasuredHeight();
- }
- }
-
- int scrollPosition = getItemsHeight(rowIndex);
- int offset = getLayoutManager().getDecoratedTop(child);
-
- return getPaddingTop() + scrollPosition - offset;
- }
-
- /**
- * Returns the available scroll height, in pixel.
- *
- * <p>If the recycler view can't be scrolled, returns 0.
- */
- @Override
- protected int getAvailableScrollHeight() {
- // AvailableScrollHeight = Total height of the all items - first page height
- int firstPageHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
- int totalHeightOfAllItems = getItemsHeight(/* untilIndex= */ mAdapter.getItemCount());
- int availableScrollHeight = totalHeightOfAllItems - firstPageHeight;
- return Math.max(0, availableScrollHeight);
- }
-
private boolean isModelNotReady() {
return mAdapter.getItemCount() == 0;
}
@@ -246,28 +180,27 @@
* <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(int untilIndex) {
+ @Override
+ protected int getItemsHeight(int untilIndex) {
+ // Initialize cache
+ int childCount = getChildCount();
+ int startPosition;
+ if (childCount > 0
+ && ((startPosition = getChildAdapterPosition(getChildAt(0))) != NO_POSITION)) {
+ for (int i = 0; i < childCount; 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++) {
- WidgetsListBaseEntry entry = mAdapter.getItems().get(i);
- if (entry instanceof WidgetsListHeaderEntry
- || entry instanceof WidgetsListSearchHeaderEntry) {
- totalItemsHeight += mWidgetHeaderHeight;
- if (i > 0) {
- // Each header contains the spacing between entries as top decoration, except
- // the first one.
- totalItemsHeight += mSpacingBetweenEntries;
- }
- } else if (entry instanceof WidgetsListContentEntry) {
- totalItemsHeight += mLastVisibleWidgetContentTableHeight;
- } else if (entry instanceof WidgetListSpaceEntry) {
- totalItemsHeight += mWidgetEmptySpaceHeight;
- } else {
- throw new UnsupportedOperationException("Can't estimate height for " + entry);
- }
+ int type = mAdapter.getItemViewType(i);
+ totalItemsHeight += mCachedSizes.get(type) + mSpacingDecoration.getSpacing(i, type);
}
return totalItemsHeight;
}
@@ -283,4 +216,31 @@
*/
int getHeaderViewHeight();
}
+
+ private static class SpacingDecoration extends RecyclerView.ItemDecoration {
+
+ private final int mSpacingBetweenEntries;
+
+ SpacingDecoration(@NonNull Context context) {
+ mSpacingBetweenEntries =
+ context.getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing);
+ }
+
+ @Override
+ public void getItemOffsets(
+ @NonNull Rect outRect,
+ @NonNull View view,
+ @NonNull RecyclerView parent,
+ @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ int position = parent.getChildAdapterPosition(view);
+ outRect.top += getSpacing(position, parent.getAdapter().getItemViewType(position));
+ }
+
+ public int getSpacing(int position, int type) {
+ boolean isHeader = type == VIEW_TYPE_WIDGETS_SEARCH_HEADER
+ || type == VIEW_TYPE_WIDGETS_HEADER;
+ return position > 0 && isHeader ? mSpacingBetweenEntries : 0;
+ }
+ }
}