diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java index 6781824d74..664377999d 100644 --- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java +++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java @@ -21,6 +21,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.widget.RelativeLayout; +import android.widget.TextView; import androidx.annotation.Nullable; @@ -39,9 +40,11 @@ final class SearchAndRecommendationsScrollController implements private final View mSearchAndRecommendationViewParent; private final WidgetsRecyclerView mPrimaryRecyclerView; private final WidgetsRecyclerView mSearchRecyclerView; + private final TextView mNoWidgetsView; private final int mTabsHeight; private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0); private final Point mTempOffset = new Point(); + private int mBottomInset; // The following are only non null if mHasWorkProfile is true. @Nullable private final WidgetsRecyclerView mWorkRecyclerView; @@ -81,7 +84,8 @@ final class SearchAndRecommendationsScrollController implements @Nullable WidgetsRecyclerView workRecyclerView, WidgetsRecyclerView searchRecyclerView, @Nullable View personalWorkTabsView, - @Nullable PersonalWorkPagedView primaryWorkViewPager) { + @Nullable PersonalWorkPagedView primaryWorkViewPager, + TextView noWidgetsView) { mHasWorkProfile = hasWorkProfile; mViewHolder = viewHolder; mViewHolder.mContainer.setSearchAndRecommendationScrollController(this); @@ -92,6 +96,7 @@ final class SearchAndRecommendationsScrollController implements mPrimaryWorkTabsView = personalWorkTabsView; mPrimaryWorkViewPager = primaryWorkViewPager; mTabsHeight = tabsHeight; + mNoWidgetsView = noWidgetsView; setCurrentRecyclerView(mPrimaryRecyclerView, /* animateReset= */ false); } @@ -113,6 +118,15 @@ final class SearchAndRecommendationsScrollController implements reset(animateReset); } + /** + * Updates padding of {@link WidgetsFullSheet} contents to include {@code bottomInset} wherever + * necessary. + */ + public boolean updateBottomInset(int bottomInset) { + mBottomInset = bottomInset; + return updateMarginAndPadding(); + } + /** * Updates the margin and padding of {@link WidgetsFullSheet} to accumulate collapsible views. * @@ -129,6 +143,8 @@ final class SearchAndRecommendationsScrollController implements + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable); int topContainerHeight = measureHeightWithVerticalMargins(mViewHolder.mContainer); + int noWidgetsViewHeight = topContainerHeight - mBottomInset; + if (mHasWorkProfile) { mCollapsibleHeightForTabs = measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle) + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable); @@ -180,6 +196,10 @@ final class SearchAndRecommendationsScrollController implements int topOffsetAfterAllViewsCollapsed = topContainerHeight + mTabsHeight - mCollapsibleHeightForTabs; + if (mPrimaryWorkTabsView.getVisibility() == View.VISIBLE) { + noWidgetsViewHeight += mTabsHeight; + } + RelativeLayout.LayoutParams viewPagerLayoutParams = (RelativeLayout.LayoutParams) mPrimaryWorkViewPager.getLayoutParams(); if (viewPagerLayoutParams.topMargin != topOffsetAfterAllViewsCollapsed) { @@ -222,6 +242,14 @@ final class SearchAndRecommendationsScrollController implements mSearchRecyclerView.getPaddingBottom()); hasMarginOrPaddingUpdated = true; } + if (mNoWidgetsView.getPaddingTop() != noWidgetsViewHeight) { + mNoWidgetsView.setPadding( + mNoWidgetsView.getPaddingLeft(), + noWidgetsViewHeight, + mNoWidgetsView.getPaddingRight(), + mNoWidgetsView.getPaddingBottom()); + hasMarginOrPaddingUpdated = true; + } return hasMarginOrPaddingUpdated; } diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index 42ff249a4a..039cad8291 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -92,8 +92,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet private final boolean mHasWorkProfile; private final SparseArray mAdapters = new SparseArray(); private final UserHandle mCurrentUser = Process.myUserHandle(); - private final Predicate mPrimaryWidgetsFilter = entry -> - mCurrentUser.equals(entry.mPkgItem.user); + private final Predicate mPrimaryWidgetsFilter = + entry -> mCurrentUser.equals(entry.mPkgItem.user); private final Predicate mWorkWidgetsFilter = mPrimaryWidgetsFilter.negate(); private final OnLayoutChangeListener mLayoutChangeListenerToShowTips = @@ -131,6 +131,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView; @Nullable private PersonalWorkPagedView mViewPager; private boolean mIsInSearchMode; + private boolean mIsNoWidgetsViewNeeded; private int mMaxSpansPerRow = 4; private View mTabsView; private TextView mNoWidgetsView; @@ -187,6 +188,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet layoutInflater.inflate(R.layout.widgets_full_sheet_search_and_recommendations, springLayout, true); + mNoWidgetsView = findViewById(R.id.no_widgets_text); mSearchAndRecommendationViewHolder = new SearchAndRecommendationViewHolder( findViewById(R.id.search_and_recommendations_container)); mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController( @@ -197,10 +199,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet mHasWorkProfile ? findViewById(R.id.work_widgets_list_view) : null, findViewById(R.id.search_widgets_list_view), mTabsView, - mViewPager); + mViewPager, + mNoWidgetsView); fastScroller.setOnFastScrollChangeListener(mSearchAndRecommendationsScrollController); - mNoWidgetsView = findViewById(R.id.no_widgets_text); onRecommendedWidgetsBound(); onWidgetsBound(); @@ -295,6 +297,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet if (mHasWorkProfile) { setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, insets.bottom); } + mSearchAndRecommendationsScrollController.updateBottomInset(insets.bottom); if (insets.bottom > 0) { setupNavBarColor(); } else { @@ -410,6 +413,16 @@ public class WidgetsFullSheet extends BaseWidgetSheet } else { updateRecyclerViewVisibility(primaryUserAdapterHolder); } + // Update recommended widgets section so that it occupies appropriate space on screen to + // leave enough space for presence/absence of mNoWidgetsView. + boolean isNoWidgetsViewNeeded = + mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.getItemCount() == 0 + || (mHasWorkProfile && mAdapters.get(AdapterHolder.WORK) + .mWidgetsListAdapter.getItemCount() == 0); + if (mIsNoWidgetsViewNeeded != isNoWidgetsViewNeeded) { + mIsNoWidgetsViewNeeded = isNoWidgetsViewNeeded; + onRecommendedWidgetsBound(); + } } @Override @@ -476,9 +489,19 @@ public class WidgetsFullSheet extends BaseWidgetSheet WidgetsRecommendationTableLayout table = mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable; if (recommendedWidgets.size() > 0) { - float maxTableHeight = - (mActivityContext.getDeviceProfile().availableHeightPx - mTabsHeight - - getHeaderViewHeight()) * RECOMMENDATION_TABLE_HEIGHT_RATIO; + float noWidgetsViewHeight = 0; + if (mIsNoWidgetsViewNeeded) { + // Make sure recommended section leaves enough space for noWidgetsView. + Rect noWidgetsViewTextBounds = new Rect(); + mNoWidgetsView.getPaint() + .getTextBounds(mNoWidgetsView.getText().toString(), /* start= */ 0, + mNoWidgetsView.getText().length(), noWidgetsViewTextBounds); + noWidgetsViewHeight = noWidgetsViewTextBounds.height(); + } + float maxTableHeight = (mActivityContext.getDeviceProfile().availableHeightPx + - mTabsHeight - getHeaderViewHeight() - noWidgetsViewHeight) + * RECOMMENDATION_TABLE_HEIGHT_RATIO; + List> recommendedWidgetsInTable = WidgetsTableUtils.groupWidgetItemsIntoTable(recommendedWidgets, mMaxSpansPerRow);