diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index 754782bd49..65cdcf06ba 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -53,14 +53,17 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public static final int ERROR_PERMISSIONS = 1; private static final String TAG = "TaskOverlayFactoryGo"; - // Empty constructor required for ResourceBasedOverride - public TaskOverlayFactoryGo(Context context) {} + private AssistContentRequester mContentRequester; + + public TaskOverlayFactoryGo(Context context) { + mContentRequester = new AssistContentRequester(context); + } /** * Create a new overlay instance for the given View */ public TaskOverlayGo createOverlay(TaskThumbnailView thumbnailView) { - return new TaskOverlayGo(thumbnailView); + return new TaskOverlayGo(thumbnailView, mContentRequester); } /** @@ -72,9 +75,12 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { private String mTaskPackageName; private String mWebUrl; private boolean mAssistPermissionsEnabled; + private AssistContentRequester mFactoryContentRequester; - private TaskOverlayGo(TaskThumbnailView taskThumbnailView) { + private TaskOverlayGo(TaskThumbnailView taskThumbnailView, + AssistContentRequester assistContentRequester) { super(taskThumbnailView); + mFactoryContentRequester = assistContentRequester; } /** @@ -105,9 +111,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } int taskId = task.key.id; - AssistContentRequester contentRequester = - new AssistContentRequester(mApplicationContext); - contentRequester.requestAssistContent(taskId, this::onAssistContentReceived); + mFactoryContentRequester.requestAssistContent(taskId, this::onAssistContentReceived); } /** Provide Assist Content to the overlay. */ diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index be927e0107..306032cff2 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -972,6 +972,10 @@ public abstract class AbsSwipeUpHandler, } if (endTarget == HOME) { duration = HOME_DURATION; + // Early detach the nav bar once the endTarget is determined as HOME + if (mRecentsAnimationController != null) { + mRecentsAnimationController.detachNavigationBarFromApp(true); + } } else if (endTarget == RECENTS) { if (mRecentsView != null) { int nearestPage = mRecentsView.getDestinationPage(); @@ -1496,7 +1500,7 @@ public abstract class AbsSwipeUpHandler, if (LIVE_TILE.get()) { mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); if (mRecentsAnimationController != null) { - mRecentsAnimationController.getController().detachNavigationBarFromApp(true); + mRecentsAnimationController.detachNavigationBarFromApp(true); } } else if (!hasTargets() || mRecentsAnimationController == null) { // If there are no targets or the animation not started, then there is nothing to finish diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index 462f71440c..50d0569cf2 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -154,6 +154,14 @@ public class RecentsAnimationController { }); } + /** + * @see RecentsAnimationControllerCompat#detachNavigationBarFromApp + */ + @UiThread + public void detachNavigationBarFromApp(boolean moveHomeToTop) { + UI_HELPER_EXECUTOR.execute(() -> mController.detachNavigationBarFromApp(moveHomeToTop)); + } + /** * Sets the final surface transaction on a Task. This is used by Launcher to notify the system * that animating Activity to PiP has completed and the associated task surface should be diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index a0bba86e20..a4c60cf239 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -410,6 +410,7 @@ public abstract class RecentsView + + + + diff --git a/res/color-v31/widgets_picker_scrim.xml b/res/color-v31/widgets_picker_scrim.xml new file mode 100644 index 0000000000..648824ac1e --- /dev/null +++ b/res/color-v31/widgets_picker_scrim.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/res/color/widgets_picker_scrim.xml b/res/color/widgets_picker_scrim.xml new file mode 100644 index 0000000000..1cf97f61f7 --- /dev/null +++ b/res/color/widgets_picker_scrim.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml index ddc98156e9..9439baf1b3 100644 --- a/res/layout/add_item_confirmation_activity.xml +++ b/res/layout/add_item_confirmation_activity.xml @@ -31,7 +31,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/add_item_dialog_background" - android:padding="24dp" + android:paddingTop="24dp" android:theme="?attr/widgetsTheme" android:layout_gravity="bottom" android:orientation="vertical"> @@ -42,6 +42,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" + android:paddingHorizontal="24dp" android:textColor="?android:attr/textColorPrimary" android:textSize="24sp" android:ellipsize="end" @@ -53,6 +54,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" + android:paddingHorizontal="24dp" android:paddingTop="8dp" android:text="@string/add_item_request_drag_hint" android:textSize="14sp" diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index cdc09f10d6..e9245b0819 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -399,8 +399,10 @@ public class DeviceProfile { public boolean shouldInsetWidgets() { Rect widgetPadding = inv.defaultWidgetPadding; - // Check all sides to ensure that the widget won't overlap into another cell. - return cellLayoutBorderSpacingPx > widgetPadding.left + // Check all sides to ensure that the widget won't overlap into another cell, or into + // status bar. + return workspaceTopPadding > widgetPadding.top + && cellLayoutBorderSpacingPx > widgetPadding.left && cellLayoutBorderSpacingPx > widgetPadding.top && cellLayoutBorderSpacingPx > widgetPadding.right && cellLayoutBorderSpacingPx > widgetPadding.bottom; diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 5dae5a672d..b4288ce1f5 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -59,6 +59,7 @@ import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.views.AbstractSlideInView; import com.android.launcher3.views.BaseDragLayer; +import com.android.launcher3.widget.AddItemWidgetsBottomSheet; import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.NavigableAppWidgetHostView; @@ -89,6 +90,7 @@ public class AddItemActivity extends BaseActivity private LauncherAppState mApp; private InvariantDeviceProfile mIdp; private BaseDragLayer mDragLayer; + private AddItemWidgetsBottomSheet mSlideInView; private WidgetCell mWidgetCell; @@ -124,8 +126,6 @@ public class AddItemActivity extends BaseActivity mDragLayer = findViewById(R.id.add_item_drag_layer); mDragLayer.recreateControllers(); mDragLayer.setInsets(mDeviceProfile.getInsets()); - AbstractSlideInView slideInView = findViewById(R.id.add_item_bottom_sheet); - slideInView.addOnCloseListener(this); mWidgetCell = findViewById(R.id.widget_cell); if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) { @@ -151,6 +151,9 @@ public class AddItemActivity extends BaseActivity TextView widgetAppName = findViewById(R.id.widget_appName); widgetAppName.setText(getApplicationInfo().labelRes); + mSlideInView = findViewById(R.id.add_item_bottom_sheet); + mSlideInView.addOnCloseListener(this); + mSlideInView.show(); setupNavBarColor(); } @@ -279,7 +282,7 @@ public class AddItemActivity extends BaseActivity */ public void onCancelClick(View v) { logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED); - finish(); + mSlideInView.close(/* animate= */ true); } /** @@ -290,7 +293,7 @@ public class AddItemActivity extends BaseActivity ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo()); logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); mRequest.accept(); - finish(); + mSlideInView.close(/* animate= */ true); return; } @@ -313,7 +316,7 @@ public class AddItemActivity extends BaseActivity mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); mRequest.accept(mWidgetOptions); logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); - finish(); + mSlideInView.close(/* animate= */ true); } @Override diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java index e69cb5b04b..c6fa98a456 100644 --- a/src/com/android/launcher3/views/WidgetsEduView.java +++ b/src/com/android/launcher3/views/WidgetsEduView.java @@ -35,8 +35,6 @@ public class WidgetsEduView extends AbstractSlideInView implements Ins private static final int DEFAULT_CLOSE_DURATION = 200; - protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000; - private Rect mInsets = new Rect(); private View mEduView; @@ -87,7 +85,7 @@ public class WidgetsEduView extends AbstractSlideInView implements Ins @Override protected int getScrimColor(Context context) { - return FINAL_SCRIM_BG_COLOR; + return context.getResources().getColor(R.color.widgets_picker_scrim); } @Override diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java index 9e0830309e..804973f423 100644 --- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java @@ -23,8 +23,11 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.util.AttributeSet; +import android.view.ViewGroup; +import android.view.ViewParent; import com.android.launcher3.Insettable; +import com.android.launcher3.R; import com.android.launcher3.dragndrop.AddItemActivity; import com.android.launcher3.views.AbstractSlideInView; @@ -48,6 +51,17 @@ public class AddItemWidgetsBottomSheet extends AbstractSlideInView } protected int getScrimColor(Context context) { - int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha); - return setColorAlphaBound(context.getColor(R.color.wallpaper_popup_scrim), alpha); + return context.getResources().getColor(R.color.widgets_picker_scrim); } @Override diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index 7963431932..3936ec8e80 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -25,6 +25,7 @@ import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.TableRow; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.Adapter; @@ -48,8 +49,10 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.OptionalInt; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Recycler view adapter for the widget tray. @@ -87,6 +90,7 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC || new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) .equals(mWidgetsContentVisiblePackageUserKey); @Nullable private Predicate mFilter = null; + @Nullable private RecyclerView mRecyclerView; public WidgetsListAdapter(Context context, LayoutInflater layoutInflater, WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache, @@ -106,6 +110,16 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC layoutInflater, /*onHeaderClickListener=*/ this, /* listAdapter= */ this)); } + @Override + public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { + mRecyclerView = recyclerView; + } + + @Override + public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { + mRecyclerView = null; + } + public void setFilter(Predicate filter) { mFilter = filter; } @@ -168,12 +182,10 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mAllEntries.forEach(entry -> { if (entry instanceof WidgetsListHeaderEntry) { ((WidgetsListHeaderEntry) entry).setIsWidgetListShown( - new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) - .equals(mWidgetsContentVisiblePackageUserKey)); + isHeaderForVisibleContent(entry)); } else if (entry instanceof WidgetsListSearchHeaderEntry) { ((WidgetsListSearchHeaderEntry) entry).setIsWidgetListShown( - new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) - .equals(mWidgetsContentVisiblePackageUserKey)); + isHeaderForVisibleContent(entry)); } }); List newVisibleEntries = mAllEntries.stream() @@ -183,6 +195,13 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator); } + private boolean isHeaderForVisibleContent(WidgetsListBaseEntry entry) { + return (entry instanceof WidgetsListHeaderEntry + || entry instanceof WidgetsListSearchHeaderEntry) + && new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) + .equals(mWidgetsContentVisiblePackageUserKey); + } + /** * Resets any expanded widget header. */ @@ -247,12 +266,40 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC if (showWidgets) { mWidgetsContentVisiblePackageUserKey = packageUserKey; updateVisibleEntries(); + // Scroll the layout manager to the header position to keep it anchored to the same + // position. + scrollToSelectedHeaderPosition(); } else if (packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) { mWidgetsContentVisiblePackageUserKey = null; updateVisibleEntries(); } } + private void scrollToSelectedHeaderPosition() { + OptionalInt selectedHeaderPosition = + IntStream.range(0, mVisibleEntries.size()) + .filter(index -> isHeaderForVisibleContent(mVisibleEntries.get(index))) + .findFirst(); + RecyclerView.LayoutManager layoutManager = + mRecyclerView == null ? null : mRecyclerView.getLayoutManager(); + if (!selectedHeaderPosition.isPresent() || layoutManager == null) { + return; + } + + // Scroll to the selected header position. LinearLayoutManager scrolls the minimum distance + // necessary, so this will keep the selected header in place during clicks, without + // interrupting the animation. + int position = selectedHeaderPosition.getAsInt(); + if (position == mVisibleEntries.size() - 2) { + // If the selected header is in the last position (-1 for the content), then scroll to + // the final position so the last list of widgets will show. + layoutManager.scrollToPosition(mVisibleEntries.size() - 1); + } else { + // Otherwise, scroll to the position of the selected header. + layoutManager.scrollToPosition(position); + } + } + /** * Sets the max horizontal spans that are allowed for grouping more than one widgets in a table * row. diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index e30e245452..090362ba33 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -154,8 +154,25 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch return -1; } - View child = getChildAt(0); - int rowIndex = getChildPosition(child); + 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) {