Loading res/layout/widget_recommendations.xml +4 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ android:layout_marginTop="16dp" android:accessibilityLiveRegion="polite" android:gravity="center_horizontal" android:layout_gravity="top" android:lineHeight="20sp" android:textColor="?attr/widgetPickerTitleColor" android:textFontWeight="500" Loading @@ -38,7 +39,7 @@ android:id="@+id/widget_recommendations_page_indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal|top" android:elevation="1dp" android:visibility="gone" /> <!-- Loading @@ -50,8 +51,9 @@ <com.android.launcher3.widget.picker.WidgetRecommendationsView android:id="@+id/widget_recommendations_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_height="0dp" android:layout_gravity="center" android:layout_weight="1" android:background="@drawable/widgets_surface_background" android:importantForAccessibility="yes" launcher:pageIndicator="@+id/widget_recommendations_page_indicator" /> Loading res/layout/widgets_two_pane_sheet.xml +1 −1 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ <LinearLayout android:id="@+id/widget_recommendations_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_height="match_parent" android:background="@drawable/widgets_surface_background" android:orientation="vertical" android:visibility="gone"> Loading src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java +34 −13 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.function.Consumer; /** * A {@link PagedView} that displays widget recommendations in categories with dots as paged Loading @@ -45,11 +46,13 @@ import java.util.TreeMap; */ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots> { private @Px float mAvailableHeight = Float.MAX_VALUE; private static final int MAX_CATEGORIES = 3; private TextView mRecommendationPageTitle; private final List<String> mCategoryTitles = new ArrayList<>(); /** Callbacks to run when page changes */ private final List<Consumer<Integer>> mPageSwitchListeners = new ArrayList<>(); @Nullable private OnLongClickListener mWidgetCellOnLongClickListener; @Nullable Loading Loading @@ -83,6 +86,13 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots mWidgetCellOnClickListener = widgetCellOnClickListener; } /** * Add a callback to run when the current displayed page changes. */ public void addPageSwitchListener(Consumer<Integer> pageChangeListener) { mPageSwitchListeners.add(pageChangeListener); } /** * Displays all the provided recommendations in a single table if they fit. * Loading @@ -104,7 +114,7 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots int displayedWidgets = maybeDisplayInTable(recommendedWidgets, deviceProfile, availableWidth, cellPadding); updateTitleAndIndicator(); updateTitleAndIndicator(/* requestedPage= */ 0); return displayedWidgets; } Loading @@ -119,16 +129,18 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots * @param availableWidth width in px that the recommendations should display in * @param cellPadding padding in px that should be applied to each widget in the * recommendations * @param requestedPage page number to display initially. * @return number of recommendations that could fit in the available space. */ public int setRecommendations( Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations, DeviceProfile deviceProfile, final @Px float availableHeight, final @Px int availableWidth, final @Px int cellPadding) { DeviceProfile deviceProfile, final @Px float availableHeight, final @Px int availableWidth, final @Px int cellPadding, final int requestedPage) { this.mAvailableHeight = availableHeight; Context context = getContext(); mPageIndicator.setPauseScroll(true, deviceProfile.isTwoPanels); // For purpose of recommendations section, we don't want paging dots to be halved in two // pane display, so, we always provide isTwoPanels = "false". mPageIndicator.setPauseScroll(/*pause=*/true, /*isTwoPanels=*/ false); clear(); int displayedCategories = 0; Loading @@ -153,26 +165,33 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots } } updateTitleAndIndicator(); mPageIndicator.setPauseScroll(false, deviceProfile.isTwoPanels); updateTitleAndIndicator(requestedPage); // For purpose of recommendations section, we don't want paging dots to be halved in two // pane display, so, we always provide isTwoPanels = "false". mPageIndicator.setPauseScroll(/*pause=*/false, /*isTwoPanels=*/false); return totalDisplayedWidgets; } private void clear() { mCategoryTitles.clear(); removeAllViews(); setCurrentPage(0); mPageIndicator.setActiveMarker(0); } /** Displays the page title and paging indicator if there are multiple pages. */ private void updateTitleAndIndicator() { private void updateTitleAndIndicator(int requestedPage) { boolean showPaginatedView = getPageCount() > 1; int titleAndIndicatorVisibility = showPaginatedView ? View.VISIBLE : View.GONE; mRecommendationPageTitle.setVisibility(titleAndIndicatorVisibility); mPageIndicator.setVisibility(titleAndIndicatorVisibility); if (showPaginatedView) { mPageIndicator.setActiveMarker(0); setCurrentPage(0); mRecommendationPageTitle.setText(mCategoryTitles.get(0)); if (requestedPage <= 0 || requestedPage >= getPageCount()) { requestedPage = 0; } setCurrentPage(requestedPage); mPageIndicator.setActiveMarker(requestedPage); mRecommendationPageTitle.setText(mCategoryTitles.get(requestedPage)); } } Loading @@ -180,7 +199,9 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots protected void notifyPageSwitchListener(int prevPage) { if (getPageCount() > 1) { // Since the title is outside the paging scroll, we update the title on page switch. mRecommendationPageTitle.setText(mCategoryTitles.get(getNextPage())); int nextPage = getNextPage(); mRecommendationPageTitle.setText(mCategoryTitles.get(nextPage)); mPageSwitchListeners.forEach(listener -> listener.accept(nextPage)); super.notifyPageSwitchListener(prevPage); } } Loading src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +81 −40 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package com.android.launcher3.widget.picker; import static android.view.View.MeasureSpec.makeMeasureSpec; import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions; import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; Loading @@ -30,6 +28,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.Process; import android.os.UserHandle; Loading Loading @@ -67,6 +66,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.model.UserManagerState; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.pm.UserCache; import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.views.RecyclerViewFastScroller; Loading @@ -81,7 +81,9 @@ import com.android.launcher3.workprofile.PersonalWorkPagedView; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.IntStream; Loading @@ -98,8 +100,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet // The widget recommendation table can easily take over the entire screen on devices with small // resolution or landscape on phone. This ratio defines the max percentage of content area that // the table can display. private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f; // the table can display with respect to bottom sheet's height. private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.45f; private static final String RECOMMENDATIONS_SAVED_STATE_KEY = "widgetsFullSheet:mRecommendationsCurrentPage"; private static final String SUPER_SAVED_STATE_KEY = "widgetsFullSheet:superHierarchyState"; private final UserCache mUserCache; private final UserManagerState mUserManagerState = new UserManagerState(); private final UserHandle mCurrentUser = Process.myUserHandle(); Loading @@ -109,8 +114,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet protected final boolean mHasWorkProfile; // Number of recommendations displayed protected int mRecommendedWidgetsCount; private List<WidgetItem> mRecommendedWidgets = new ArrayList<>(); private Map<WidgetRecommendationCategory, List<WidgetItem>> mRecommendedWidgetsMap = new HashMap<>(); protected int mRecommendationsCurrentPage = 0; protected final SparseArray<AdapterHolder> mAdapters = new SparseArray(); @Nullable private ArrowTipView mLatestEducationalTip; @Nullable private ArrowTipView mLatestEducationalTip; private final OnLayoutChangeListener mLayoutChangeListenerToShowTips = new OnLayoutChangeListener() { @Override Loading Loading @@ -156,14 +166,19 @@ public class WidgetsFullSheet extends BaseWidgetSheet } }; @Px private final int mTabsHeight; @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView; @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView; @Nullable PersonalWorkPagedView mViewPager; @Px private final int mTabsHeight; @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView; @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView; @Nullable PersonalWorkPagedView mViewPager; private boolean mIsInSearchMode; private boolean mIsNoWidgetsViewNeeded; @Px protected int mMaxSpanPerRow; @Px protected int mMaxSpanPerRow; protected DeviceProfile mDeviceProfile; protected TextView mNoWidgetsView; Loading Loading @@ -227,13 +242,16 @@ public class WidgetsFullSheet extends BaseWidgetSheet R.id.widget_recommendations_container); mWidgetRecommendationsView = mSearchScrollView.findViewById( R.id.widget_recommendations_view); // To save the currently displayed page, so that, it can be requested when rebinding // recommendations with different size constraints. mWidgetRecommendationsView.addPageSwitchListener( newPage -> mRecommendationsCurrentPage = newPage); mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer); mWidgetRecommendationsView.setWidgetCellLongClickListener(this); mWidgetRecommendationsView.setWidgetCellOnClickListener(this); mHeaderTitle = mSearchScrollView.findViewById(R.id.title); onRecommendedWidgetsBound(); onWidgetsBound(); setUpEducationViewsIfNeeded(); } Loading Loading @@ -354,7 +372,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet super.onAttachedToWindow(); LauncherAppState.getInstance(mActivityContext).getModel() .refreshAndBindWidgetsAndShortcuts(null); onRecommendedWidgetsBound(); } @Override Loading Loading @@ -582,16 +599,26 @@ public class WidgetsFullSheet extends BaseWidgetSheet } if (enableCategorizedWidgetSuggestions()) { // We avoid applying new recommendations when some are already displayed. if (mRecommendedWidgetsMap.isEmpty()) { mRecommendedWidgetsMap = mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(); } mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations( mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(), mRecommendedWidgetsMap, mDeviceProfile, /* availableHeight= */ getMaxAvailableHeightForRecommendations(), /* availableWidth= */ mMaxSpanPerRow, /* cellPadding= */ mWidgetCellHorizontalPadding /* cellPadding= */ mWidgetCellHorizontalPadding, /* requestedPage= */ mRecommendationsCurrentPage ); } else { if (mRecommendedWidgets.isEmpty()) { mRecommendedWidgets = mActivityContext.getPopupDataProvider().getRecommendedWidgets(); } mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations( mActivityContext.getPopupDataProvider().getRecommendedWidgets(), mRecommendedWidgets, mDeviceProfile, /* availableHeight= */ getMaxAvailableHeightForRecommendations(), /* availableWidth= */ mMaxSpanPerRow, Loading @@ -604,23 +631,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Px private float getMaxAvailableHeightForRecommendations() { 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(); } if (!isTwoPane()) { doMeasure( makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx, MeasureSpec.EXACTLY), makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx, MeasureSpec.EXACTLY)); } return getMaxTableHeight(noWidgetsViewHeight); return (mDeviceProfile.heightPx - mDeviceProfile.bottomSheetTopPadding) * getRecommendationSectionHeightRatio(); } /** b/209579563: "Widgets" header should be focused first. */ Loading @@ -629,12 +641,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet return mHeaderTitle; } /** * Ratio of recommendations section with respect to bottom sheet's height on scale of 0 to 1. */ @Px protected float getMaxTableHeight(@Px float noWidgetsViewHeight) { return (mContent.getMeasuredHeight() - mTabsHeight - getHeaderViewHeight() - noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO; protected float getRecommendationSectionHeightRatio() { return RECOMMENDATION_TABLE_HEIGHT_RATIO; } private void open(boolean animate) { Loading Loading @@ -705,6 +717,27 @@ public class WidgetsFullSheet extends BaseWidgetSheet return sheet; } @Override public void saveHierarchyState(SparseArray<Parcelable> sparseArray) { Bundle bundle = new Bundle(); // With widget picker open, when we open shade to switch theme, Launcher re-creates the // picker and calls save/restore hierarchy state. We save the state of recommendations // across those updates. bundle.putInt(RECOMMENDATIONS_SAVED_STATE_KEY, mRecommendationsCurrentPage); SparseArray<Parcelable> superState = new SparseArray<>(); super.saveHierarchyState(superState); bundle.putSparseParcelableArray(SUPER_SAVED_STATE_KEY, superState); sparseArray.put(0, bundle); } @Override public void restoreHierarchyState(SparseArray<Parcelable> sparseArray) { Bundle state = (Bundle) sparseArray.get(0); mRecommendationsCurrentPage = state.getInt( RECOMMENDATIONS_SAVED_STATE_KEY, /*defaultValue=*/0); super.restoreHierarchyState(state.getSparseParcelableArray(SUPER_SAVED_STATE_KEY)); } private static int getWidgetSheetId(BaseActivity activity) { boolean isTwoPane = (activity.getDeviceProfile().isTablet // Enables two pane picker for tablets in all orientations when the Loading Loading @@ -793,7 +826,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet /** private the height, in pixel, + the vertical margins of a given view. */ protected static int measureHeightWithVerticalMargins(View view) { if (view.getVisibility() != VISIBLE) { if (view == null || view.getVisibility() != VISIBLE) { return 0; } MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams(); Loading Loading @@ -828,6 +861,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet saveHierarchyState(widgetsState); handleClose(false); WidgetsFullSheet sheet = show(BaseActivity.fromContext(getContext()), false); sheet.restoreRecommendations(mRecommendedWidgets, mRecommendedWidgetsMap); sheet.restoreHierarchyState(widgetsState); sheet.restorePreviousAdapterHolderType(getCurrentAdapterHolderType()); } else if (!isTwoPane()) { Loading @@ -838,6 +872,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet mDeviceProfile = dp; } private void restoreRecommendations(List<WidgetItem> recommendedWidgets, Map<WidgetRecommendationCategory, List<WidgetItem>> recommendedWidgetsMap) { mRecommendedWidgets = recommendedWidgets; mRecommendedWidgetsMap = recommendedWidgetsMap; } /** * Indicates if layout should be re-created on device profile change - so that a different * layout can be displayed. Loading Loading @@ -887,7 +927,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet } } @Nullable private View getViewToShowEducationTip() { @Nullable private View getViewToShowEducationTip() { if (mWidgetRecommendationsContainer.getVisibility() == VISIBLE) { return mWidgetRecommendationsView.getViewForEducationTip(); } Loading src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +12 −4 Original line number Diff line number Diff line Loading @@ -62,6 +62,9 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { private static final int MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP = 395; private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry"; // This ratio defines the max percentage of content area that the recommendations can display // with respect to the bottom sheet's height. private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.75f; private FrameLayout mSuggestedWidgetsContainer; private WidgetsListHeader mSuggestedWidgetsHeader; private PackageUserKey mSuggestedWidgetsPackageUserKey; Loading Loading @@ -126,6 +129,10 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer); mWidgetRecommendationsView.setWidgetCellLongClickListener(this); mWidgetRecommendationsView.setWidgetCellOnClickListener(this); // To save the currently displayed page, so that, it can be requested when rebinding // recommendations with different size constraints. mWidgetRecommendationsView.addPageSwitchListener( newPage -> mRecommendationsCurrentPage = newPage); mHeaderTitle = mContent.findViewById(R.id.title); mRightPane = mContent.findViewById(R.id.right_pane); Loading @@ -139,7 +146,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider); mPrimaryWidgetListView.setClipToOutline(true); onRecommendedWidgetsBound(); onWidgetsBound(); setUpEducationViewsIfNeeded(); Loading Loading @@ -240,11 +246,13 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { String suggestionsRightPaneTitle = getContext().getString( R.string.widget_picker_right_pane_accessibility_title, suggestionsHeaderTitle); packageItemInfo.title = suggestionsHeaderTitle; // Suggestions may update at run time. The widgets count on suggestions doesn't add any // value, so, we don't show the count. WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create( packageItemInfo, /*titleSectionName=*/ suggestionsHeaderTitle, /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(), /*visibleWidgetsCount=*/ mRecommendedWidgetsCount) /*visibleWidgetsCount=*/ 0) .withWidgetListShown(); mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry); Loading @@ -266,8 +274,8 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { @Override @Px protected float getMaxTableHeight(@Px float noWidgetsViewHeight) { return mContent.getMeasuredHeight() - measureHeightWithVerticalMargins(mHeaderTitle); protected float getRecommendationSectionHeightRatio() { return RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE; } @Override Loading Loading
res/layout/widget_recommendations.xml +4 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ android:layout_marginTop="16dp" android:accessibilityLiveRegion="polite" android:gravity="center_horizontal" android:layout_gravity="top" android:lineHeight="20sp" android:textColor="?attr/widgetPickerTitleColor" android:textFontWeight="500" Loading @@ -38,7 +39,7 @@ android:id="@+id/widget_recommendations_page_indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal|top" android:elevation="1dp" android:visibility="gone" /> <!-- Loading @@ -50,8 +51,9 @@ <com.android.launcher3.widget.picker.WidgetRecommendationsView android:id="@+id/widget_recommendations_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_height="0dp" android:layout_gravity="center" android:layout_weight="1" android:background="@drawable/widgets_surface_background" android:importantForAccessibility="yes" launcher:pageIndicator="@+id/widget_recommendations_page_indicator" /> Loading
res/layout/widgets_two_pane_sheet.xml +1 −1 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ <LinearLayout android:id="@+id/widget_recommendations_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_height="match_parent" android:background="@drawable/widgets_surface_background" android:orientation="vertical" android:visibility="gone"> Loading
src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java +34 −13 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.function.Consumer; /** * A {@link PagedView} that displays widget recommendations in categories with dots as paged Loading @@ -45,11 +46,13 @@ import java.util.TreeMap; */ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots> { private @Px float mAvailableHeight = Float.MAX_VALUE; private static final int MAX_CATEGORIES = 3; private TextView mRecommendationPageTitle; private final List<String> mCategoryTitles = new ArrayList<>(); /** Callbacks to run when page changes */ private final List<Consumer<Integer>> mPageSwitchListeners = new ArrayList<>(); @Nullable private OnLongClickListener mWidgetCellOnLongClickListener; @Nullable Loading Loading @@ -83,6 +86,13 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots mWidgetCellOnClickListener = widgetCellOnClickListener; } /** * Add a callback to run when the current displayed page changes. */ public void addPageSwitchListener(Consumer<Integer> pageChangeListener) { mPageSwitchListeners.add(pageChangeListener); } /** * Displays all the provided recommendations in a single table if they fit. * Loading @@ -104,7 +114,7 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots int displayedWidgets = maybeDisplayInTable(recommendedWidgets, deviceProfile, availableWidth, cellPadding); updateTitleAndIndicator(); updateTitleAndIndicator(/* requestedPage= */ 0); return displayedWidgets; } Loading @@ -119,16 +129,18 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots * @param availableWidth width in px that the recommendations should display in * @param cellPadding padding in px that should be applied to each widget in the * recommendations * @param requestedPage page number to display initially. * @return number of recommendations that could fit in the available space. */ public int setRecommendations( Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations, DeviceProfile deviceProfile, final @Px float availableHeight, final @Px int availableWidth, final @Px int cellPadding) { DeviceProfile deviceProfile, final @Px float availableHeight, final @Px int availableWidth, final @Px int cellPadding, final int requestedPage) { this.mAvailableHeight = availableHeight; Context context = getContext(); mPageIndicator.setPauseScroll(true, deviceProfile.isTwoPanels); // For purpose of recommendations section, we don't want paging dots to be halved in two // pane display, so, we always provide isTwoPanels = "false". mPageIndicator.setPauseScroll(/*pause=*/true, /*isTwoPanels=*/ false); clear(); int displayedCategories = 0; Loading @@ -153,26 +165,33 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots } } updateTitleAndIndicator(); mPageIndicator.setPauseScroll(false, deviceProfile.isTwoPanels); updateTitleAndIndicator(requestedPage); // For purpose of recommendations section, we don't want paging dots to be halved in two // pane display, so, we always provide isTwoPanels = "false". mPageIndicator.setPauseScroll(/*pause=*/false, /*isTwoPanels=*/false); return totalDisplayedWidgets; } private void clear() { mCategoryTitles.clear(); removeAllViews(); setCurrentPage(0); mPageIndicator.setActiveMarker(0); } /** Displays the page title and paging indicator if there are multiple pages. */ private void updateTitleAndIndicator() { private void updateTitleAndIndicator(int requestedPage) { boolean showPaginatedView = getPageCount() > 1; int titleAndIndicatorVisibility = showPaginatedView ? View.VISIBLE : View.GONE; mRecommendationPageTitle.setVisibility(titleAndIndicatorVisibility); mPageIndicator.setVisibility(titleAndIndicatorVisibility); if (showPaginatedView) { mPageIndicator.setActiveMarker(0); setCurrentPage(0); mRecommendationPageTitle.setText(mCategoryTitles.get(0)); if (requestedPage <= 0 || requestedPage >= getPageCount()) { requestedPage = 0; } setCurrentPage(requestedPage); mPageIndicator.setActiveMarker(requestedPage); mRecommendationPageTitle.setText(mCategoryTitles.get(requestedPage)); } } Loading @@ -180,7 +199,9 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots protected void notifyPageSwitchListener(int prevPage) { if (getPageCount() > 1) { // Since the title is outside the paging scroll, we update the title on page switch. mRecommendationPageTitle.setText(mCategoryTitles.get(getNextPage())); int nextPage = getNextPage(); mRecommendationPageTitle.setText(mCategoryTitles.get(nextPage)); mPageSwitchListeners.forEach(listener -> listener.accept(nextPage)); super.notifyPageSwitchListener(prevPage); } } Loading
src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +81 −40 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package com.android.launcher3.widget.picker; import static android.view.View.MeasureSpec.makeMeasureSpec; import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions; import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; Loading @@ -30,6 +28,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.Process; import android.os.UserHandle; Loading Loading @@ -67,6 +66,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.model.UserManagerState; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.pm.UserCache; import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.views.RecyclerViewFastScroller; Loading @@ -81,7 +81,9 @@ import com.android.launcher3.workprofile.PersonalWorkPagedView; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.IntStream; Loading @@ -98,8 +100,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet // The widget recommendation table can easily take over the entire screen on devices with small // resolution or landscape on phone. This ratio defines the max percentage of content area that // the table can display. private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f; // the table can display with respect to bottom sheet's height. private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.45f; private static final String RECOMMENDATIONS_SAVED_STATE_KEY = "widgetsFullSheet:mRecommendationsCurrentPage"; private static final String SUPER_SAVED_STATE_KEY = "widgetsFullSheet:superHierarchyState"; private final UserCache mUserCache; private final UserManagerState mUserManagerState = new UserManagerState(); private final UserHandle mCurrentUser = Process.myUserHandle(); Loading @@ -109,8 +114,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet protected final boolean mHasWorkProfile; // Number of recommendations displayed protected int mRecommendedWidgetsCount; private List<WidgetItem> mRecommendedWidgets = new ArrayList<>(); private Map<WidgetRecommendationCategory, List<WidgetItem>> mRecommendedWidgetsMap = new HashMap<>(); protected int mRecommendationsCurrentPage = 0; protected final SparseArray<AdapterHolder> mAdapters = new SparseArray(); @Nullable private ArrowTipView mLatestEducationalTip; @Nullable private ArrowTipView mLatestEducationalTip; private final OnLayoutChangeListener mLayoutChangeListenerToShowTips = new OnLayoutChangeListener() { @Override Loading Loading @@ -156,14 +166,19 @@ public class WidgetsFullSheet extends BaseWidgetSheet } }; @Px private final int mTabsHeight; @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView; @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView; @Nullable PersonalWorkPagedView mViewPager; @Px private final int mTabsHeight; @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView; @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView; @Nullable PersonalWorkPagedView mViewPager; private boolean mIsInSearchMode; private boolean mIsNoWidgetsViewNeeded; @Px protected int mMaxSpanPerRow; @Px protected int mMaxSpanPerRow; protected DeviceProfile mDeviceProfile; protected TextView mNoWidgetsView; Loading Loading @@ -227,13 +242,16 @@ public class WidgetsFullSheet extends BaseWidgetSheet R.id.widget_recommendations_container); mWidgetRecommendationsView = mSearchScrollView.findViewById( R.id.widget_recommendations_view); // To save the currently displayed page, so that, it can be requested when rebinding // recommendations with different size constraints. mWidgetRecommendationsView.addPageSwitchListener( newPage -> mRecommendationsCurrentPage = newPage); mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer); mWidgetRecommendationsView.setWidgetCellLongClickListener(this); mWidgetRecommendationsView.setWidgetCellOnClickListener(this); mHeaderTitle = mSearchScrollView.findViewById(R.id.title); onRecommendedWidgetsBound(); onWidgetsBound(); setUpEducationViewsIfNeeded(); } Loading Loading @@ -354,7 +372,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet super.onAttachedToWindow(); LauncherAppState.getInstance(mActivityContext).getModel() .refreshAndBindWidgetsAndShortcuts(null); onRecommendedWidgetsBound(); } @Override Loading Loading @@ -582,16 +599,26 @@ public class WidgetsFullSheet extends BaseWidgetSheet } if (enableCategorizedWidgetSuggestions()) { // We avoid applying new recommendations when some are already displayed. if (mRecommendedWidgetsMap.isEmpty()) { mRecommendedWidgetsMap = mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(); } mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations( mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(), mRecommendedWidgetsMap, mDeviceProfile, /* availableHeight= */ getMaxAvailableHeightForRecommendations(), /* availableWidth= */ mMaxSpanPerRow, /* cellPadding= */ mWidgetCellHorizontalPadding /* cellPadding= */ mWidgetCellHorizontalPadding, /* requestedPage= */ mRecommendationsCurrentPage ); } else { if (mRecommendedWidgets.isEmpty()) { mRecommendedWidgets = mActivityContext.getPopupDataProvider().getRecommendedWidgets(); } mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations( mActivityContext.getPopupDataProvider().getRecommendedWidgets(), mRecommendedWidgets, mDeviceProfile, /* availableHeight= */ getMaxAvailableHeightForRecommendations(), /* availableWidth= */ mMaxSpanPerRow, Loading @@ -604,23 +631,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Px private float getMaxAvailableHeightForRecommendations() { 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(); } if (!isTwoPane()) { doMeasure( makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx, MeasureSpec.EXACTLY), makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx, MeasureSpec.EXACTLY)); } return getMaxTableHeight(noWidgetsViewHeight); return (mDeviceProfile.heightPx - mDeviceProfile.bottomSheetTopPadding) * getRecommendationSectionHeightRatio(); } /** b/209579563: "Widgets" header should be focused first. */ Loading @@ -629,12 +641,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet return mHeaderTitle; } /** * Ratio of recommendations section with respect to bottom sheet's height on scale of 0 to 1. */ @Px protected float getMaxTableHeight(@Px float noWidgetsViewHeight) { return (mContent.getMeasuredHeight() - mTabsHeight - getHeaderViewHeight() - noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO; protected float getRecommendationSectionHeightRatio() { return RECOMMENDATION_TABLE_HEIGHT_RATIO; } private void open(boolean animate) { Loading Loading @@ -705,6 +717,27 @@ public class WidgetsFullSheet extends BaseWidgetSheet return sheet; } @Override public void saveHierarchyState(SparseArray<Parcelable> sparseArray) { Bundle bundle = new Bundle(); // With widget picker open, when we open shade to switch theme, Launcher re-creates the // picker and calls save/restore hierarchy state. We save the state of recommendations // across those updates. bundle.putInt(RECOMMENDATIONS_SAVED_STATE_KEY, mRecommendationsCurrentPage); SparseArray<Parcelable> superState = new SparseArray<>(); super.saveHierarchyState(superState); bundle.putSparseParcelableArray(SUPER_SAVED_STATE_KEY, superState); sparseArray.put(0, bundle); } @Override public void restoreHierarchyState(SparseArray<Parcelable> sparseArray) { Bundle state = (Bundle) sparseArray.get(0); mRecommendationsCurrentPage = state.getInt( RECOMMENDATIONS_SAVED_STATE_KEY, /*defaultValue=*/0); super.restoreHierarchyState(state.getSparseParcelableArray(SUPER_SAVED_STATE_KEY)); } private static int getWidgetSheetId(BaseActivity activity) { boolean isTwoPane = (activity.getDeviceProfile().isTablet // Enables two pane picker for tablets in all orientations when the Loading Loading @@ -793,7 +826,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet /** private the height, in pixel, + the vertical margins of a given view. */ protected static int measureHeightWithVerticalMargins(View view) { if (view.getVisibility() != VISIBLE) { if (view == null || view.getVisibility() != VISIBLE) { return 0; } MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams(); Loading Loading @@ -828,6 +861,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet saveHierarchyState(widgetsState); handleClose(false); WidgetsFullSheet sheet = show(BaseActivity.fromContext(getContext()), false); sheet.restoreRecommendations(mRecommendedWidgets, mRecommendedWidgetsMap); sheet.restoreHierarchyState(widgetsState); sheet.restorePreviousAdapterHolderType(getCurrentAdapterHolderType()); } else if (!isTwoPane()) { Loading @@ -838,6 +872,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet mDeviceProfile = dp; } private void restoreRecommendations(List<WidgetItem> recommendedWidgets, Map<WidgetRecommendationCategory, List<WidgetItem>> recommendedWidgetsMap) { mRecommendedWidgets = recommendedWidgets; mRecommendedWidgetsMap = recommendedWidgetsMap; } /** * Indicates if layout should be re-created on device profile change - so that a different * layout can be displayed. Loading Loading @@ -887,7 +927,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet } } @Nullable private View getViewToShowEducationTip() { @Nullable private View getViewToShowEducationTip() { if (mWidgetRecommendationsContainer.getVisibility() == VISIBLE) { return mWidgetRecommendationsView.getViewForEducationTip(); } Loading
src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +12 −4 Original line number Diff line number Diff line Loading @@ -62,6 +62,9 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { private static final int MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP = 395; private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry"; // This ratio defines the max percentage of content area that the recommendations can display // with respect to the bottom sheet's height. private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.75f; private FrameLayout mSuggestedWidgetsContainer; private WidgetsListHeader mSuggestedWidgetsHeader; private PackageUserKey mSuggestedWidgetsPackageUserKey; Loading Loading @@ -126,6 +129,10 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer); mWidgetRecommendationsView.setWidgetCellLongClickListener(this); mWidgetRecommendationsView.setWidgetCellOnClickListener(this); // To save the currently displayed page, so that, it can be requested when rebinding // recommendations with different size constraints. mWidgetRecommendationsView.addPageSwitchListener( newPage -> mRecommendationsCurrentPage = newPage); mHeaderTitle = mContent.findViewById(R.id.title); mRightPane = mContent.findViewById(R.id.right_pane); Loading @@ -139,7 +146,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider); mPrimaryWidgetListView.setClipToOutline(true); onRecommendedWidgetsBound(); onWidgetsBound(); setUpEducationViewsIfNeeded(); Loading Loading @@ -240,11 +246,13 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { String suggestionsRightPaneTitle = getContext().getString( R.string.widget_picker_right_pane_accessibility_title, suggestionsHeaderTitle); packageItemInfo.title = suggestionsHeaderTitle; // Suggestions may update at run time. The widgets count on suggestions doesn't add any // value, so, we don't show the count. WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create( packageItemInfo, /*titleSectionName=*/ suggestionsHeaderTitle, /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(), /*visibleWidgetsCount=*/ mRecommendedWidgetsCount) /*visibleWidgetsCount=*/ 0) .withWidgetListShown(); mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry); Loading @@ -266,8 +274,8 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { @Override @Px protected float getMaxTableHeight(@Px float noWidgetsViewHeight) { return mContent.getMeasuredHeight() - measureHeightWithVerticalMargins(mHeaderTitle); protected float getRecommendationSectionHeightRatio() { return RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE; } @Override Loading