From 840b42f66fff8898829140ae9e189a04c6120186 Mon Sep 17 00:00:00 2001 From: Jon Spivack Date: Fri, 26 Feb 2021 15:24:02 -0800 Subject: [PATCH 01/11] Pass Assistant web URI in NIU Actions The Task Overlay for the activity shown in Recents requests the AssistContent for that activity. If the content includes a web URI, this is added to the Intents sent by the NIU Actions buttons. Bug: 180157890 Test: Manual (tested with Chrome as the recent activity on local device) Test: TODO (b/179738220) Change-Id: I33c79e75678605693e0282e4ad82dc6af28957dd --- go/AndroidManifest.xml | 2 + .../quickstep/TaskOverlayFactoryGo.java | 80 +++++++++++++++++-- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml index f36439db53..2671604f94 100644 --- a/go/AndroidManifest.xml +++ b/go/AndroidManifest.xml @@ -24,6 +24,8 @@ + + The type of View in which the overlay will be placed */ public static final class TaskOverlayGo extends TaskOverlay { + private static final String ASSIST_KEY_CONTENT = "content"; - private String mPackageName; + private String mNIUPackageName; + private int mTaskId; + private Bundle mAssistData; + private final Handler mMainThreadHandler; private TaskOverlayGo(TaskThumbnailView taskThumbnailView) { super(taskThumbnailView); + mMainThreadHandler = new Handler(Looper.getMainLooper()); } /** @@ -70,16 +87,39 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix, boolean rotated) { getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null); - mPackageName = + mNIUPackageName = mApplicationContext.getResources().getString(R.string.niu_actions_package); - if (thumbnail == null || TextUtils.isEmpty(mPackageName)) { + if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) { return; } getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); boolean isAllowedByPolicy = thumbnail.isRealSnapshot; getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); + + mTaskId = task.key.id; + AssistDataReceiverImpl receiver = new AssistDataReceiverImpl(); + receiver.setOverlay(this); + + try { + ActivityTaskManager.getService().requestAssistDataForTask(receiver, mTaskId, + mApplicationContext.getPackageName()); + } catch (RemoteException e) { + Log.e(TAG, "Unable to request AssistData"); + } + } + + /** + * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's + * AssistDataRequester + */ + public void onAssistDataReceived(Bundle data) { + mMainThreadHandler.post(() -> { + if (data != null) { + mAssistData = data; + } + }); } private void sendNIUIntent(String actionType) { @@ -88,11 +128,21 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } private Intent createNIUIntent(String actionType) { - return new Intent(actionType) + Intent intent = new Intent(actionType) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) - .setPackage(mPackageName) + .setPackage(mNIUPackageName) .putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos()); + + if (mAssistData != null) { + final AssistContent content = mAssistData.getParcelable(ASSIST_KEY_CONTENT); + Uri webUri = (content == null) ? null : content.getWebUri(); + if (webUri != null) { + intent.putExtra(ACTIONS_URL, webUri.toString()); + } + } + + return intent; } protected class OverlayUICallbacksGoImpl extends OverlayUICallbacksImpl @@ -130,6 +180,26 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } } + /** + * Basic AssistDataReceiver. This is passed to ActivityTaskManagerService, which then requests + * the data. + */ + private static final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub { + private TaskOverlayGo mOverlay; + + public void setOverlay(TaskOverlayGo overlay) { + mOverlay = overlay; + } + + @Override + public void onHandleAssistData(Bundle data) { + mOverlay.onAssistDataReceived(data); + } + + @Override + public void onHandleAssistScreenshot(Bitmap screenshot) {} + } + /** * Callbacks the Ui can generate. This is the only way for a Ui to call methods on the * controller. From 116e94e0a7017ff417470db19f2d4b547218eefc Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 19 Mar 2021 17:21:22 -0400 Subject: [PATCH 02/11] Account for children margins when orienting popup container. Instead of recalculating the orientation after adding margins, we account for the margins in the initial calls to orientAboutObject. This ensures consistent mIsAboveIcon throughout calls to show the popup. - Also updates the smaller radius to match the middle items. Bug: 175329686 Test: long press on item where height and height without margins would result in differing mIsAboveIcon values eg. the 3rd item in a folder in the top middle of 5x5 workspace Change-Id: I6132b544a89c7948339d17f219ad75c797233f55 --- res/drawable/middle_item_primary.xml | 2 +- res/values/dimens.xml | 2 +- .../android/launcher3/popup/ArrowPopup.java | 21 ++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/res/drawable/middle_item_primary.xml b/res/drawable/middle_item_primary.xml index c9757142da..0c04ea14ec 100644 --- a/res/drawable/middle_item_primary.xml +++ b/res/drawable/middle_item_primary.xml @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index b60b6113e4..36ee6bb38c 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -192,7 +192,7 @@ 32dp 2dp 100dp - 4dp + 4dp 12dp 16dp 10dp diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index a53fe1f848..373653829b 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -130,13 +130,14 @@ public abstract class ArrowPopup extends Abstrac R.dimen.popup_arrow_horizontal_center_offset) - (mArrowWidth / 2); mArrowPointRadius = resources.getDimensionPixelSize(R.dimen.popup_arrow_corner_radius); + int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius); mRoundedTop = new GradientDrawable(); mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius, - mOutlineRadius, 0, 0, 0, 0}); + mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius}); mRoundedBottom = new GradientDrawable(); - mRoundedBottom.setCornerRadii(new float[] { 0, 0, 0, 0, mOutlineRadius, mOutlineRadius, - mOutlineRadius, mOutlineRadius}); + mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius, + smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius}); int primaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); int secondaryColor = Themes.getAttrColor(context, R.attr.popupColorSecondary); @@ -272,7 +273,6 @@ public abstract class ArrowPopup extends Abstrac } onInflationComplete(reverseOrder); assignMarginsAndBackgrounds(); - orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -286,7 +286,6 @@ public abstract class ArrowPopup extends Abstrac setupForDisplay(); onInflationComplete(false); assignMarginsAndBackgrounds(); - orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -383,10 +382,18 @@ public abstract class ArrowPopup extends Abstrac private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) { measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - int width = getMeasuredWidth(); int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding); - int height = getMeasuredHeight() + extraVerticalSpace; + // The margins are added after we call this method, so we need to account for them here. + int numVisibleChildren = 0; + for (int i = getChildCount() - 1; i >= 0; --i) { + if (getChildAt(i).getVisibility() == VISIBLE) { + numVisibleChildren++; + } + } + int childMargins = (numVisibleChildren - 1) * mMargin; + int height = getMeasuredHeight() + extraVerticalSpace + childMargins; + int width = getMeasuredWidth(); getTargetObjectLocation(mTempRect); InsettableFrameLayout dragLayer = getPopupContainer(); From a22574aa66ef8e122d2d332d60acfe9e0320d160 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 18 Mar 2021 22:37:33 -0700 Subject: [PATCH 03/11] Remove cursor when edit text no longer has focus Bug: 180142918 Test: manual Change-Id: I9a58ef605b145889e30cb42e99f0b98e16af1e46 Signed-off-by: Hyunyoung Song --- .../allapps/AllAppsRecyclerView.java | 1 + .../allapps/AllAppsSectionDecorator.java | 25 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index f307a53bc0..66575eb289 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -189,6 +189,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView { case SCROLL_STATE_DRAGGING: mgr.logger().sendToInteractionJankMonitor( LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this); + requestFocus(); getWindowInsetsController().hide(WindowInsets.Type.ime()); break; case SCROLL_STATE_IDLE: diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java index 7fcd6ec16f..0bd2f44cc9 100644 --- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java +++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java @@ -22,13 +22,11 @@ import android.graphics.Path; import android.graphics.RectF; import android.view.View; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; -import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager; import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.util.Themes; @@ -68,28 +66,6 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { } } - // Fallback logic in case non of the SearchTarget is labeled as focused item. - private void drawDecoration(@NonNull Canvas c, - @NonNull SectionDecorationHandler decorationHandler, - @NonNull RecyclerView parent) { - if (decorationHandler.mIsFullWidth) { - decorationHandler.mBounds.left = parent.getPaddingLeft(); - decorationHandler.mBounds.right = parent.getWidth() - parent.getPaddingRight(); - } - if (mAppsView.getFloatingHeaderView().getFocusedChild() == null - && mAppsView.getApps().getFocusedChild() != null) { - int index = mAppsView.getApps().getFocusedChildIndex(); - AppsGridLayoutManager layoutManager = (AppsGridLayoutManager) - mAppsView.getActiveRecyclerView().getLayoutManager(); - if (layoutManager.findFirstVisibleItemPosition() <= index - && index < parent.getChildCount()) { - RecyclerView.ViewHolder vh = parent.findViewHolderForAdapterPosition(index); - if (vh != null) decorationHandler.onFocusDraw(c, vh.itemView); - } - } - decorationHandler.reset(); - } - /** * Handles grouping and drawing of items in the same all apps sections. */ @@ -136,7 +112,6 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { */ public void onGroupDraw(Canvas canvas, View view) { if (view == null) return; - mPaint.setColor(mFillcolor); mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); onDraw(canvas); From 471922c5ac92741868d61b1d0de97e1ab8d3129c Mon Sep 17 00:00:00 2001 From: Yogisha Dixit Date: Mon, 22 Mar 2021 11:14:48 +0000 Subject: [PATCH 04/11] Do not allow widget to be resized beyond max size. Test: manual Bug: 179807199 Change-Id: I38e108a8db2c5f06c0922972efa334e3b2864046 --- .../launcher3/AppWidgetResizeFrame.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 8071782617..d02efb0100 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -100,6 +100,8 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private int mRunningVInc; private int mMinHSpan; private int mMinVSpan; + private int mMaxHSpan; + private int mMaxVSpan; private int mDeltaX; private int mDeltaY; private int mDeltaXAddOn; @@ -183,6 +185,8 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mMinHSpan = info.minSpanX; mMinVSpan = info.minSpanY; + mMaxHSpan = info.maxSpanX; + mMaxVSpan = info.maxSpanY; mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(), widgetView.getAppWidgetInfo().provider, null); @@ -314,7 +318,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O // expandability. mTempRange1.set(cellX, spanX + cellX); int hSpanDelta = mTempRange1.applyDeltaAndBound(mLeftBorderActive, mRightBorderActive, - hSpanInc, mMinHSpan, mCellLayout.getCountX(), mTempRange2); + hSpanInc, mMinHSpan, mMaxHSpan, mCellLayout.getCountX(), mTempRange2); cellX = mTempRange2.start; spanX = mTempRange2.size(); if (hSpanDelta != 0) { @@ -323,7 +327,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mTempRange1.set(cellY, spanY + cellY); int vSpanDelta = mTempRange1.applyDeltaAndBound(mTopBorderActive, mBottomBorderActive, - vSpanInc, mMinVSpan, mCellLayout.getCountY(), mTempRange2); + vSpanInc, mMinVSpan, mMaxVSpan, mCellLayout.getCountY(), mTempRange2); cellY = mTempRange2.start; spanY = mTempRange2.size(); if (vSpanDelta != 0) { @@ -642,12 +646,15 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O * @param minSize minimum size after with the moving edge should not be shifted any further. * For eg, if delta = -3 when moving the endEdge brings the size to less than * minSize, only delta = -2 will applied + * @param maxSize maximum size after with the moving edge should not be shifted any further. + * For eg, if delta = -3 when moving the endEdge brings the size to greater + * than maxSize, only delta = -2 will applied * @param maxEnd The maximum value to the end edge (start edge is always restricted to 0) * @return the amount of increase when endEdge was moves and the amount of decrease when * the start edge was moved. */ public int applyDeltaAndBound(boolean moveStart, boolean moveEnd, int delta, - int minSize, int maxEnd, IntRange out) { + int minSize, int maxSize, int maxEnd, IntRange out) { applyDelta(moveStart, moveEnd, delta, out); if (out.start < 0) { out.start = 0; @@ -662,6 +669,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O out.end = out.start + minSize; } } + if (out.size() > maxSize) { + if (moveStart) { + out.start = out.end - maxSize; + } else if (moveEnd) { + out.end = out.start + maxSize; + } + } return moveEnd ? out.size() - size() : size() - out.size(); } } From e4c0e954d3ed452134e1db8c5523fde55fa90765 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Fri, 19 Mar 2021 22:51:09 +0000 Subject: [PATCH 05/11] Exact common layout from widgets bottom sheet Test: open widgets bottom sheet and drag and drop widgets & shortcuts. Bug: 182305634 Change-Id: I82e3e584edf64177ffa6e677f5b3f487823d3e1b --- res/layout/widgets_bottom_sheet.xml | 36 +------------- res/layout/widgets_bottom_sheet_content.xml | 53 +++++++++++++++++++++ 2 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 res/layout/widgets_bottom_sheet_content.xml diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml index d18ba568cf..8002d1ddc7 100644 --- a/res/layout/widgets_bottom_sheet.xml +++ b/res/layout/widgets_bottom_sheet.xml @@ -24,41 +24,7 @@ android:elevation="@dimen/deep_shortcuts_elevation" android:layout_gravity="bottom" android:theme="?attr/widgetsTheme"> - - - - - - - + \ No newline at end of file diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml new file mode 100644 index 0000000000..916ff1baf7 --- /dev/null +++ b/res/layout/widgets_bottom_sheet_content.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + From 05df2843ee8fcec539363a84b253e28b09c07e47 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Mon, 22 Mar 2021 20:22:21 +0000 Subject: [PATCH 06/11] Increase the number of prediction for widgets model Test: launch all widgets tray and observes widgets predicted. Bug: 179797520 Change-Id: Id231cde5015a2a79b7532a39343b3340c27e09c9 --- .../com/android/launcher3/model/QuickstepModelDelegate.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index b1b4d70152..df3657d01d 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -73,6 +73,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS"; + private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20; private static final boolean IS_DEBUG = false; private static final String TAG = "QuickstepModelDelegate"; @@ -217,7 +218,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange registerWidgetsPredictor(apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("widgets") - .setPredictedTargetCount(mIDP.numColumns) + .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION) .build())); } From 62e08797f3096b0f67efbb0c380578781016cbb1 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 22 Mar 2021 15:13:21 -0700 Subject: [PATCH 07/11] Fix extra haptic on swipe up Test: swipe up in 0 button mode, no haptic until pause detected Bug: 181165935 Change-Id: I69b598cf8e1ac1038d5cfad0f43468a8d7d23e4a --- quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 6da2201dc9..496d5a67bb 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -617,7 +617,7 @@ public abstract class AbsSwipeUpHandler, final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (passed != mPassedOverviewThreshold) { mPassedOverviewThreshold = passed; - if (!mDeviceState.isTwoButtonNavMode()) { + if (mDeviceState.isTwoButtonNavMode()) { performHapticFeedback(); } } From 867ff5f60cd2941a0b06d410da0d2665c209b6a3 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Mon, 22 Mar 2021 18:25:19 +0000 Subject: [PATCH 08/11] Update title of bottom widgets tray Only use the "app name" instead of "app name widgets" as title Remove "Touch & hold to move a widget" subtitle. Test: manual Bug: 179797520 Change-Id: I7a5954af73aa5b480096e93ade3520cef6c93f17 --- res/layout/widgets_bottom_sheet_content.xml | 10 ---------- res/values/strings.xml | 2 -- .../android/launcher3/widget/WidgetsBottomSheet.java | 3 +-- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml index 916ff1baf7..a9d523ae57 100644 --- a/res/layout/widgets_bottom_sheet_content.xml +++ b/res/layout/widgets_bottom_sheet_content.xml @@ -29,16 +29,6 @@ android:textColor="?android:attr/textColorPrimary" android:textSize="24sp"/> - - %1$s waiting to install - - %1$s widgets Widgets list diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 267f9f72c0..2fda86c89c 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -119,8 +119,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { public void populateAndShow(ItemInfo itemInfo) { mOriginalItemInfo = itemInfo; - ((TextView) findViewById(R.id.title)).setText(getContext().getString( - R.string.widgets_bottom_sheet_title, mOriginalItemInfo.title)); + ((TextView) findViewById(R.id.title)).setText(mOriginalItemInfo.title); onWidgetsBound(); attachToContainer(); From 9ce3b25ef6f30418558da49efead328d5353210b Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 22 Mar 2021 14:43:58 -0700 Subject: [PATCH 09/11] Add TaskbarView as a child of Hotseat Instead of keeping the Taskbar window showing above the home screen, we now integrate a copy of TaskbarView directly into Launcher's view hierarchy. Most TaskbarController calls apply to both TaskbarViews (mTaskbarViewInApp and mTaskbarViewOnHome), except for calls related to Hotseat, which only apply to mTasbkarViewInApp given the real Hotseat will be showing with mTaskbarViewOnHome. More cleanup will follow this change. Test: All taskbar interactions (e.g. drag and drop) continue to work Bug: 182512211 Bug: 171917176 Change-Id: I0f0b124f652daa85f866e1df8f9e2981540331a0 --- quickstep/res/layout/taskbar_divider.xml | 2 - quickstep/res/layout/taskbar_view.xml | 26 ++++ .../launcher3/BaseQuickstepLauncher.java | 4 +- .../taskbar/TaskbarActivityContext.java | 5 +- .../taskbar/TaskbarContainerView.java | 2 +- .../launcher3/taskbar/TaskbarController.java | 145 +++++++++++------- .../launcher3/taskbar/TaskbarView.java | 91 +++++++---- .../util/StaggeredWorkspaceAnim.java | 26 +++- res/layout/taskbar_view.xml | 21 +++ src/com/android/launcher3/Hotseat.java | 44 ++++-- src/com/android/launcher3/LauncherState.java | 7 +- .../WorkspaceStateTransitionAnimation.java | 5 +- .../launcher3/views/ActivityContext.java | 18 ++- 13 files changed, 264 insertions(+), 132 deletions(-) create mode 100644 quickstep/res/layout/taskbar_view.xml create mode 100644 res/layout/taskbar_view.xml diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml index 6e1aa1e3d5..87649f752e 100644 --- a/quickstep/res/layout/taskbar_divider.xml +++ b/quickstep/res/layout/taskbar_divider.xml @@ -18,6 +18,4 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/taskbar_divider_thickness" android:layout_height="@dimen/taskbar_divider_height" - android:layout_marginStart="@dimen/taskbar_icon_spacing" - android:layout_marginEnd="@dimen/taskbar_icon_spacing" android:background="@color/taskbar_divider" /> \ No newline at end of file diff --git a/quickstep/res/layout/taskbar_view.xml b/quickstep/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..34a88ea6a2 --- /dev/null +++ b/quickstep/res/layout/taskbar_view.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index c4becf105f..9ab49cebfa 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -46,6 +46,7 @@ import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarController; import com.android.launcher3.taskbar.TaskbarStateHandler; +import com.android.launcher3.taskbar.TaskbarView; import com.android.launcher3.uioverrides.RecentsViewStateController; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.DisplayController; @@ -243,9 +244,10 @@ public abstract class BaseQuickstepLauncher extends Launcher mTaskbarController = null; } if (mDeviceProfile.isTaskbarPresent) { + TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView(); TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this); mTaskbarController = new TaskbarController(this, - taskbarActivityContext.getTaskbarContainerView()); + taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome); mTaskbarController.init(); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8312b82062..fc5e2c1740 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -54,10 +54,7 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo return mTaskbarContainerView; } - /** - * @return A LayoutInflater to use in this Context. Views inflated with this LayoutInflater will - * be able to access this TaskbarActivityContext via ActivityContext.lookupContext(). - */ + @Override public LayoutInflater getLayoutInflater() { return mLayoutInflater; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java index 528f43e699..5202d91684 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java @@ -84,7 +84,7 @@ public class TaskbarContainerView extends BaseDragLayer private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() { return insetsInfo -> { if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD - || mTaskbarView.isDraggingItem()) { + || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) { // We're invisible or dragging out of taskbar, let touches pass through us. insetsInfo.touchableRegion.setEmpty(); insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index f652961629..abf6d54146 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -19,8 +19,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_TASKBAR; -import static com.android.launcher3.AbstractFloatingView.TYPE_REPLACE_TASKBAR_WITH_HOTSEAT; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; @@ -43,7 +41,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Hotseat; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; @@ -54,6 +51,7 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -70,7 +68,8 @@ public class TaskbarController { private static final String WINDOW_TITLE = "Taskbar"; private final TaskbarContainerView mTaskbarContainerView; - private final TaskbarView mTaskbarView; + private final TaskbarView mTaskbarViewInApp; + private final TaskbarView mTaskbarViewOnHome; private final BaseQuickstepLauncher mLauncher; private final WindowManager mWindowManager; // Layout width and height of the Taskbar in the default state. @@ -91,14 +90,17 @@ public class TaskbarController { private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; + private boolean mIsAnimatingToApp; public TaskbarController(BaseQuickstepLauncher launcher, - TaskbarContainerView taskbarContainerView) { + TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) { mLauncher = launcher; mTaskbarContainerView = taskbarContainerView; mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks()); - mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); - mTaskbarView.construct(createTaskbarViewCallbacks()); + mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view); + mTaskbarViewInApp.construct(createTaskbarViewCallbacks()); + mTaskbarViewOnHome = taskbarViewOnHome; + mTaskbarViewOnHome.construct(createTaskbarViewCallbacks()); mWindowManager = mLauncher.getWindowManager(); mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize); mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); @@ -115,12 +117,13 @@ public class TaskbarController { return new TaskbarVisibilityControllerCallbacks() { @Override public void updateTaskbarBackgroundAlpha(float alpha) { - mTaskbarView.setBackgroundAlpha(alpha); + mTaskbarViewInApp.setBackgroundAlpha(alpha); } @Override public void updateTaskbarVisibilityAlpha(float alpha) { mTaskbarContainerView.setAlpha(alpha); + mTaskbarViewOnHome.setAlpha(alpha); } }; } @@ -196,7 +199,7 @@ public class TaskbarController { public View.OnLongClickListener getItemOnLongClickListener() { return view -> { if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) { - alignRealHotseatWithTaskbar(); + // TODO: remove this path return mDragController.startWorkspaceDragOnLongClick(view); } else { return mDragController.startSystemDragOnLongClick(view); @@ -205,11 +208,24 @@ public class TaskbarController { } @Override - public int getEmptyHotseatViewVisibility() { + public int getEmptyHotseatViewVisibility(TaskbarView taskbarView) { // When on the home screen, we want the empty hotseat views to take up their full // space so that the others line up with the home screen hotseat. - return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher - ? View.INVISIBLE : View.GONE; + boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome + || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher; + return isOnHomeScreen ? View.INVISIBLE : View.GONE; + } + + @Override + public float getNonIconScale(TaskbarView taskbarView) { + return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f; + } + + @Override + public void onItemPositionsChanged(TaskbarView taskbarView) { + if (taskbarView == mTaskbarViewOnHome) { + alignRealHotseatWithTaskbar(); + } } }; } @@ -218,7 +234,7 @@ public class TaskbarController { return new TaskbarHotseatControllerCallbacks() { @Override public void updateHotseatItems(ItemInfo[] hotseatItemInfos) { - mTaskbarView.updateHotseatItems(hotseatItemInfos); + mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos); mLatestLoadedHotseatItems = hotseatItemInfos; dedupeAndUpdateRecentItems(); } @@ -235,7 +251,8 @@ public class TaskbarController { @Override public void updateRecentTaskAtIndex(int taskIndex, Task task) { - mTaskbarView.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task); } }; } @@ -244,16 +261,20 @@ public class TaskbarController { * Initializes the Taskbar, including adding it to the screen. */ public void init() { - mTaskbarView.init(mHotseatController.getNumHotseatIcons(), + mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(), mRecentsController.getNumRecentIcons()); - mTaskbarContainerView.init(mTaskbarView); + mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(), + mRecentsController.getNumRecentIcons()); + mTaskbarContainerView.init(mTaskbarViewInApp); addToWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks()); mTaskbarVisibilityController.init(); mHotseatController.init(); mRecentsController.init(); - SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f); + SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed() + ? getTaskbarScaleOnHome() : 1f); + updateWhichTaskbarViewIsVisible(); } private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() { @@ -274,7 +295,8 @@ public class TaskbarController { mAnimator.end(); } - mTaskbarView.cleanup(); + mTaskbarViewInApp.cleanup(); + mTaskbarViewOnHome.cleanup(); mTaskbarContainerView.cleanup(); removeFromWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(null); @@ -313,7 +335,7 @@ public class TaskbarController { TaskbarContainerView.LayoutParams taskbarLayoutParams = new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y); taskbarLayoutParams.gravity = gravity; - mTaskbarView.setLayoutParams(taskbarLayoutParams); + mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams); mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams); } @@ -330,7 +352,6 @@ public class TaskbarController { mAnimator = createAnimToLauncher(null, duration); } else { mAnimator = createAnimToApp(duration); - replaceTaskbarWithHotseatOrViceVersa(); } mAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -351,36 +372,41 @@ public class TaskbarController { if (toState != null) { mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim); } - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), getTaskbarScaleOnHome(), LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = true; - mTaskbarView.updateHotseatItemsVisibility(); + mTaskbarViewInApp.updateHotseatItemsVisibility(); } @Override public void onAnimationEnd(Animator animation) { mIsAnimatingToLauncher = false; + updateWhichTaskbarViewIsVisible(); } }); - anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar); - return anim.buildAnim(); } private Animator createAnimToApp(long duration) { PendingAnimation anim = new PendingAnimation(duration); anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration)); - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR); + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mTaskbarView.updateHotseatItemsVisibility(); - setReplaceTaskbarWithHotseat(false); + mIsAnimatingToApp = true; + mTaskbarViewInApp.updateHotseatItemsVisibility(); + updateWhichTaskbarViewIsVisible(); + } + + @Override + public void onAnimationEnd(Animator animation) { + mIsAnimatingToApp = false; } }); return anim.buildAnim(); @@ -405,11 +431,11 @@ public class TaskbarController { * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. */ public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { - return mTaskbarView.isEventOverAnyItem(ev); + return mTaskbarViewInApp.isEventOverAnyItem(ev); } public boolean isDraggingItem() { - return mTaskbarView.isDraggingItem(); + return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem(); } private void dedupeAndUpdateRecentItems() { @@ -454,7 +480,8 @@ public class TaskbarController { tasksArray[tasksArray.length - 1 - i] = task; } - mTaskbarView.updateRecentTasks(tasksArray); + mTaskbarViewInApp.updateRecentTasks(tasksArray); + mTaskbarViewOnHome.updateRecentTasks(tasksArray); mRecentsController.loadIconsForTasks(tasksArray); } @@ -475,10 +502,11 @@ public class TaskbarController { int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize; int hotseatTopDiff = hotseatHeight - grid.taskbarSize; - mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds); - mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff, - mTaskbarView.getWidth() - hotseatBounds.right, - mTaskbarView.getHeight() - hotseatBounds.bottom); + mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds); + mLauncher.getHotseat().setPadding(hotseatBounds.left, + hotseatBounds.top + hotseatTopDiff, + mTaskbarViewOnHome.getWidth() - hotseatBounds.right, + mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom); } /** @@ -486,36 +514,32 @@ public class TaskbarController { * show the real one instead. */ public void onLauncherDragLayerHierarchyChanged() { - replaceTaskbarWithHotseatOrViceVersa(); + // TODO: remove, as this is a no-op now } - private void replaceTaskbarWithHotseatOrViceVersa() { - boolean replaceTaskbarWithHotseat = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_REPLACE_TASKBAR_WITH_HOTSEAT) != null; - if (!mLauncher.hasBeenResumed()) { - replaceTaskbarWithHotseat = false; - } - setReplaceTaskbarWithHotseat(replaceTaskbarWithHotseat); - - boolean hideTaskbar = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_HIDE_TASKBAR) != null; - mTaskbarVisibilityController.animateToVisibilityForFloatingView(hideTaskbar ? 0f : 1f); - } - - private void setReplaceTaskbarWithHotseat(boolean replaceTaskbarWithHotseat) { - Hotseat hotseat = mLauncher.getHotseat(); - if (replaceTaskbarWithHotseat) { - alignRealHotseatWithTaskbar(); - hotseat.getReplaceTaskbarAlpha().setValue(1f); - mTaskbarView.setHotseatViewsHidden(true); + private void updateWhichTaskbarViewIsVisible() { + boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher + || mIsAnimatingToApp; + if (isInApp) { + mTaskbarViewInApp.setVisibility(View.VISIBLE); + mTaskbarViewOnHome.setVisibility(View.INVISIBLE); + mLauncher.getHotseat().setIconsAlpha(0); } else { - hotseat.getReplaceTaskbarAlpha().setValue(0f); - mTaskbarView.setHotseatViewsHidden(false); + mTaskbarViewInApp.setVisibility(View.INVISIBLE); + mTaskbarViewOnHome.setVisibility(View.VISIBLE); + mLauncher.getHotseat().setIconsAlpha(1); } } - private float getTaskbarScaleOnHome() { - return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale(); + /** + * Returns the ratio of the taskbar icon size on home vs in an app. + */ + public float getTaskbarScaleOnHome() { + DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext() + .getDeviceProfile(); + DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext()) + .getDeviceProfile(); + return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx; } /** @@ -561,7 +585,10 @@ public class TaskbarController { protected interface TaskbarViewCallbacks { View.OnClickListener getItemOnClickListener(); View.OnLongClickListener getItemOnLongClickListener(); - int getEmptyHotseatViewVisibility(); + int getEmptyHotseatViewVisibility(TaskbarView taskbarView); + /** Returns how much to scale non-icon elements such as spacing and dividers. */ + float getNonIconScale(TaskbarView taskbarView); + void onItemPositionsChanged(TaskbarView taskbarView); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 1d762e9696..3567c17afa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -15,11 +15,14 @@ */ package com.android.launcher3.taskbar; +import android.animation.Animator; +import android.animation.AnimatorSet; import android.animation.LayoutTransition; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -36,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.folder.FolderIcon; @@ -48,20 +52,23 @@ import com.android.systemui.shared.recents.model.Task; /** * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps. */ -public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent { +public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable { private final ColorDrawable mBackgroundDrawable; - private final int mItemMarginLeftRight; + private final int mDividerWidth; + private final int mDividerHeight; private final int mIconTouchSize; private final boolean mIsRtl; private final int mTouchSlop; private final RectF mTempDelegateBounds = new RectF(); private final RectF mDelegateSlopBounds = new RectF(); private final int[] mTempOutLocation = new int[2]; - private final Matrix mTempMatrix = new Matrix(); // Initialized in TaskbarController constructor. private TaskbarController.TaskbarViewCallbacks mControllerCallbacks; + // Scale on elements that aren't icons. + private float mNonIconScale; + private int mItemMarginLeftRight; // Initialized in init(). private LayoutTransition mLayoutTransition; @@ -78,7 +85,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private boolean mIsDraggingItem; // Only non-null when the corresponding Folder is open. private @Nullable FolderIcon mLeaveBehindFolderIcon; - private boolean mIsHotseatHidden; public TaskbarView(@NonNull Context context) { this(context, null); @@ -99,7 +105,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa Resources resources = getResources(); mBackgroundDrawable = (ColorDrawable) getBackground(); - mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness); + mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height); mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size); mIsRtl = Utilities.isRtl(resources); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); @@ -107,11 +114,16 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks) { mControllerCallbacks = taskbarViewCallbacks; + mNonIconScale = mControllerCallbacks.getNonIconScale(this); + mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale); } protected void init(int numHotseatIcons, int numRecentIcons) { mLayoutTransition = new LayoutTransition(); - setLayoutTransitionsEnabled(true); + addUpdateListenerForAllLayoutTransitions( + () -> mControllerCallbacks.onItemPositionsChanged(this)); + setLayoutTransition(mLayoutTransition); mHotseatStartIndex = 0; mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1; @@ -125,12 +137,30 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa updateRecentTasks(new Task[numRecentIcons]); } - private void setLayoutTransitionsEnabled(boolean enabled) { - setLayoutTransition(enabled ? mLayoutTransition : null); + private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) { + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_DISAPPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.DISAPPEARING, onUpdate); + } + + private void addUpdateListenerForLayoutTransition(int transitionType, Runnable onUpdate) { + Animator anim = mLayoutTransition.getAnimator(transitionType); + if (anim instanceof ValueAnimator) { + ((ValueAnimator) anim).addUpdateListener(valueAnimator -> onUpdate.run()); + } else { + AnimatorSet animSet = new AnimatorSet(); + ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1); + updateAnim.addUpdateListener(valueAnimator -> onUpdate.run()); + animSet.playTogether(anim, updateAnim); + mLayoutTransition.setAnimator(transitionType, animSet); + } } protected void cleanup() { removeAllViews(); + mHotseatRecentsDivider = null; } /** @@ -170,12 +200,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId || needsReinflate) { removeView(hotseatView); - TaskbarActivityContext activityContext = - ActivityContext.lookupContext(getContext()); + ActivityContext activityContext = ActivityContext.lookupContext(getContext()); if (isFolder) { FolderInfo folderInfo = (FolderInfo) hotseatItemInfo; FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId, - activityContext, this, folderInfo); + ActivityContext.lookupContext(getContext()), this, folderInfo); folderIcon.setTextVisible(false); hotseatView = folderIcon; } else { @@ -216,22 +245,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } } - /** - * Hides or shows the hotseat items immediately (without layout transitions). - */ - protected void setHotseatViewsHidden(boolean hidden) { - mIsHotseatHidden = hidden; - setLayoutTransitionsEnabled(false); - updateHotseatItemsVisibility(); - setLayoutTransitionsEnabled(true); - } - private void updateHotseatItemVisibility(View hotseatView) { if (hotseatView.getTag() != null) { - hotseatView.setVisibility(mIsHotseatHidden ? INVISIBLE : VISIBLE); + hotseatView.setVisibility(VISIBLE); } else { int oldVisibility = hotseatView.getVisibility(); - int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(); + int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this); hotseatView.setVisibility(newVisibility); if (oldVisibility == GONE && newVisibility != GONE) { // By default, the layout transition only runs when going to VISIBLE, @@ -243,7 +262,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private View addDivider(int dividerIndex) { View divider = inflate(R.layout.taskbar_divider); - addView(divider, dividerIndex); + LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight); + lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0); + divider.setScaleX(mNonIconScale); + divider.setScaleY(mNonIconScale); + addView(divider, dividerIndex, lp); return divider; } @@ -437,9 +460,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } /** - * @return The bounding box of where the hotseat elements will be when we reach the given scale. + * @return The bounding box of where the hotseat elements are relative to this TaskbarView. */ - protected RectF getHotseatBoundsAtScale(float taskbarViewScale) { + protected RectF getHotseatBounds() { View firstHotseatView = null, lastHotseatView = null; for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) { View child = getChildAt(i); @@ -455,14 +478,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView; View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView; - RectF hotseatBounds = new RectF( + return new RectF( leftmostHotseatView.getLeft() - mItemMarginLeftRight, leftmostHotseatView.getTop(), rightmostHotseatView.getRight() + mItemMarginLeftRight, rightmostHotseatView.getBottom()); - mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY()); - mTempMatrix.mapRect(hotseatBounds); - return hotseatBounds; } // FolderIconParent implemented methods. @@ -493,7 +513,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } private View inflate(@LayoutRes int layoutResId) { - TaskbarActivityContext taskbarActivityContext = ActivityContext.lookupContext(getContext()); - return taskbarActivityContext.getLayoutInflater().inflate(layoutResId, this, false); + return ActivityContext.lookupContext(getContext()).getLayoutInflater() + .inflate(layoutResId, this, false); + } + + @Override + public void setInsets(Rect insets) { + // Ignore, we just implement Insettable to draw behind system insets. } } diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index ae644cd6fd..3faf72a006 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -112,20 +112,32 @@ public class StaggeredWorkspaceAnim { } // Set up springs for the hotseat and qsb. - ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0); + ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets(); if (grid.isVerticalBarLayout()) { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + 1, totalRows); } } else { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); - addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows); + final int hotseatRow, qsbRow, taskbarRow; + if (grid.isTaskbarPresent) { + qsbRow = grid.inv.numRows + 1; + hotseatRow = grid.inv.numRows + 2; + } else { + hotseatRow = grid.inv.numRows + 1; + qsbRow = grid.inv.numRows + 2; + } + // Taskbar and hotseat overlap. + taskbarRow = hotseatRow; + + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); + addStaggeredAnimationForView(child, hotseatRow, totalRows); } - addStaggeredAnimationForView(hotseat.getQsb(), grid.inv.numRows + 2, totalRows); + addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows); + addStaggeredAnimationForView(hotseat.getTaskbarView(), taskbarRow, totalRows); } if (animateOverviewScrim) { diff --git a/res/layout/taskbar_view.xml b/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..96ae43db4a --- /dev/null +++ b/res/layout/taskbar_view.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index af4a843b12..4049ed6882 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -29,8 +29,6 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; -import com.android.launcher3.util.MultiValueAlpha; - import java.util.function.Consumer; /** @@ -38,10 +36,6 @@ import java.util.function.Consumer; */ public class Hotseat extends CellLayout implements Insettable { - private static final int ALPHA_INDEX_STATE = 0; - private static final int ALPHA_INDEX_REPLACE_TASKBAR = 1; - private static final int NUM_ALPHA_CHANNELS = 2; - // Ratio of empty space, qsb should take up to appear visually centered. public static final float QSB_CENTER_FACTOR = .325f; @@ -52,10 +46,12 @@ public class Hotseat extends CellLayout implements Insettable { @Nullable private Consumer mOnVisibilityAggregatedCallback; - private final MultiValueAlpha mMultiValueAlpha; private final View mQsb; private final int mQsbHeight; + private final View mTaskbarView; + private final int mTaskbarViewHeight; + public Hotseat(Context context) { this(context, null); } @@ -66,12 +62,15 @@ public class Hotseat extends CellLayout implements Insettable { public Hotseat(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS, MultiValueAlpha.Mode.MAX); - mMultiValueAlpha.setUpdateVisibility(true); mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); mQsbHeight = mQsb.getLayoutParams().height; addView(mQsb); + + mTaskbarView = LayoutInflater.from(context).inflate(R.layout.taskbar_view, this, false); + mTaskbarViewHeight = mTaskbarView.getLayoutParams().height; + // We want taskbar in the back so its background applies to Hotseat as well. + addView(mTaskbarView, 0); } /** @@ -193,6 +192,8 @@ public class Hotseat extends CellLayout implements Insettable { int width = getShortcutsAndWidgets().getMeasuredWidth(); mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY)); + mTaskbarView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mTaskbarViewHeight, MeasureSpec.EXACTLY)); } @Override @@ -212,6 +213,13 @@ public class Hotseat extends CellLayout implements Insettable { - (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom); int top = bottom - mQsbHeight; mQsb.layout(left, top, right, bottom); + + int taskbarWidth = mTaskbarView.getMeasuredWidth(); + left = (r - l - taskbarWidth) / 2; + right = left + taskbarWidth; + bottom = b - t; + top = bottom - mTaskbarViewHeight; + mTaskbarView.layout(left, top, right, bottom); } /** @@ -221,12 +229,11 @@ public class Hotseat extends CellLayout implements Insettable { return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator); } - public MultiValueAlpha.AlphaProperty getStateAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_STATE); - } - - public MultiValueAlpha.AlphaProperty getReplaceTaskbarAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_REPLACE_TASKBAR); + /** + * Sets the alpha value of just our ShortcutAndWidgetContainer. + */ + public void setIconsAlpha(float alpha) { + getShortcutsAndWidgets().setAlpha(alpha); } /** @@ -235,4 +242,11 @@ public class Hotseat extends CellLayout implements Insettable { public View getQsb() { return mQsb; } + + /** + * Returns the Taskbar inside hotseat + */ + public View getTaskbarView() { + return mTaskbarView; + } } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index e9a34953d5..0f8c6b9172 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -185,12 +185,7 @@ public abstract class LauncherState implements BaseState { } public int getVisibleElements(Launcher launcher) { - DeviceProfile deviceProfile = launcher.getDeviceProfile(); - int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; - if (!deviceProfile.isTaskbarPresent) { - flags |= HOTSEAT_ICONS; - } - return flags; + return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; } /** diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 412754e211..cfcf0a0ced 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -54,7 +54,6 @@ import com.android.launcher3.graphics.SysUiScrim; import com.android.launcher3.graphics.WorkspaceDragScrim; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; -import com.android.launcher3.util.MultiValueAlpha; import com.android.systemui.plugins.ResourceProvider; /** @@ -135,8 +134,8 @@ public class WorkspaceStateTransitionAnimation { } float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; - propertySetter.setFloat(hotseat.getStateAlpha(), MultiValueAlpha.VALUE, - hotseatIconsAlpha, config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); + propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, + config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0; propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, fadeInterpolator); diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index 505c6cea42..71aa4ac445 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -18,6 +18,7 @@ package com.android.launcher3.views; import android.content.Context; import android.content.ContextWrapper; import android.graphics.Rect; +import android.view.LayoutInflater; import android.view.View.AccessibilityDelegate; import com.android.launcher3.DeviceProfile; @@ -66,6 +67,18 @@ public interface ActivityContext { default void updateOpenFolderPosition(int[] inOutPosition, Rect bounds, int width, int height) { } + /** + * Returns a LayoutInflater that is cloned in this Context, so that Views inflated by it will + * have the same Context. (i.e. {@link #lookupContext(Context)} will find this ActivityContext.) + */ + default LayoutInflater getLayoutInflater() { + if (this instanceof Context) { + Context context = (Context) this; + return LayoutInflater.from(context).cloneInContext(context); + } + return null; + } + /** * The root view to support drag-and-drop and popup support. */ @@ -73,7 +86,10 @@ public interface ActivityContext { DeviceProfile getDeviceProfile(); - static T lookupContext(Context context) { + /** + * Returns the ActivityContext associated with the given Context. + */ + static T lookupContext(Context context) { if (context instanceof ActivityContext) { return (T) context; } else if (context instanceof ContextWrapper) { From 59b5e241e2b1ca7b2befe6efb601ff661ffa58dc Mon Sep 17 00:00:00 2001 From: Sreyas Date: Fri, 19 Mar 2021 14:00:14 -0700 Subject: [PATCH 10/11] Hide chips if loaded in select mode. Bug: 182375263 Test: Manual Change-Id: Id9709a2033b303c09d9ca26d2e05af6af45df564 --- .../com/android/quickstep/views/TaskView.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 809adcbe21..2b7e6fd059 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -298,7 +298,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mEndQuickswitchCuj; private View mContextualChipWrapper; - private View mContextualChip; private final float[] mIconCenterCoords = new float[2]; private final float[] mChipCenterCoords = new float[2]; @@ -447,9 +446,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } mModalness = modalness; mIconView.setAlpha(comp(modalness)); - if (mContextualChip != null) { - mContextualChip.setScaleX(comp(modalness)); - mContextualChip.setScaleY(comp(modalness)); + if (mContextualChipWrapper != null) { + mContextualChipWrapper.setScaleX(comp(modalness)); + mContextualChipWrapper.setScaleY(comp(modalness)); } mDigitalWellBeingToast.updateBannerOffset(modalness, mCurrentFullscreenParams.mCurrentDrawnInsets.top @@ -689,10 +688,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { .getInterpolation(progress); mIconView.setScaleX(scale); mIconView.setScaleY(scale); - if (mContextualChip != null && mContextualChipWrapper != null) { + if (mContextualChipWrapper != null && mContextualChipWrapper != null) { mContextualChipWrapper.setAlpha(scale); - mContextualChip.setScaleX(scale); - mContextualChip.setScaleY(scale); + mContextualChipWrapper.setScaleX(Math.min(scale, comp(mModalness))); + mContextualChipWrapper.setScaleY(Math.min(scale, comp(mModalness))); } mDigitalWellBeingToast.updateBannerOffset(1f - scale, mCurrentFullscreenParams.mCurrentDrawnInsets.top @@ -797,14 +796,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { int expectedChipHeight = getExpectedViewHeight(view); float chipOffset = getResources().getDimension(R.dimen.chip_hint_vertical_offset); layoutParams.bottomMargin = -expectedChipHeight - (int) chipOffset; - mContextualChip = ((FrameLayout) mContextualChipWrapper).getChildAt(0); - mContextualChip.setScaleX(0f); - mContextualChip.setScaleY(0f); + mContextualChipWrapper.setScaleX(0f); + mContextualChipWrapper.setScaleY(0f); addView(view, getChildCount(), layoutParams); - if (mContextualChip != null) { - mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50); - } if (mContextualChipWrapper != null) { + float scale = comp(mModalness); + mContextualChipWrapper.animate().scaleX(scale).scaleY(scale).setDuration(50); mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper); } } @@ -825,7 +822,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } View oldContextualChipWrapper = mContextualChipWrapper; mContextualChipWrapper = null; - mContextualChip = null; mChipTouchDelegate = null; return oldContextualChipWrapper; } From e888b08b70657f29e20c59319ec17f6c2686c968 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 23 Mar 2021 12:00:38 -0400 Subject: [PATCH 11/11] Updating deep shortcut container to new width. Bug: 175329686 Test: manual, visual Change-Id: I0487d240523ab3de4bf3e381ec359267eaa33a71 --- res/layout/deep_shortcut.xml | 2 ++ res/layout/system_shortcut.xml | 3 ++- res/values/dimens.xml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml index d6b4a37dd4..0d11b50ab3 100644 --- a/res/layout/deep_shortcut.xml +++ b/res/layout/deep_shortcut.xml @@ -32,6 +32,8 @@ android:paddingEnd="@dimen/popup_padding_end" android:drawableEnd="@drawable/ic_drag_handle" android:drawablePadding="@dimen/deep_shortcut_drawable_padding" + android:singleLine="true" + android:ellipsize="end" android:textSize="14sp" android:textColor="?android:attr/textColorPrimary" launcher:layoutHorizontal="true" diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml index 68251e4d15..9f45f30216 100644 --- a/res/layout/system_shortcut.xml +++ b/res/layout/system_shortcut.xml @@ -31,7 +31,8 @@ android:paddingStart="@dimen/deep_shortcuts_text_padding_start" android:paddingEnd="@dimen/popup_padding_end" android:textSize="14sp" - android:maxLines="1" + android:singleLine="true" + android:ellipsize="end" android:textColor="?android:attr/textColorPrimary" launcher:iconDisplay="shortcut_popup" launcher:layoutHorizontal="true" diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 64c07d03d5..2f46a2a51a 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -185,7 +185,7 @@ 0dp - 234dp + 216dp 56dp 6dp