From 8796707172228fa74d77be0244568de73392983f Mon Sep 17 00:00:00 2001 From: Alina Zaidi Date: Tue, 1 Jun 2021 15:17:16 +0100 Subject: [PATCH 1/7] Update scrim in widget pickers. Also adjust padding in pin widget bottom sheet. Test: Tested manually Bug: 189802334 Change-Id: Ic25547ab1519139afdbf07aaefeb9168cf3501ff --- res/color-night-v31/widgets_picker_scrim.xml | 22 +++++++++++++++++++ res/color-v31/widgets_picker_scrim.xml | 22 +++++++++++++++++++ res/color/widgets_picker_scrim.xml | 22 +++++++++++++++++++ res/layout/add_item_confirmation_activity.xml | 4 +++- .../launcher3/dragndrop/AddItemActivity.java | 13 ++++++----- .../launcher3/views/WidgetsEduView.java | 4 +--- .../widget/AddItemWidgetsBottomSheet.java | 19 ++++++++++++++++ .../launcher3/widget/BaseWidgetSheet.java | 5 +---- 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 res/color-night-v31/widgets_picker_scrim.xml create mode 100644 res/color-v31/widgets_picker_scrim.xml create mode 100644 res/color/widgets_picker_scrim.xml diff --git a/res/color-night-v31/widgets_picker_scrim.xml b/res/color-night-v31/widgets_picker_scrim.xml new file mode 100644 index 0000000000..be7010b80b --- /dev/null +++ b/res/color-night-v31/widgets_picker_scrim.xml @@ -0,0 +1,22 @@ + + + + + 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/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 From da08cb26395a9f48504d3d0129c06c412801e5d2 Mon Sep 17 00:00:00 2001 From: zakcohen Date: Wed, 2 Jun 2021 15:46:46 -0700 Subject: [PATCH 2/7] RecentsView - reduce work in color tint animator Don't allocate animators when there is no animation to do. The work was not required. Bug: 189492167 Test: Local build, run and trace analysis Change-Id: I111768b055ed636aa92d5d9d6b799f316a568380 --- .../com/android/quickstep/views/RecentsView.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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 Date: Wed, 2 Jun 2021 15:55:06 -0700 Subject: [PATCH 3/7] TaskOverlayFactoryGo: Keep persistent instance of AssistContentRequester Holding a reference to AssistContentRequester prevents it from being deleted by the garbage collector while it is still in use. Bug: 189985872 Test: Manual (Pixel 3A) Test: m -j RunLauncherGoGoogleRoboTests Change-Id: I204aab907175a171c496c3bd146a8b23d2bbcf16 --- .../quickstep/TaskOverlayFactoryGo.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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. */ From 2b006fb27b81c03eb3afb1aef48073dd50e5d6a8 Mon Sep 17 00:00:00 2001 From: shawnlin Date: Thu, 3 Jun 2021 12:57:13 +0800 Subject: [PATCH 4/7] Detach the nav once the endTarget is determined as HOME Bug: 189900722 Test: manual - swipe up to home from an app and observe the nav Change-Id: I421de17fe4d8413deaf9ebd63166a6d2d00d096e --- .../src/com/android/quickstep/AbsSwipeUpHandler.java | 6 +++++- .../com/android/quickstep/RecentsAnimationController.java | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) 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 From abd33b38e2a37ca24b70247fff9fe80b9e38b975 Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Wed, 2 Jun 2021 16:57:18 +0000 Subject: [PATCH 5/7] 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. The previous logic is kept in the case that the layout manager returns null for any reason, which can happen before layout has occurred for the position. Fix: 189588014 Test: verified locally Change-Id: Ie8b5dcef50287e9e90a21f86e30a1ebcbbcba30f --- .../widget/picker/WidgetsRecyclerView.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) 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) { From eb367e471b03a9edbb4499a230e4d8433b596d9f Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Wed, 2 Jun 2021 16:21:54 +0000 Subject: [PATCH 6/7] Scroll to the selected widget picker row after headers are clicked This keeps the row in view. Currently, this will scroll the row to the centre-bottom of the screen due to the top padding being double counted, but that will remedied in a future CL. This also resolves the issue where the last row's widgets aren't visible by handling that case specially Fix: 188665456 Bug: 183378651 Test: verified locally Change-Id: I9acb9087a8cdaf130ac5955c810c96462b368f36 --- .../widget/picker/WidgetsListAdapter.java | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) 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. From 4981118478921c227fcba4f0991723efbc848a71 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 3 Jun 2021 09:52:40 -0700 Subject: [PATCH 7/7] Only inset widgets if workspaceTopPadding is greater than the widget padding. This prevents widget from becoming too close to status bar. Bug: 189724771 Test: manual Change-Id: I86f83b6a35bd2802bdbdf175340a379b498f481d --- src/com/android/launcher3/DeviceProfile.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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;