From 5c6a3e574607787346676e13a261cf69d6a12f5c Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Mon, 30 Sep 2024 23:17:23 +0000 Subject: [PATCH 01/13] Use context#getDrawable instead of AppCompatResources#getDrawable to fix test failure. Bug: b/352775107 Flag: EXEMPT Test crash fix Test: atest NexusLauncherTests Change-Id: I2a20fd6d1de3a5398c665d477c1e234d9b890781 --- .../quickstep/interaction/TutorialController.java | 9 +++------ .../quickstep/interaction/TutorialStepIndicator.java | 7 ++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 5028da4f6a..9510a059d0 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -52,7 +52,6 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StyleRes; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.content.res.AppCompatResources; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; @@ -610,8 +609,8 @@ abstract class TutorialController implements BackGestureAttemptCallback, private void updateDrawables() { if (mContext != null) { - mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable( - mContext, getMockWallpaperResId())); + mTutorialFragment.getRootView() + .setBackground(mContext.getDrawable(getMockWallpaperResId())); mTutorialFragment.updateFeedbackAnimation(); mFakeLauncherView.setBackgroundColor(getFakeLauncherColor()); updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId()); @@ -619,9 +618,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFakeTaskView.animate().alpha(1).setListener( AnimatorListeners.forSuccessCallback(() -> mFakeTaskView.animate().cancel())); mFakePreviousTaskView.setFakeTaskViewFillColor(getMockPreviousAppTaskThumbnailColor()); - mFakeIconView.setBackground(AppCompatResources.getDrawable( - mContext, getMockAppIconResId())); - + mFakeIconView.setBackground(mContext.getDrawable(getMockAppIconResId())); mExitingAppView.setBackgroundColor(getExitingAppColor()); mFakeTaskView.setBackgroundColor(getFakeTaskViewColor()); updateHotseatChildViewColor(mHotseatIconView); diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java b/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java index ae0e725aad..f1fc1797c4 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java @@ -22,8 +22,6 @@ import android.util.Log; import android.widget.ImageView; import android.widget.LinearLayout; -import androidx.appcompat.content.res.AppCompatResources; - import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.icons.GraphicsUtils; @@ -91,9 +89,8 @@ public class TutorialStepIndicator extends LinearLayout { int inactiveStepIndicatorColor = GraphicsUtils.getAttrColor( getContext(), android.R.attr.textColorSecondaryInverse); for (int i = 0; i < mTotalSteps; i++) { - Drawable pageIndicatorPillDrawable = AppCompatResources.getDrawable( - getContext(), R.drawable.tutorial_step_indicator_pill); - + Drawable pageIndicatorPillDrawable = + getContext().getDrawable(R.drawable.tutorial_step_indicator_pill); if (i >= getChildCount()) { ImageView pageIndicatorPill = new ImageView(getContext()); pageIndicatorPill.setImageDrawable(pageIndicatorPillDrawable); From ded650084861f7c410e8b17b916d1dcc2072a111 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Fri, 27 Sep 2024 12:04:17 +0100 Subject: [PATCH 02/13] Make large task tile snap to position after scrolling - There's an edge case when there are only 2 grid tasks, mNextPage will still be on the grid tasks when they're not fully visible, so the new isAnySmallTaskFullyVisible check can't kick in. This only happens when grid tasks are barely out of screen. Fix: 370733696 Test: Scroll betwene large tiles, it should always snap after scrolling Test: Scroll from focus task to grid task, it should only snap if grid tasks aren't fully visible Flag: com.android.launcher3.enable_large_desktop_windowing_tile Change-Id: I3b0a80ceffb1caae57aa53b1c949c5e51336231a --- .../src/com/android/quickstep/util/RecentsViewUtils.kt | 6 ++++++ quickstep/src/com/android/quickstep/views/RecentsView.java | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt index 68690d2f43..c3b072deac 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt @@ -113,6 +113,12 @@ class RecentsViewUtils { it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden) } + /** Returns if any small tasks are fully visible */ + fun isAnySmallTaskFullyVisible( + taskViews: Iterable, + isTaskViewFullyVisible: (TaskView) -> Boolean, + ): Boolean = taskViews.any { !it.isLargeTile && isTaskViewFullyVisible(it) } + /** Returns the current list of [TaskView] children. */ fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): Iterable = (0 until taskViewCount).map(requireTaskViewAt) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 0d2acf0dab..458a0d0b1c 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1706,10 +1706,11 @@ public abstract class RecentsView< return; } TaskView taskView = getTaskViewAt(mNextPage); - // Snap to fully visible focused task and clear all button. boolean shouldSnapToLargeTask = taskView != null && taskView.isLargeTile() - && isTaskViewFullyVisible(taskView); + && !mUtils.isAnySmallTaskFullyVisible(getTaskViews(), + this::isTaskViewFullyVisible); boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton); + // Snap to large tile when grid tasks aren't fully visible or the clear all button. if (!shouldSnapToLargeTask && !shouldSnapToClearAll) { return; } From 0cf067ef473ceb50e36d129685bf7bfe67d295ad Mon Sep 17 00:00:00 2001 From: Jordan Silva Date: Mon, 30 Sep 2024 15:32:10 -0700 Subject: [PATCH 03/13] Fix translation when focused task or desktop task is dismissed. (3/4) This CL uses the same logic used for handheld dissmiss translation to fix the following cases when large tile is enabled for desktop task: - When the LAST focused task is dismissed (i.e., no other task in the grid), translate all large tiles from the right side to the left, to occupy the dismissed focused task position. - When Desktop Task is dismissed, translate focused task and grid from the left to the right side to occupy the dismissed desktop task position. - When 2 tasks are visible in recents (i.e., 1 focused task, 1 desktop task) and the user dismisses the desktop task while in Clear All Button page (page 2), the focused task translates when no translation should be done, due to snapping to ClearAllButton page on Tablet. To fix this we introduced a logic in getOffsetToDismissedTask to use the previous page for the calculation when the grid snaps to Clear All Button page. Bug: 353948136 Fix: 353948182 Flag: com.android.launcher3.enable_large_desktop_windowing_tile Test: OverviewDesktopTaskImageTest Change-Id: If8b06410c26a8f817d84ec6a635a66b2941e3ae9 --- .../android/quickstep/views/RecentsView.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index a075c58a00..b2429c7223 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3609,10 +3609,10 @@ public abstract class RecentsView< float dismissedTaskWidth = 0; float nextFocusedTaskWidth = 0; - // Non-grid specific properties. int[] oldScroll = new int[count]; int[] newScroll = new int[count]; int scrollDiffPerPage = 0; + // Non-grid specific properties. boolean needsCurveUpdates = false; if (showAsGrid) { @@ -3642,13 +3642,13 @@ public abstract class RecentsView< } } } - } else { - getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC); - getPageScrolls(newScroll, false, - v -> v.getVisibility() != GONE && v != dismissedTaskView); - if (count > 1) { - scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]); - } + } + + getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC); + getPageScrolls(newScroll, false, + v -> v.getVisibility() != GONE && v != dismissedTaskView); + if (count > 1) { + scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]); } float dismissTranslationInterpolationEnd = 1; @@ -3800,7 +3800,9 @@ public abstract class RecentsView< addDismissedTaskAnimations(dismissedTaskView, duration, anim); } } - } else if (!showAsGrid) { + } else if (!showAsGrid || (enableLargeDesktopWindowingTile() + && dismissedTaskView.isLargeTile() + && nextFocusedTaskView == null)) { int offset = getOffsetToDismissedTask(scrollDiffPerPage, dismissedIndex, taskCount); int scrollDiff = newScroll[i] - oldScroll[i] + offset; if (scrollDiff != 0) { @@ -3812,18 +3814,16 @@ public abstract class RecentsView< splitTimings); needsCurveUpdates = true; } - } else if (child instanceof TaskView) { - TaskView taskView = (TaskView) child; + } else if (child instanceof TaskView taskView) { if (isFocusedTaskDismissed) { if (nextFocusedTaskView != null && !isSameGridRow(taskView, nextFocusedTaskView)) { continue; } - } else { - if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) { - continue; - } + } else if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) { + continue; } + // Animate task with index >= dismissed index and in the same row as the // dismissed index or next focused index. Offset successive task dismissal // durations for a staggered effect. @@ -4134,15 +4134,18 @@ public abstract class RecentsView< * - Dragging an adjacent page on the left side (right side for RTL) */ private int getOffsetToDismissedTask(int scrollDiffPerPage, int dismissedIndex, int taskCount) { + // When mCurrentPage is ClearAllButton, use the last TaskView instead to calculate + // offset. + int currentPage = mCurrentPage == taskCount ? taskCount - 1 : mCurrentPage; int offset = mIsRtl ? scrollDiffPerPage : 0; - if (mCurrentPage == dismissedIndex) { + if (currentPage == dismissedIndex) { int lastPage = taskCount - 1; - if (mCurrentPage == lastPage) { + if (currentPage == lastPage) { offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage; } } else { // Dismissing an adjacent page. - int negativeAdjacent = mCurrentPage - 1; // (Right in RTL, left in LTR) + int negativeAdjacent = currentPage - 1; // (Right in RTL, left in LTR) if (dismissedIndex == negativeAdjacent) { offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage; } From 8bd8feb72d68e66eb605f427315448f43d71d521 Mon Sep 17 00:00:00 2001 From: Liran Binyamin Date: Mon, 30 Sep 2024 17:33:17 -0400 Subject: [PATCH 04/13] Bubble bar flyout polish Animate the elevation of the flyout along with the expansion animation. Also start revealing the triangle as soon as we're past the bubble bar. Flag: com.android.wm.shell.enable_bubble_bar Bug: 277815200 Test: atest BubbleBarFlyoutViewScreenshotTest Test: atest BubbleBarFlyoutControllerTest Change-Id: Ie7e27240ae3ab86f8e7c3f39aa1c80885cfdc98e --- .../flyout/BubbleBarFlyoutPositioner.kt | 9 ++++ .../bubbles/flyout/BubbleBarFlyoutView.kt | 44 +++++++++++++++---- .../BubbleBarFlyoutViewScreenshotTest.kt | 6 ++- .../flyout/BubbleBarFlyoutControllerTest.kt | 2 + 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt index b8c1c7f1d7..aa2555e865 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt @@ -39,4 +39,13 @@ interface BubbleBarFlyoutPositioner { /** The color of the flyout when collapsed. */ val collapsedColor: Int + + /** The elevation of the flyout when collapsed. */ + val collapsedElevation: Float + + /** + * The distance the flyout must pass from its collapsed position until it can start revealing + * the triangle. + */ + val distanceToRevealTriangle: Float } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt index 6723f57dd5..8d84ddf8ab 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt @@ -40,8 +40,6 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly ConstraintLayout(context) { private companion object { - // the minimum progress of the expansion animation before the triangle is made visible. - const val MIN_EXPANSION_PROGRESS_FOR_TRIANGLE = 0.1f // the minimum progress of the expansion animation before the content starts fading in. const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f } @@ -92,6 +90,11 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_max_width) } + private val flyoutElevation by + lazy(LazyThreadSafetyMode.NONE) { + context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat() + } + /** The bounds of the background rect. */ private val backgroundRect = RectF() private val cornerRadius: Float @@ -108,6 +111,10 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly private var collapsedCornerRadius = 0f /** The color of the flyout when collapsed. */ private var collapsedColor = 0 + /** The elevation of the flyout when collapsed. */ + private var collapsedElevation = 0f + /** The minimum progress of the expansion animation before the triangle is made visible. */ + private var minExpansionProgressForTriangle = 0f /** The corner radius of the background according to the progress of the animation. */ private val currentCornerRadius @@ -141,8 +148,7 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly val padding = context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding) // add extra padding to the bottom of the view to include the triangle setPadding(padding, padding, padding, padding + triangleHeight - triangleOverlap) - translationZ = - context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat() + translationZ = flyoutElevation RoundedArrowDrawable.addDownPointingRoundedTriangleToPath( triangleWidth.toFloat(), @@ -182,6 +188,12 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly collapsedSize = positioner.collapsedSize collapsedCornerRadius = collapsedSize / 2 collapsedColor = positioner.collapsedColor + collapsedElevation = positioner.collapsedElevation + + // calculate the expansion progress required before we start showing the triangle as part of + // the expansion animation + minExpansionProgressForTriangle = + positioner.distanceToRevealTriangle / tyToCollapsedPosition // post the request to start the expand animation to the looper so the view can measure // itself @@ -240,6 +252,9 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly message.alpha = alpha avatar.alpha = alpha + translationZ = + collapsedElevation + (flyoutElevation - collapsedElevation) * expansionProgress + invalidate() } @@ -275,7 +290,7 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly currentCornerRadius, backgroundPaint, ) - if (expansionProgress >= MIN_EXPANSION_PROGRESS_FOR_TRIANGLE) { + if (expansionProgress >= minExpansionProgressForTriangle) { drawTriangle(canvas) } canvas.restore() @@ -291,9 +306,20 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly } else { width - currentCornerRadius - triangleWidth } - // instead of scaling the triangle, increasingly reveal it from the background, starting - // with half the size. this has the effect of the triangle scaling. - val triangleY = height - triangleHeight - 0.5f * triangleHeight * (1 - expansionProgress) + // instead of scaling the triangle, increasingly reveal it from the background. this has the + // effect of the triangle scaling. + + // the translation y of the triangle before we start revealing it. align its bottom with the + // bottom of the rect + val triangleYCollapsed = height - triangleHeight - (triangleHeight - triangleOverlap) + // the translation y of the triangle when it's fully revealed + val triangleYExpanded = height - triangleHeight + val interpolatedExpansion = + ((expansionProgress - minExpansionProgressForTriangle) / + (1 - minExpansionProgressForTriangle)) + .coerceIn(0f, 1f) + val triangleY = + triangleYCollapsed + (triangleYExpanded - triangleYCollapsed) * interpolatedExpansion canvas.translate(triangleX, triangleY) canvas.drawPath(triangle, backgroundPaint) triangleOutline.setPath(triangle) @@ -309,7 +335,7 @@ class BubbleBarFlyoutView(context: Context, private val positioner: BubbleBarFly currentCornerRadius, Path.Direction.CW, ) - if (expansionProgress >= MIN_EXPANSION_PROGRESS_FOR_TRIANGLE) { + if (expansionProgress >= minExpansionProgressForTriangle) { path.addPath(triangleOutline.mPath) } outline.setPath(path) diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt index 50e2dcf7b4..6aba6a3c78 100644 --- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt +++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt @@ -224,7 +224,7 @@ class BubbleBarFlyoutViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { BubbleBarFlyoutMessage( senderAvatar = ColorDrawable(Color.RED), senderName = "sender", - message = "collapsed 90% on left", + message = "expanded 90% on left", isGroupChat = true, ) ) {} @@ -249,7 +249,7 @@ class BubbleBarFlyoutViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { BubbleBarFlyoutMessage( senderAvatar = ColorDrawable(Color.RED), senderName = "sender", - message = "collapsed 80% on right", + message = "expanded 80% on right", isGroupChat = true, ) ) {} @@ -265,5 +265,7 @@ class BubbleBarFlyoutViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { override val targetTy = 0f override val collapsedSize = 30f override val collapsedColor = Color.BLUE + override val collapsedElevation = 1f + override val distanceToRevealTriangle = 10f } } diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt index 0f02444b30..d857ae5579 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt @@ -55,6 +55,8 @@ class BubbleBarFlyoutControllerTest { override val distanceToCollapsedPosition = PointF(100f, 200f) override val collapsedSize = 30f override val collapsedColor = Color.BLUE + override val collapsedElevation = 1f + override val distanceToRevealTriangle = 50f } flyoutController = BubbleBarFlyoutController(flyoutContainer, positioner) } From 32007e05cd7947f3830e20d732cf41bae5b4c9b9 Mon Sep 17 00:00:00 2001 From: Brandon Dayauon Date: Fri, 27 Sep 2024 11:32:51 -0700 Subject: [PATCH 05/13] Don't call onAppsUpdated() when in testHarness Suspect that the jump in these flakes where it cannot find the private space container is due to this calculateDiff call when onAppsUpdate() is called bug: 355466672 Test: tapl presubmit and vid: https://drive.google.com/file/d/1hshI6g7oqvi45EiO92Rl4e-gaXfDVe_b/view?usp=sharing Flag: NONE trying to fix flake Change-Id: I0bff416624c5b9e2cb7a4fe32834f9d521507922 --- src/com/android/launcher3/allapps/PrivateProfileManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java index e215cabcd7..6a401215f1 100644 --- a/src/com/android/launcher3/allapps/PrivateProfileManager.java +++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java @@ -66,6 +66,7 @@ import com.android.launcher3.BuildConfig; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Flags; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatedPropertySetter; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.icons.BitmapInfo; @@ -699,7 +700,9 @@ public class PrivateProfileManager extends UserProfileManager { mAllApps.mAH.get(MAIN).mRecyclerView.removeItemDecoration( mPrivateAppsSectionDecorator); // Call onAppsUpdated() because it may be canceled when this animation occurs. - mAllApps.getPersonalAppList().onAppsUpdated(); + if (!Utilities.isRunningInTestHarness()) { + mAllApps.getPersonalAppList().onAppsUpdated(); + } if (isPrivateSpaceHidden()) { // TODO (b/325455879): Figure out if we can avoid this. getMainRecyclerView().getAdapter().notifyDataSetChanged(); From d77f2c1692ace56a9ed1d118330f90b9b5a0c349 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 1 Oct 2024 10:28:27 -0700 Subject: [PATCH 06/13] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I281ab493777a8d86477c5f5ca1f069cd368af5c3 --- quickstep/res/values-en-rGB/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index a74a17b8dc..04b04dde75 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -139,8 +139,7 @@ "Always show Taskbar" "Change navigation mode" "Taskbar divider" - - + "Taskbar overflow" "Move to top/left" "Move to bottom/right" "{count,plural, =1{more app}other{more apps}}" From 9e196da120c83ed9e3d442b356b1cfa86ec05000 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 1 Oct 2024 10:28:37 -0700 Subject: [PATCH 07/13] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Id0277715e43f68ca608c9ecf9629a5aa0c31d6fa --- res/values-en-rGB/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index aee49beaca..f7b04a31fd 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -31,8 +31,7 @@ "Split screen" "App info for %1$s" "Usage settings for %1$s" - - + "New window" "Save app pair" "%1$s | %2$s" "This app pair isn\'t supported on this device" From 63dfd60b2301fd3fc1c536eff45703a4ec91cb47 Mon Sep 17 00:00:00 2001 From: Schneider Victor-Tulias Date: Mon, 30 Sep 2024 16:32:15 -0400 Subject: [PATCH 08/13] Add debug memory logs to AbstractLauncherUiTest Flag: EXEMPT test debug logs Bug: 365628676 Test: TAPL tests Change-Id: Ia019bc128b76b9b2d776c54ad93713ae4110b2de --- .../launcher3/ui/AbstractLauncherUiTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 68004bb058..cee88ac047 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -26,6 +26,7 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -103,6 +104,8 @@ public abstract class AbstractLauncherUiTest { public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT; private static final String TAG = "AbstractLauncherUiTest"; + private static final long BYTES_PER_MEGABYTE = 1 << 20; + private static boolean sDumpWasGenerated = false; private static boolean sActivityLeakReported = false; private static boolean sSeenKeyguard = false; @@ -124,6 +127,10 @@ public abstract class AbstractLauncherUiTest { protected String mTargetPackage; private int mLauncherPid; + private final ActivityManager.MemoryInfo mMemoryInfo = new ActivityManager.MemoryInfo(); + private final ActivityManager mActivityManager; + private long mMemoryBefore; + /** Detects activity leaks and throws an exception if a leak is found. */ public static void checkDetectedLeaks(LauncherInstrumentation launcher) { checkDetectedLeaks(launcher, false); @@ -192,6 +199,8 @@ public abstract class AbstractLauncherUiTest { } protected AbstractLauncherUiTest() { + mActivityManager = InstrumentationRegistry.getContext() + .getSystemService(ActivityManager.class); mLauncher.enableCheckEventsForSuccessfulGestures(); mLauncher.setAnomalyChecker(AbstractLauncherUiTest::verifyKeyguardInvisible); try { @@ -311,6 +320,26 @@ public abstract class AbstractLauncherUiTest { initialize(this); } + private long getAvailableMemory() { + mActivityManager.getMemoryInfo(mMemoryInfo); + + return Math.divideExact(mMemoryInfo.availMem, BYTES_PER_MEGABYTE); + } + + @Before + public void saveMemoryBefore() { + mMemoryBefore = getAvailableMemory(); + } + + @After + public void logMemoryAfter() { + long memoryAfter = getAvailableMemory(); + + Log.d(TAG, "Available memory: before=" + mMemoryBefore + + "MB, after=" + memoryAfter + + "MB, delta=" + (memoryAfter - mMemoryBefore) + "MB"); + } + /** Method that should be called when a test starts. */ public static void onTestStart() { waitForSetupWizardDismissal(); From 21f504e0f14f0d3b983bf6694eeda8fc7bedda34 Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Tue, 1 Oct 2024 11:50:54 -0700 Subject: [PATCH 09/13] Fix small bug with TaskView tile expansion There was a small typo that resulted in the wrong measurement being returned for the remaining TaskView. This CL fixes it. Fixes: 365476600 Test: Manual Flag: NONE bugfix Change-Id: I1abf993abcaa8d06e5475f31c0322017f6e96e6f --- .../src/com/android/quickstep/util/SplitAnimationController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index 3449cf2034..f708f4bb39 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -238,7 +238,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC taskViewHeight, ) val snapshotViewSize = - if (isPrimaryTaskSplitting) primarySnapshotViewSize else secondarySnapshotViewSize + if (isPrimaryTaskSplitting) secondarySnapshotViewSize else primarySnapshotViewSize if (deviceProfile.isLeftRightSplit) { // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0 val centerThumbnailTranslationX: Float = (taskViewWidth - snapshotViewSize.x) / 2f From 29e060408fe123129de7cd1573dc20ad29a23c93 Mon Sep 17 00:00:00 2001 From: Anushree Ganjam Date: Tue, 1 Oct 2024 11:04:43 -0700 Subject: [PATCH 10/13] Make InstallSessionHelper injected by Dagger (7/n) Bug: 361850561 Test: Manual Flag: NONE Dagger Integration Change-Id: Ib1833436bfd1079ae78f1d865831c1aa8a7a0c41 --- .../dagger/LauncherBaseAppComponent.java | 3 +++ .../launcher3/pm/InstallSessionHelper.java | 19 +++++++++++++++---- .../launcher3/pm/InstallSessionHelperTest.kt | 4 +++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java index 0a50e8bc9e..9f6b40b075 100644 --- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java +++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java @@ -18,6 +18,7 @@ package com.android.launcher3.dagger; import android.content.Context; +import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.util.DaggerSingletonTracker; import dagger.BindsInstance; @@ -32,6 +33,8 @@ import dagger.BindsInstance; */ public interface LauncherBaseAppComponent { DaggerSingletonTracker getDaggerSingletonTracker(); + InstallSessionHelper getInstallSessionHelper(); + /** Builder for LauncherBaseAppComponent. */ interface Builder { @BindsInstance Builder appContext(@ApplicationContext Context context); diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index 124907f181..f36f595545 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -31,12 +31,17 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.Flags; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.SessionCommitReceiver; +import com.android.launcher3.dagger.ApplicationContext; +import com.android.launcher3.dagger.LauncherAppSingleton; +import com.android.launcher3.dagger.LauncherBaseAppComponent; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.util.ApplicationInfoWrapper; +import com.android.launcher3.util.DaggerSingletonObject; +import com.android.launcher3.util.DaggerSingletonTracker; +import com.android.launcher3.util.ExecutorUtil; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; -import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SafeCloseable; @@ -47,10 +52,13 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; +import javax.inject.Inject; + /** * Utility class to tracking install sessions */ @SuppressWarnings("NewApi") +@LauncherAppSingleton public class InstallSessionHelper implements SafeCloseable { @NonNull @@ -64,8 +72,8 @@ public class InstallSessionHelper implements SafeCloseable { private static final boolean DEBUG = false; @NonNull - public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(InstallSessionHelper::new); + public static final DaggerSingletonObject INSTANCE = + new DaggerSingletonObject<>(LauncherBaseAppComponent::getInstallSessionHelper); @Nullable private final LauncherApps mLauncherApps; @@ -82,10 +90,13 @@ public class InstallSessionHelper implements SafeCloseable { @Nullable private IntSet mPromiseIconIds; - public InstallSessionHelper(@NonNull final Context context) { + @Inject + public InstallSessionHelper(@NonNull @ApplicationContext final Context context, + DaggerSingletonTracker tracker) { mInstaller = context.getPackageManager().getPackageInstaller(); mAppContext = context.getApplicationContext(); mLauncherApps = context.getSystemService(LauncherApps.class); + ExecutorUtil.executeSyncOnMainOrFail(() -> tracker.addCloseable(this)); } @Override diff --git a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt index ca2ef42124..a991981362 100644 --- a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt +++ b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt @@ -28,6 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.LauncherPrefs import com.android.launcher3.LauncherPrefs.Companion.PROMISE_ICON_IDS +import com.android.launcher3.util.DaggerSingletonTracker import com.android.launcher3.util.Executors.MODEL_EXECUTOR import com.android.launcher3.util.IntArray import com.android.launcher3.util.LauncherModelHelper @@ -53,6 +54,7 @@ class InstallSessionHelperTest { private val expectedAppPackage = "expectedAppPackage" private val expectedInstallerPackage = "expectedInstallerPackage" private val mockPackageInstaller: PackageInstaller = mock() + private val mTracker: DaggerSingletonTracker = mock() private lateinit var installSessionHelper: InstallSessionHelper private lateinit var launcherApps: LauncherApps @@ -62,7 +64,7 @@ class InstallSessionHelperTest { whenever(packageManager.packageInstaller).thenReturn(mockPackageInstaller) whenever(sandboxContext.packageName).thenReturn(expectedInstallerPackage) launcherApps = sandboxContext.spyService(LauncherApps::class.java) - installSessionHelper = InstallSessionHelper(sandboxContext) + installSessionHelper = InstallSessionHelper(sandboxContext, mTracker) } @Test From 7519b7c2e66baaa1c6f6a85b9548948b91f1b336 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 30 Sep 2024 22:45:47 +0000 Subject: [PATCH 11/13] Fix Taskbar unlock transition - There are multiple signals that come just after FLAG_DEVICE_LOCKED is removed, and those should still be considered part of the unlock transition. We already did this for TaskbarStashController so I copied it to TaskbarLauncherStateController. - Also animate when changing SYSUI_STATE_OVERVIEW_DISABLED, since this happens when the device is locked/unlocked and changes the visibility of TaskbarView icons. Test: manually unlock over both home screen and in-app, verify clean transition without jump (e.g. Hotseat is immediately visible as part of Workspace, and Taskbar fades in during unlock to an app) Flag: EXEMPT bug fix Fixes: 364586744 Change-Id: If0497fcc17bb0ec44294c4ea1163104b4d8be459 --- .../TaskbarLauncherStateController.java | 22 ++++++++++++++++--- .../taskbar/TaskbarStashController.java | 2 +- .../taskbar/TaskbarViewController.java | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 065646ad39..43b1ae04d5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -24,6 +24,7 @@ import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_FOR_BUBBLES; +import static com.android.launcher3.taskbar.TaskbarStashController.UNLOCK_TRANSITION_MEMOIZATION_MS; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME; import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_ALPHA_DURATION_MS; import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS; @@ -167,7 +168,12 @@ public class TaskbarLauncherStateController { private boolean mSkipNextRecentsAnimEnd; // Time when FLAG_TASKBAR_HIDDEN was last cleared, SystemClock.elapsedRealtime (milliseconds). - private long mLastUnlockTimeMs = 0; + private long mLastRemoveTaskbarHiddenTimeMs = 0; + /** + * Time when FLAG_DEVICE_LOCKED was last cleared, plus + * {@link TaskbarStashController#UNLOCK_TRANSITION_MEMOIZATION_MS} + */ + private long mLastUnlockTransitionTimeout; private @Nullable TaskBarRecentsAnimationListener mTaskBarRecentsAnimationListener; @@ -535,7 +541,7 @@ public class TaskbarLauncherStateController { if (hasAnyFlag(changedFlags, FLAG_TASKBAR_HIDDEN) && !hasAnyFlag(FLAG_TASKBAR_HIDDEN)) { // Take note of the current time, as the taskbar is made visible again. - mLastUnlockTimeMs = SystemClock.elapsedRealtime(); + mLastRemoveTaskbarHiddenTimeMs = SystemClock.elapsedRealtime(); } boolean isHidden = hasAnyFlag(FLAG_TASKBAR_HIDDEN); @@ -561,7 +567,8 @@ public class TaskbarLauncherStateController { // with a fingerprint reader. This should only be done when the device was woken // up via fingerprint reader, however since this information is currently not // available, opting to always delay the fade-in a bit. - long durationSinceLastUnlockMs = SystemClock.elapsedRealtime() - mLastUnlockTimeMs; + long durationSinceLastUnlockMs = SystemClock.elapsedRealtime() + - mLastRemoveTaskbarHiddenTimeMs; taskbarVisibility.setStartDelay( Math.max(0, TASKBAR_SHOW_DELAY_MS - durationSinceLastUnlockMs)); } @@ -631,6 +638,15 @@ public class TaskbarLauncherStateController { boolean isUnlockTransition = hasAnyFlag(changedFlags, FLAG_DEVICE_LOCKED) && !hasAnyFlag(FLAG_DEVICE_LOCKED); if (isUnlockTransition) { + // the launcher might not be resumed at the time the device is considered + // unlocked (when the keyguard goes away), but possibly shortly afterwards. + // To play the unlock transition at the time the unstash animation actually happens, + // this memoizes the state transition for UNLOCK_TRANSITION_MEMOIZATION_MS. + mLastUnlockTransitionTimeout = + SystemClock.elapsedRealtime() + UNLOCK_TRANSITION_MEMOIZATION_MS; + } + boolean isInUnlockTimeout = SystemClock.elapsedRealtime() < mLastUnlockTransitionTimeout; + if (isUnlockTransition || isInUnlockTimeout) { // When transitioning to unlocked, ensure the hotseat is fully visible from the // beginning. The hotseat itself is animated by LauncherUnlockAnimationController. mIconAlignment.cancelAnimation(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 6222e53a5f..8991965f61 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -191,7 +191,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // Duration for which an unlock event is considered "current", as other events are received // asynchronously. - private static final long UNLOCK_TRANSITION_MEMOIZATION_MS = 200; + public static final long UNLOCK_TRANSITION_MEMOIZATION_MS = 200; /** * The default stash animation, morphing the taskbar into the navbar. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 0fa9e60d06..05f84e29f0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -84,7 +84,6 @@ import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.function.Predicate; @@ -330,7 +329,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar */ public void setRecentsButtonDisabled(boolean isDisabled) { // TODO: check TaskbarStashController#supportsStashing(), to stash instead of setting alpha. - mTaskbarIconAlpha.get(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1); + mTaskbarIconAlpha.get(ALPHA_INDEX_RECENTS_DISABLED).animateToValue(isDisabled ? 0 : 1) + .start(); } /** From da477af93dfee3af40a8134652f32b9a2c700104 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Tue, 1 Oct 2024 21:06:02 +0000 Subject: [PATCH 12/13] Fix comment in TransientBubbleStashControllerTest Bug: 345488489 Change-Id: Ide38c1e36a0da53e9fcc7a5c6b0c3241eff24add Test: na Flag: DOCS_ONLY --- .../bubbles/stashing/TransientBubbleStashControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt index c6a50d1d0f..412bdeb8ac 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt @@ -240,7 +240,7 @@ class TransientBubbleStashControllerTest { mTransientBubbleStashController.isStashed = false whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false) - // When unstash + // When stash getInstrumentation().runOnMainSync { mTransientBubbleStashController.updateStashedAndExpandedState( stash = true, From 9240b68dd6c3074936b64b36375a66d8231ab5d7 Mon Sep 17 00:00:00 2001 From: Schneider Victor-Tulias Date: Thu, 26 Sep 2024 14:05:51 -0400 Subject: [PATCH 13/13] Update where we end CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS Flag: EXEMPT bug fix Fixes: 369359244 Test: performance testing Change-Id: Id70c4b02738fd1abd62027fcddd0fac3c99fe95e --- quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index a6d651c951..384ea16a34 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1145,12 +1145,18 @@ public abstract class AbsSwipeUpHandler< if (endTarget != NEW_TASK) { InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH); + } else { + InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH); } if (endTarget != HOME) { InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME); + } else { + InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME); } if (endTarget != RECENTS) { InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS); + } else { + InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS); } switch (endTarget) {