Merge changes from topic "standalone-fix" into main

* changes:
  [part 2] Update standalone picker to align widget loading and animations
  [part-1] Perform doMeasure only once in WidgetsFullSheet
This commit is contained in:
Shamali Patwa
2024-06-26 14:39:49 +00:00
committed by Android (Google) Code Review
5 changed files with 85 additions and 43 deletions
@@ -120,10 +120,6 @@ public class WidgetPickerActivity extends BaseActivity {
WindowInsetsController wc = mDragLayer.getWindowInsetsController();
wc.hide(navigationBars() + statusBars());
BaseWidgetSheet widgetSheet = WidgetsFullSheet.show(this, true);
widgetSheet.disableNavBarScrim(true);
widgetSheet.addOnCloseListener(this::finish);
parseIntentExtras();
refreshAndBindWidgets();
}
@@ -224,9 +220,10 @@ public class WidgetPickerActivity extends BaseActivity {
};
}
/** Updates the model with widgets and provides them after applying the provided filter. */
/** Updates the model with widgets, applies filters and launches the widgets sheet once
* widgets are available */
private void refreshAndBindWidgets() {
MODEL_EXECUTOR.execute(() -> {
MODEL_EXECUTOR.getHandler().postDelayed(() -> {
LauncherAppState app = LauncherAppState.getInstance(this);
mModel.update(app, null);
final List<WidgetsListBaseEntry> allWidgets =
@@ -240,6 +237,9 @@ public class WidgetPickerActivity extends BaseActivity {
}
);
bindWidgets(allWidgets);
// Open sheet once widgets are available, so that it doesn't interrupt the open
// animation.
openWidgetsSheet();
if (mUiSurface != null) {
Map<ComponentKey, WidgetItem> allWidgetItems = allWidgets.stream()
.filter(entry -> entry instanceof WidgetsListContentEntry)
@@ -253,15 +253,26 @@ public class WidgetPickerActivity extends BaseActivity {
mUiSurface, allWidgetItems);
mWidgetPredictionsRequester.request(mAddedWidgets, this::bindRecommendedWidgets);
}
});
}, mDeviceProfile.bottomSheetOpenDuration);
}
private void bindWidgets(List<WidgetsListBaseEntry> widgets) {
MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
}
private void openWidgetsSheet() {
MAIN_EXECUTOR.execute(() -> {
BaseWidgetSheet widgetSheet = WidgetsFullSheet.show(this, true);
widgetSheet.disableNavBarScrim(true);
widgetSheet.addOnCloseListener(this::finish);
});
}
private void bindRecommendedWidgets(List<ItemInfo> recommendedWidgets) {
MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets));
// Bind recommendations once picker has finished open animation.
MAIN_EXECUTOR.getHandler().postDelayed(
() -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets),
mDeviceProfile.bottomSheetOpenDuration);
}
@Override
@@ -65,6 +65,7 @@ public class WidgetPredictionsRequester {
private final Context mContext;
@NonNull
private final String mUiSurface;
private boolean mPredictionsAvailable;
@NonNull
private final Map<ComponentKey, WidgetItem> mAllWidgets;
@@ -76,8 +77,8 @@ public class WidgetPredictionsRequester {
}
/**
* Requests predictions from the app predictions manager and registers the provided callback to
* receive updates when predictions are available.
* Requests one time predictions from the app predictions manager and invokes provided callback
* once predictions are available.
*
* @param existingWidgets widgets that are currently added to the surface;
* @param callback consumer of prediction results to be called when predictions are
@@ -159,10 +160,14 @@ public class WidgetPredictionsRequester {
@WorkerThread
private void bindPredictions(List<AppTarget> targets, Predicate<WidgetItem> filter,
Consumer<List<ItemInfo>> callback) {
List<WidgetItem> filteredPredictions = filterPredictions(targets, mAllWidgets, filter);
List<ItemInfo> mappedPredictions = mapWidgetItemsToItemInfo(filteredPredictions);
if (!mPredictionsAvailable) {
mPredictionsAvailable = true;
List<WidgetItem> filteredPredictions = filterPredictions(targets, mAllWidgets, filter);
List<ItemInfo> mappedPredictions = mapWidgetItemsToItemInfo(filteredPredictions);
MAIN_EXECUTOR.execute(() -> callback.accept(mappedPredictions));
MAIN_EXECUTOR.execute(() -> callback.accept(mappedPredictions));
MODEL_EXECUTOR.execute(this::clear);
}
}
/**
@@ -214,5 +219,6 @@ public class WidgetPredictionsRequester {
mAppPredictor.destroy();
mAppPredictor = null;
}
mPredictionsAvailable = false;
}
}
@@ -331,8 +331,21 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
* status bar, into account.
*/
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthUsed = getInsetsWidth();
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
measureChildWithMargins(mContent, widthMeasureSpec,
widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
/**
* Returns the width used on left and right by the insets / padding.
*/
protected int getInsetsWidth() {
int widthUsed;
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
if (deviceProfile.isTablet) {
widthUsed = Math.max(2 * getTabletHorizontalMargin(deviceProfile),
2 * (mInsets.left + mInsets.right));
@@ -343,11 +356,7 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
widthUsed = Math.max(padding.left + padding.right,
2 * (mInsets.left + mInsets.right));
}
measureChildWithMargins(mContent, widthMeasureSpec,
widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
return widthUsed;
}
/** Returns the horizontal margins to be applied to the widget sheet. **/
@@ -55,7 +55,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -416,19 +415,18 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int availableWidth = MeasureSpec.getSize(widthMeasureSpec);
updateMaxSpansPerRow(availableWidth);
doMeasure(widthMeasureSpec, heightMeasureSpec);
if (updateMaxSpansPerRow()) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/** Returns {@code true} if the max spans have been updated. */
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
@Px int maxHorizontalSpan = getContentView().getMeasuredWidth()
- (2 * mContentHorizontalMargin);
/** Returns {@code true} if the max spans have been updated.
*
* @param availableWidth Total width available within parent (includes insets).
*/
private void updateMaxSpansPerRow(int availableWidth) {
@Px int maxHorizontalSpan = getAvailableWidthForSuggestions(
availableWidth - getInsetsWidth());
if (mMaxSpanPerRow != maxHorizontalSpan) {
mMaxSpanPerRow = maxHorizontalSpan;
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
@@ -439,16 +437,15 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
maxHorizontalSpan);
}
onRecommendedWidgetsBound();
return true;
post(this::onRecommendedWidgetsBound);
}
return false;
}
protected View getContentView() {
return mHasWorkProfile
? mViewPager
: mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
/**
* Returns the width available to display suggestions.
*/
protected int getAvailableWidthForSuggestions(int pickerAvailableWidth) {
return pickerAvailableWidth - (2 * mContentHorizontalMargin);
}
@Override
@@ -493,7 +490,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
.mWidgetsListAdapter.hasVisibleEntries());
if (mIsNoWidgetsViewNeeded != isNoWidgetsViewNeeded) {
mIsNoWidgetsViewNeeded = isNoWidgetsViewNeeded;
onRecommendedWidgetsBound();
post(this::onRecommendedWidgetsBound);
}
}
@@ -549,7 +546,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
onRecommendedWidgetsBound();
post(this::onRecommendedWidgetsBound);
onWidgetsBound();
}
}
@@ -322,6 +322,30 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
* RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE;
}
@Override
@Px
protected int getAvailableWidthForSuggestions(int pickerAvailableWidth) {
int rightPaneWidth = (int) Math.ceil(0.67 * pickerAvailableWidth);
if (mDeviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
// See onLayout
int leftPaneWidth = (int) (0.33 * pickerAvailableWidth);
@Px int minLeftPaneWidthPx = Utilities.dpToPx(MINIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
@Px int maxLeftPaneWidthPx = Utilities.dpToPx(MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
if (leftPaneWidth < minLeftPaneWidthPx) {
leftPaneWidth = minLeftPaneWidthPx;
} else if (leftPaneWidth > maxLeftPaneWidthPx) {
leftPaneWidth = maxLeftPaneWidthPx;
}
rightPaneWidth = pickerAvailableWidth - leftPaneWidth;
}
// Since suggestions are shown in right pane, the available width is 2/3 of total width of
// bottom sheet.
return rightPaneWidth - getResources().getDimensionPixelSize(
R.dimen.widget_list_horizontal_margin_two_pane); // right pane end margin.
}
@Override
public void onActivePageChanged(int currentActivePage) {
super.onActivePageChanged(currentActivePage);
@@ -384,11 +408,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
}
@Override
protected View getContentView() {
return mRightPane;
}
private HeaderChangeListener getHeaderChangeListener() {
return new HeaderChangeListener() {
@Override