("scrollAnimOffset") {
- @Override
- public void setValue(SearchAndRecommendationsScrollController controller, float offset) {
- controller.mScrollOffset = offset;
- controller.updateHeaderScroll();
- }
-
- @Override
- public Float get(SearchAndRecommendationsScrollController controller) {
- return controller.mScrollOffset;
- }
- };
-
- private static final MotionEventProxyMethod INTERCEPT_PROXY = ViewGroup::onInterceptTouchEvent;
- private static final MotionEventProxyMethod TOUCH_PROXY = ViewGroup::onTouchEvent;
-
- final SearchAndRecommendationsView mContainer;
- final View mSearchBarContainer;
- final WidgetsSearchBar mSearchBar;
- final TextView mHeaderTitle;
- final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
- @Nullable final View mTabBar;
-
- private WidgetsRecyclerView mCurrentRecyclerView;
- private EmptySpaceView mCurrentEmptySpaceView;
-
- private float mLastScroll = 0;
- private float mScrollOffset = 0;
- private Animator mOffsetAnimator;
-
- private boolean mShouldForwardToRecyclerView = false;
-
- private int mHeaderHeight;
-
- SearchAndRecommendationsScrollController(
- SearchAndRecommendationsView searchAndRecommendationContainer) {
- mContainer = searchAndRecommendationContainer;
- mSearchBarContainer = mContainer.findViewById(R.id.search_bar_container);
- mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
- mHeaderTitle = mContainer.findViewById(R.id.title);
- mRecommendedWidgetsTable = mContainer.findViewById(R.id.recommended_widget_table);
- mTabBar = mContainer.findViewById(R.id.tabs);
-
- mContainer.setSearchAndRecommendationScrollController(this);
- }
-
- public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
- boolean animateReset = mCurrentRecyclerView != null;
- if (mCurrentRecyclerView != null) {
- mCurrentRecyclerView.removeOnChildAttachStateChangeListener(this);
- }
- mCurrentRecyclerView = currentRecyclerView;
- mCurrentRecyclerView.addOnChildAttachStateChangeListener(this);
- findCurrentEmptyView();
- reset(animateReset);
- }
-
- public int getHeaderHeight() {
- return mHeaderHeight;
- }
-
- private void updateHeaderScroll() {
- mLastScroll = getCurrentScroll();
- mHeaderTitle.setTranslationY(mLastScroll);
- mRecommendedWidgetsTable.setTranslationY(mLastScroll);
-
- float searchYDisplacement = Math.max(mLastScroll, -mSearchBarContainer.getTop());
- mSearchBarContainer.setTranslationY(searchYDisplacement);
-
- if (mTabBar != null) {
- float tabsDisplacement = Math.max(mLastScroll, -mTabBar.getTop()
- + mSearchBarContainer.getHeight());
- mTabBar.setTranslationY(tabsDisplacement);
- }
- }
-
- private float getCurrentScroll() {
- return mScrollOffset + (mCurrentEmptySpaceView == null ? 0 : mCurrentEmptySpaceView.getY());
- }
-
- /**
- * Updates the scrollable header height
- *
- * @return {@code true} if the header height or dependent property changed.
- */
- public boolean updateHeaderHeight() {
- boolean hasSizeUpdated = false;
-
- int headerHeight = mContainer.getMeasuredHeight();
- if (headerHeight != mHeaderHeight) {
- mHeaderHeight = headerHeight;
- hasSizeUpdated = true;
- }
-
- if (mCurrentEmptySpaceView != null
- && mCurrentEmptySpaceView.setFixedHeight(mHeaderHeight)) {
- hasSizeUpdated = true;
- }
- return hasSizeUpdated;
- }
-
- /** Resets any previous view translation. */
- public void reset(boolean animate) {
- if (mOffsetAnimator != null) {
- mOffsetAnimator.cancel();
- mOffsetAnimator = null;
- }
-
- mScrollOffset = 0;
- if (!animate) {
- updateHeaderScroll();
- } else {
- float startValue = mLastScroll - getCurrentScroll();
- mOffsetAnimator = ObjectAnimator.ofFloat(this, SCROLL_OFFSET, startValue, 0);
- mOffsetAnimator.addListener(forEndCallback(() -> mOffsetAnimator = null));
- mOffsetAnimator.start();
- }
- }
-
- /**
- * Returns {@code true} if a touch event should be intercepted by this controller.
- */
- public boolean onInterceptTouchEvent(MotionEvent event) {
- return (mShouldForwardToRecyclerView = proxyMotionEvent(event, INTERCEPT_PROXY));
- }
-
- /**
- * Returns {@code true} if this controller has intercepted and consumed a touch event.
- */
- public boolean onTouchEvent(MotionEvent event) {
- return mShouldForwardToRecyclerView && proxyMotionEvent(event, TOUCH_PROXY);
- }
-
- private boolean proxyMotionEvent(MotionEvent event, MotionEventProxyMethod method) {
- float dx = mCurrentRecyclerView.getLeft() - mContainer.getLeft();
- float dy = mCurrentRecyclerView.getTop() - mContainer.getTop();
- event.offsetLocation(dx, dy);
- try {
- return method.proxyEvent(mCurrentRecyclerView, event);
- } finally {
- event.offsetLocation(-dx, -dy);
- }
- }
-
- @Override
- public void onChildViewAttachedToWindow(@NonNull View view) {
- if (view instanceof EmptySpaceView) {
- findCurrentEmptyView();
- }
- }
-
- @Override
- public void onChildViewDetachedFromWindow(@NonNull View view) {
- if (view == mCurrentEmptySpaceView) {
- findCurrentEmptyView();
- }
- }
-
- private void findCurrentEmptyView() {
- if (mCurrentEmptySpaceView != null) {
- mCurrentEmptySpaceView.setOnYChangeCallback(null);
- mCurrentEmptySpaceView = null;
- }
- int childCount = mCurrentRecyclerView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View view = mCurrentRecyclerView.getChildAt(i);
- if (view instanceof EmptySpaceView) {
- mCurrentEmptySpaceView = (EmptySpaceView) view;
- mCurrentEmptySpaceView.setFixedHeight(getHeaderHeight());
- mCurrentEmptySpaceView.setOnYChangeCallback(this::updateHeaderScroll);
- return;
- }
- }
- }
-
- private interface MotionEventProxyMethod {
-
- boolean proxyEvent(ViewGroup view, MotionEvent event);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsView.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsView.java
deleted file mode 100644
index 0d7d2b5e78..0000000000
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsView.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-/**
- * A {@link LinearLayout} container for holding search and widgets recommendation.
- *
- * This class intercepts touch events and dispatch them to the right view.
- */
-public class SearchAndRecommendationsView extends LinearLayout {
- private SearchAndRecommendationsScrollController mController;
-
- public SearchAndRecommendationsView(Context context) {
- this(context, /* attrs= */ null);
- }
-
- public SearchAndRecommendationsView(Context context, AttributeSet attrs) {
- this(context, attrs, /* defStyleAttr= */ 0);
- }
-
- public SearchAndRecommendationsView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, /* defStyleRes= */ 0);
- }
-
- public SearchAndRecommendationsView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- public void setSearchAndRecommendationScrollController(
- SearchAndRecommendationsScrollController controller) {
- mController = controller;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- return mController.onInterceptTouchEvent(event) || super.onInterceptTouchEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return mController.onTouchEvent(event) || super.onTouchEvent(event);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index a49cdc005a..88d9723546 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -62,11 +62,13 @@ import com.android.launcher3.pm.UserCache;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
+import com.android.launcher3.views.StickyHeaderLayout;
import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
+import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.util.WidgetsTableUtils;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -161,7 +163,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet
private boolean mIsNoWidgetsViewNeeded;
private int mMaxSpansPerRow = DEFAULT_MAX_HORIZONTAL_SPANS;
private TextView mNoWidgetsView;
- private SearchAndRecommendationsScrollController mSearchScrollController;
+
+ private StickyHeaderLayout mSearchScrollView;
+ private WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ private View mTabBar;
+ private View mSearchBarContainer;
+ private WidgetsSearchBar mSearchBar;
+ private TextView mHeaderTitle;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -214,17 +222,23 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
mNoWidgetsView = findViewById(R.id.no_widgets_text);
- mSearchScrollController = new SearchAndRecommendationsScrollController(
- findViewById(R.id.search_and_recommendations_container));
- mSearchScrollController.setCurrentRecyclerView(
- findViewById(R.id.primary_widgets_list_view));
- mSearchScrollController.mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
- mSearchScrollController.mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+
+ mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
+ mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
+
+ mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
+ mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+
+ mTabBar = mSearchScrollView.findViewById(R.id.tabs);
+ mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
+ mSearchBar = mSearchScrollView.findViewById(R.id.widgets_search_bar);
+ mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
onRecommendedWidgetsBound();
onWidgetsBound();
- mSearchScrollController.mSearchBar.initialize(
+ mSearchBar.initialize(
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
setUpEducationViewsIfNeeded();
@@ -258,7 +272,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
reset();
resetExpandedHeaders();
mCurrentWidgetsRecyclerView = recyclerView;
- mSearchScrollController.setCurrentRecyclerView(recyclerView);
+ mSearchScrollView.setCurrentRecyclerView(recyclerView);
}
}
@@ -285,7 +299,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
}
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
- mSearchScrollController.reset(/* animate= */ true);
+ mSearchScrollView.reset(/* animate= */ true);
}
@VisibleForTesting
@@ -355,8 +369,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
protected void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx) {
- setContentViewChildHorizontalMargin(mSearchScrollController.mContainer,
- contentHorizontalMarginInPx);
+ setContentViewChildHorizontalMargin(mSearchScrollView, contentHorizontalMarginInPx);
if (mViewPager == null) {
setContentViewChildHorizontalPadding(
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView,
@@ -390,16 +403,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mSearchScrollController.updateHeaderHeight()) {
- doMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
if (updateMaxSpansPerRow()) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (mSearchScrollController.updateHeaderHeight()) {
- doMeasure(widthMeasureSpec, heightMeasureSpec);
- }
}
}
@@ -460,7 +465,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
if (mHasWorkProfile) {
mViewPager.setVisibility(VISIBLE);
- mSearchScrollController.mTabBar.setVisibility(VISIBLE);
+ mTabBar.setVisibility(VISIBLE);
AdapterHolder workUserAdapterHolder = mAdapters.get(AdapterHolder.WORK);
workUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
onActivePageChanged(mViewPager.getCurrentPage());
@@ -508,10 +513,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet
private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
- mSearchScrollController.mRecommendedWidgetsTable.setVisibility(GONE);
+ mRecommendedWidgetsTable.setVisibility(GONE);
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
- mSearchScrollController.mTabBar.setVisibility(GONE);
+ mTabBar.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.setVisibility(GONE);
}
@@ -539,7 +544,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
List recommendedWidgets =
mActivityContext.getPopupDataProvider().getRecommendedWidgets();
- WidgetsRecommendationTableLayout table = mSearchScrollController.mRecommendedWidgetsTable;
if (recommendedWidgets.size() > 0) {
float noWidgetsViewHeight = 0;
if (mIsNoWidgetsViewNeeded) {
@@ -562,9 +566,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet
List> recommendedWidgetsInTable =
WidgetsTableUtils.groupWidgetItemsIntoTableWithoutReordering(
recommendedWidgets, mMaxSpansPerRow);
- table.setRecommendedWidgets(recommendedWidgetsInTable, maxTableHeight);
+ mRecommendedWidgetsTable.setRecommendedWidgets(
+ recommendedWidgetsInTable, maxTableHeight);
} else {
- table.setVisibility(GONE);
+ mRecommendedWidgetsTable.setVisibility(GONE);
}
}
@@ -619,10 +624,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mNoIntercept = !getRecyclerView().shouldContainerScroll(ev, getPopupContainer());
}
- if (mSearchScrollController.mSearchBar.isSearchBarFocused()
- && !getPopupContainer().isEventOverView(
- mSearchScrollController.mSearchBarContainer, ev)) {
- mSearchScrollController.mSearchBar.clearSearchBarFocus();
+ if (mSearchBar.isSearchBarFocused()
+ && !getPopupContainer().isEventOverView(mSearchBarContainer, ev)) {
+ mSearchBar.clearSearchBarFocus();
}
}
return super.onControllerInterceptTouchEvent(ev);
@@ -663,8 +667,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
public int getHeaderViewHeight() {
- return measureHeightWithVerticalMargins(mSearchScrollController.mHeaderTitle)
- + measureHeightWithVerticalMargins(mSearchScrollController.mSearchBarContainer);
+ return measureHeightWithVerticalMargins(mHeaderTitle)
+ + measureHeightWithVerticalMargins(mSearchBarContainer);
}
/** private the height, in pixel, + the vertical margins of a given view. */
@@ -681,14 +685,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mIsInSearchMode) {
- mSearchScrollController.mSearchBar.reset();
+ mSearchBar.reset();
}
}
@Override
public boolean onBackPressed() {
if (mIsInSearchMode) {
- mSearchScrollController.mSearchBar.reset();
+ mSearchBar.reset();
return true;
}
return super.onBackPressed();
@@ -701,10 +705,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
@Nullable private View getViewToShowEducationTip() {
- if (mSearchScrollController.mRecommendedWidgetsTable.getVisibility() == VISIBLE
- && mSearchScrollController.mRecommendedWidgetsTable.getChildCount() > 0) {
- return ((ViewGroup) mSearchScrollController.mRecommendedWidgetsTable.getChildAt(0))
- .getChildAt(0);
+ if (mRecommendedWidgetsTable.getVisibility() == VISIBLE
+ && mRecommendedWidgetsTable.getChildCount() > 0) {
+ return ((ViewGroup) mRecommendedWidgetsTable.getChildAt(0)).getChildAt(0);
}
AdapterHolder adapterHolder = mAdapters.get(mIsInSearchMode
@@ -801,7 +804,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
private int getEmptySpaceHeight() {
- return mSearchScrollController.getHeaderHeight();
+ return mSearchScrollView.getHeaderHeight();
}
void setup(WidgetsRecyclerView recyclerView) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java
index 1aa5753791..0c4f7aa7a2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java
@@ -15,16 +15,12 @@
*/
package com.android.launcher3.widget.picker;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-
-import android.content.Context;
-import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.launcher3.recyclerview.ViewHolderBinder;
+import com.android.launcher3.views.StickyHeaderLayout.EmptySpaceView;
import com.android.launcher3.widget.model.WidgetListSpaceEntry;
import java.util.List;
@@ -52,64 +48,4 @@ public class WidgetsSpaceViewHolderBinder
@ListPosition int position, List