From 684ee34fe77d7ae476e22190182c72fca898fae5 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 3 Jun 2024 10:59:57 +0800 Subject: [PATCH 01/10] Send source rect hint to Shell via stopSwipePipToHome Launcher has calculated it, so shell side can use it directly to avoid inconsistency. Bug: 331315278 Test: Assume the target app support auto-pip and it doesn't draw under display cutout. E.g. LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES Enter PiP from 90 degrees to home with 0 degrees. The left side of pip should not flicker. Change-Id: Id09efc8a30eeef14a031d9db2ab1e00b6f3034bc --- quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 3 ++- quickstep/src/com/android/quickstep/SystemUiProxy.java | 4 ++-- .../com/android/quickstep/util/SwipePipToHomeAnimator.java | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 463222dfd0..3199076547 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1614,7 +1614,8 @@ public abstract class AbsSwipeUpHandler Date: Tue, 21 May 2024 17:26:17 +0000 Subject: [PATCH 02/10] Add flag for Recents in Taskbar Flag: com.android.launcher3.enable_recents_in_taskbar Test: none Bug: 315354060 Change-Id: I5b757558ab8e5905b4142146901b68f55d0c7ef8 --- aconfig/launcher.aconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index 9147e4c54f..22fe82b0ec 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -284,3 +284,10 @@ flag { description: "Enables folders in all apps" bug: "341582436" } + +flag { + name: "enable_recents_in_taskbar" + namespace: "launcher" + description: "Replace hybrid hotseat app predictions with strictly Recent Apps" + bug: "315354060" +} From ce3bbc7b5ed5a4412077f17ebdb7f5db452d007b Mon Sep 17 00:00:00 2001 From: Liran Binyamin Date: Mon, 10 Jun 2024 10:17:13 -0400 Subject: [PATCH 03/10] Fix state after dragging bubble to dismiss After dragging a bubble in the bubble bar to dismiss it, we remove it from the view and update the width of the bubble bar. The issue here is that the drag state only gets cleared in BubbleBarView after the dismiss animation is complete, so when the width is updated, we don't reposition all the bubbles according to the new width, and end up in a weird state. The fix is to clear the drag state in onDragDismiss. Flag: com.android.wm.shell.enable_bubble_bar Fixes: 345482103 Test: manual - Add multiple bubbles to the bubble bar - Drag a bubble to dismiss it - Observe bubble bar updates correctly - Repeat with other bubbles Change-Id: Ie94f8ace0f5660466686a261174b42c8d71b3e30 --- .../android/launcher3/taskbar/bubbles/BubbleDragController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java index fbd1b88693..efc747c725 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java @@ -153,6 +153,7 @@ public class BubbleDragController { @Override protected void onDragDismiss() { mBubblePinController.onDragEnd(); + mBubbleBarViewController.onBubbleDragEnd(); } @Override From e2bdd1568cf19fb49e5b7d8e2b21773d486b1603 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Mon, 3 Jun 2024 15:49:52 -0400 Subject: [PATCH 04/10] Finish the running recents animation when the user locks their device mid-animation. Flag: NONE bug fix Fixes: 319022192 Test: locked device during home animation and checked temp logs Change-Id: I884694a4318348259b04c3b6073d3ea37eff98fb --- .../taskbar/TaskbarKeyguardController.java | 19 +----- .../TaskbarLauncherStateController.java | 5 +- .../taskbar/TaskbarStashController.java | 8 +-- .../quickstep/TaskAnimationManager.java | 62 +++++++++++++++---- .../quickstep/TouchInteractionService.java | 13 +--- .../quickstep/util/SystemUiFlagUtils.kt | 53 ++++++++++++++++ 6 files changed, 111 insertions(+), 49 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java index eac4eaa130..911140aa2d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java @@ -5,9 +5,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK; @@ -16,6 +13,7 @@ import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_A import android.app.KeyguardManager; import com.android.launcher3.AbstractFloatingView; +import com.android.quickstep.util.SystemUiFlagUtils; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; @@ -26,19 +24,6 @@ import java.io.PrintWriter; */ public class TaskbarKeyguardController implements TaskbarControllers.LoggableTaskbarController { - private static final long KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING - | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING - | SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED - | SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED - | SYSUI_STATE_WAKEFULNESS_MASK; - - // If any of these SysUi flags (via QuickstepContract) is set, the device to be considered - // locked. - public static final long MASK_ANY_SYSUI_LOCKED = SYSUI_STATE_BOUNCER_SHOWING - | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING - | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED - | SYSUI_STATE_DEVICE_DREAMING; - private final TaskbarActivityContext mContext; private long mKeyguardSysuiFlags; private boolean mBouncerShowing; @@ -55,7 +40,7 @@ public class TaskbarKeyguardController implements TaskbarControllers.LoggableTas } public void updateStateForSysuiFlags(@SystemUiStateFlags long systemUiStateFlags) { - long interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS; + long interestingKeyguardFlags = systemUiStateFlags & SystemUiFlagUtils.KEYGUARD_SYSUI_FLAGS; if (interestingKeyguardFlags == mKeyguardSysuiFlags) { // No change in keyguard relevant flags return; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index ead1a8a441..cb9f24ae80 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -16,7 +16,6 @@ package com.android.launcher3.taskbar; import static com.android.app.animation.Interpolators.EMPHASIZED; -import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED; 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; @@ -51,6 +50,7 @@ import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; +import com.android.quickstep.util.SystemUiFlagUtils; import com.android.quickstep.views.RecentsView; import com.android.systemui.animation.ViewRootSync; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -343,8 +343,7 @@ public class TaskbarLauncherStateController { prevIsAwake && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE)); } - boolean isDeviceLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED); - updateStateForFlag(FLAG_DEVICE_LOCKED, isDeviceLocked); + updateStateForFlag(FLAG_DEVICE_LOCKED, SystemUiFlagUtils.isLocked(systemUiStateFlags)); // Taskbar is hidden whenever the device is dreaming. The dreaming state includes the // interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 74d2d60014..a54a349147 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -25,7 +25,6 @@ import static com.android.internal.jank.InteractionJankMonitor.Configuration; import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW; -import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.FlagDebugUtils.appendFlag; import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; @@ -35,7 +34,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_I import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -66,6 +64,7 @@ import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.util.SystemUiFlagUtils; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -942,9 +941,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba && DisplayController.isTransientTaskbar(mActivity); updateStateForFlag(FLAG_STASHED_SYSUI, hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING) || stashForBubbles); - boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED) - && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY); - updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked); + updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, + SystemUiFlagUtils.isLocked(systemUiStateFlags)); mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING); mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING); diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 2348f28c62..28fa81a4f5 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -26,6 +26,8 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -44,9 +46,11 @@ import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; import com.android.quickstep.util.ActiveGestureLog; +import com.android.quickstep.util.SystemUiFlagUtils; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; @@ -373,20 +377,54 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return mCallbacks; } - public void endLiveTile() { - if (mLastGestureState == null) { - return; - } - BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); - if (containerInterface.isInLiveTileMode() - && containerInterface.getCreatedContainer() != null) { - RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel(); - if (recentsView != null) { - recentsView.switchToScreenshot(null, - () -> recentsView.finishRecentsAnimation(true /* toRecents */, - false /* shouldPip */, null)); + public void onSystemUiFlagsChanged(@QuickStepContract.SystemUiStateFlags long lastSysUIFlags, + @QuickStepContract.SystemUiStateFlags long newSysUIFlags) { + long isShadeExpandedFlagMask = + SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; + boolean wasExpanded = hasAnyFlag(lastSysUIFlags, isShadeExpandedFlagMask); + boolean isExpanded = hasAnyFlag(newSysUIFlags, isShadeExpandedFlagMask); + if (wasExpanded != isExpanded && isExpanded) { + // End live tile when expanding the notification panel for the first time from + // overview. + if (endLiveTile()) { + return; } } + + boolean wasLocked = SystemUiFlagUtils.isLocked(lastSysUIFlags); + boolean isLocked = SystemUiFlagUtils.isLocked(newSysUIFlags); + if (wasLocked != isLocked && isLocked) { + // Finish the running recents animation when locking the device. + finishRunningRecentsAnimation( + mController != null && mController.getFinishTargetIsLauncher()); + } + } + + private boolean hasAnyFlag(long flags, long flagMask) { + return (flags & flagMask) != 0; + } + + /** + * Switches the {@link RecentsView} to screenshot if in live tile mode. + * + * @return true iff the {@link RecentsView} was in live tile mode and was switched to screenshot + */ + public boolean endLiveTile() { + if (mLastGestureState == null) { + return false; + } + BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); + if (!containerInterface.isInLiveTileMode() + || containerInterface.getCreatedContainer() == null) { + return false; + } + RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel(); + if (recentsView == null) { + return false; + } + recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation( + true /* toRecents */, false /* shouldPip */, null)); + return true; } public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) { diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 4599f180b1..d79242a89d 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -47,8 +47,6 @@ import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SY import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES; @@ -643,16 +641,7 @@ public class TouchInteractionService extends Service { SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); mOverviewComponentObserver.onSystemUiStateChanged(); mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags); - - long isShadeExpandedFlag = - SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; - boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0; - boolean isExpanded = (systemUiStateFlags & isShadeExpandedFlag) != 0; - if (wasExpanded != isExpanded && isExpanded) { - // End live tile when expanding the notification panel for the first time from - // overview. - mTaskAnimationManager.endLiveTile(); - } + mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags); } } diff --git a/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt new file mode 100644 index 0000000000..5f4388c918 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util + +import com.android.systemui.shared.system.QuickStepContract +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags + +/** Util class for holding and checking [SystemUiStateFlags] masks. */ +object SystemUiFlagUtils { + const val KEYGUARD_SYSUI_FLAGS = + (QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or + QuickStepContract.SYSUI_STATE_DEVICE_DOZING or + QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED or + QuickStepContract.SYSUI_STATE_HOME_DISABLED or + QuickStepContract.SYSUI_STATE_BACK_DISABLED or + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or + QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK) + + // If any of these SysUi flags (via QuickstepContract) is set, the device to be considered + // locked. + private const val MASK_ANY_SYSUI_LOCKED = + (QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or + QuickStepContract.SYSUI_STATE_DEVICE_DREAMING) + + /** + * Returns true iff the given [SystemUiStateFlags] imply that the device is considered locked. + */ + @JvmStatic + fun isLocked(@SystemUiStateFlags flags: Long): Boolean { + return hasAnyFlag(flags, MASK_ANY_SYSUI_LOCKED) && + !hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY) + } + + private fun hasAnyFlag(@SystemUiStateFlags flags: Long, flagMask: Long): Boolean { + return (flags and flagMask) != 0L + } +} From de5ef62967383310ed2f06a73d082abf86c9cd1c Mon Sep 17 00:00:00 2001 From: Sihua Ma Date: Sat, 8 Jun 2024 01:15:40 +0000 Subject: [PATCH 05/10] Migrate GeneratedPreviewTest to multivalent Test: atest NexusLauncherRoboTests Test: SysUI studio Fix: 325088369 Flag: TEST_ONLY Change-Id: I2c88a357c8ac5fb0171a70e850be25e8fb11de33 --- tests/Android.bp | 1 + .../android/launcher3/widget/GeneratedPreviewTest.kt | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) rename tests/{ => multivalentTests}/src/com/android/launcher3/widget/GeneratedPreviewTest.kt (94%) diff --git a/tests/Android.bp b/tests/Android.bp index 1dcb2a6fe3..e51242f48a 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -211,6 +211,7 @@ android_robolectric_test { "Launcher3TestResources", "SystemUISharedLib", "launcher-testing-shared", + "android.appwidget.flags-aconfig-java", ], libs: [ "android.test.runner", diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt similarity index 94% rename from tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt rename to tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt index 460058b937..b239aed7cf 100644 --- a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt @@ -18,12 +18,12 @@ import android.widget.RemoteViews import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.icons.IconCache import com.android.launcher3.icons.IconProvider import com.android.launcher3.model.WidgetItem -import com.android.launcher3.tests.R import com.android.launcher3.util.ActivityContextWrapper import com.android.launcher3.util.Executors import com.google.common.truth.Truth.assertThat @@ -41,7 +41,10 @@ class GeneratedPreviewTest { "com.android.launcher3.tests", "com.android.launcher3.testcomponent.AppWidgetNoConfig" ) - private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue + private val generatedPreviewLayout = + getInstrumentation().context.run { + resources.getIdentifier("test_layout_appwidget_blue", "layout", packageName) + } private lateinit var context: Context private lateinit var generatedPreview: RemoteViews private lateinit var widgetCell: WidgetCell @@ -137,6 +140,7 @@ class GeneratedPreviewTest { assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse() assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse() } + @Test @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS) fun widgetItem_getGeneratedPreview() { @@ -148,6 +152,7 @@ class GeneratedPreviewTest { @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS) fun widgetCell_showGeneratedPreview() { widgetCell.applyFromCellItem(widgetItem) + DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get() assertThat(widgetCell.appWidgetHostViewPreview).isNotNull() assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo) .isEqualTo(appWidgetProviderInfo) @@ -157,6 +162,7 @@ class GeneratedPreviewTest { @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS) fun widgetCell_showGeneratedPreview_flagDisabled() { widgetCell.applyFromCellItem(widgetItem) + DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get() assertThat(widgetCell.appWidgetHostViewPreview).isNull() } } From 3fa291e1a7a8aae436276e30294c7cdcb833c6b0 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 7 Jun 2024 05:48:57 +0000 Subject: [PATCH 06/10] Add max width to the screen instructions view text - This ensures that the instruction wraps if the text is too long Fixes: 328577545 Fixes: 345128488 Flag: EXEMPT bugfix Test: Visual inspection of instructions view in different languages/form factors Change-Id: I73e889372a5c482277b0e4b61fb834304304c0a6 Merged-In: I73e889372a5c482277b0e4b61fb834304304c0a6 (cherry picked from commit 73cf3bc3a1b622275de7eca4b5b49710eff7aeaa) --- quickstep/res/layout/split_instructions_view.xml | 2 ++ quickstep/res/values-sw600dp/dimens.xml | 4 ++++ quickstep/res/values/dimens.xml | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml index 1115ff2b7c..797ea45be4 100644 --- a/quickstep/res/layout/split_instructions_view.xml +++ b/quickstep/res/layout/split_instructions_view.xml @@ -29,6 +29,7 @@ android:id="@+id/split_instructions_text" android:layout_height="wrap_content" android:layout_width="wrap_content" + android:maxWidth="@dimen/split_instructions_view_max_width" android:textColor="?androidprv:attr/textColorOnAccent" android:text="@string/toast_split_select_app" /> @@ -36,6 +37,7 @@ android:id="@+id/split_instructions_text_cancel" android:layout_height="wrap_content" android:layout_width="wrap_content" + android:layout_gravity="center_vertical" android:textColor="?androidprv:attr/textColorOnAccent" android:layout_marginStart="@dimen/split_instructions_start_margin_cancel" android:text="@string/toast_split_select_app_cancel" diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml index f9528b3632..e24d8fea79 100644 --- a/quickstep/res/values-sw600dp/dimens.xml +++ b/quickstep/res/values-sw600dp/dimens.xml @@ -45,4 +45,8 @@ 38sp 15sp + + + 300dp + diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index dbcba4904a..6a863f0fc8 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -464,4 +464,8 @@ 14sp 8dp + + + 220dp + From c1470021c86d49492f1eaa2d2e0390588f0fd98d Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Wed, 5 Jun 2024 18:19:55 -0700 Subject: [PATCH 07/10] Fix flaky test Attempts to fix a flaky test by ensuring that recents is always cleared before creating a split pair (so the split pair under test is always the same). Bug: 340935208 Test: testSaveAppPairMenuItemOrActionExistsOnSplitPair(), testSplitTaskTapBothIconMenus() Flag: TEST_ONLY Change-Id: Ibc81b90fac531f0e78e93a494ff59073ab5e52cf --- .../quickstep/views/OverviewActionsView.java | 2 +- .../quickstep/TaplOverviewIconTest.java | 2 ++ .../quickstep/TaplTestsSplitscreen.java | 18 +++----------- .../launcher3/ui/AbstractLauncherUiTest.java | 7 ++++++ .../android/launcher3/tapl/BaseOverview.java | 24 ++++++++++++++++--- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 604d072ad5..d9468c7038 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -278,7 +278,7 @@ public class OverviewActionsView extends FrameLayo boolean showSingleTaskActions = !mIsGroupedTask; boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair; Log.d(TAG, "updateActionButtonsVisibility() called: showSingleTaskActions = [" - + showSingleTaskActions + ", showGroupActions = [" + showGroupActions + "]"); + + showSingleTaskActions + "], showGroupActions = [" + showGroupActions + "]"); getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0); getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0); } diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java index fa10b61ad4..b7fd8be311 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java @@ -88,6 +88,8 @@ public class TaplOverviewIconTest extends AbstractLauncherUiTest { UiDevice.getInstance(getInstrumentation()).pressHome(); mLauncher.waitForLauncherInitialized(); } + + /** Clears all recent tasks */ + protected void clearAllRecentTasks() { + if (!mLauncher.getRecentTasks().isEmpty()) { + mLauncher.goHome().switchToOverview().dismissAllTasks(); + } + } } diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index e10893eea5..567a8bd1c0 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -23,6 +23,7 @@ import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; import android.graphics.Rect; +import android.util.Log; import android.view.KeyEvent; import androidx.annotation.NonNull; @@ -44,6 +45,7 @@ import java.util.stream.Collectors; * Common overview panel for both Launcher and fallback recents */ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { + private static final String TAG = "BaseOverview"; protected static final String TASK_RES_ID = "task"; private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile( "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0"); @@ -384,25 +386,31 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { protected boolean isActionsViewVisible() { if (!hasTasks() || isClearAllVisible()) { + Log.d(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible"); return false; } boolean isTablet = mLauncher.isTablet(); if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) { + Log.d(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview"); return false; } OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask(); if (task == null) { + Log.d(TAG, "Not expecting an actions bar: no current task"); return false; } // In tablets, if focused task is not in center, overview actions aren't visible. if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) { + Log.d(TAG, "Not expecting an actions bar: device is tablet and task is not centered"); return false; } if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) { + Log.d(TAG, "Not expecting an actions bar: device is phone and task is split"); // Overview actions aren't visible for split screen tasks, except for save app pair // button on tablets. return false; } + Log.d(TAG, "Expecting an actions bar"); return true; } @@ -447,10 +455,20 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { } private void verifyActionsViewVisibility() { + // If no running tasks, no need to verify actions view visibility. + if (getTasks().isEmpty()) { + return; + } + + boolean isTablet = mLauncher.isTablet(); + OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask(); + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( - "want to assert overview actions view visibility")) { - boolean isTablet = mLauncher.isTablet(); - OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask(); + "want to assert overview actions view visibility=" + + isActionsViewVisible() + + ", focused task is " + + (task == null ? "null" : (task.isTaskSplit() ? "split" : "not split")) + )) { if (isActionsViewVisible()) { if (task.isTaskSplit()) { From a2b510dc23b4e77b4d0fe3117f41c9b62a158e9a Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 21 May 2024 21:21:43 +0000 Subject: [PATCH 08/10] Move Desktop running apps support into TaskbarRecentAppsController - Merged DesktopTaskbarRunningAppsController up into TaskbarRecentAppsController, which is now initialized directly - The old TaskbarRecentAppsController was effectively a no-op that was always overridden, so merging the one subclass up makes things simpler (especially for the follow up CLs which will add support for switching between Running and Recent tasks using the same underlying data). Flag: com.android.launcher3.enable_recents_in_taskbar Test: TaskbarRecentAppsControllerTest Bug: 315354060 Change-Id: I8411fb832e5dd3d76201d2694dec0b11bd70bbf9 --- .../taskbar/TaskbarActivityContext.java | 16 +- .../launcher3/taskbar/TaskbarControllers.java | 5 +- .../taskbar/TaskbarModelCallbacks.java | 2 +- .../taskbar/TaskbarRecentAppsController.java | 77 --------- ...ller.kt => TaskbarRecentAppsController.kt} | 163 +++++++++--------- ....kt => TaskbarRecentAppsControllerTest.kt} | 50 +++--- 6 files changed, 116 insertions(+), 197 deletions(-) delete mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java rename quickstep/src/com/android/launcher3/taskbar/{DesktopTaskbarRunningAppsController.kt => TaskbarRecentAppsController.kt} (62%) rename quickstep/tests/src/com/android/launcher3/taskbar/{DesktopTaskbarRunningAppsControllerTest.kt => TaskbarRecentAppsControllerTest.kt} (82%) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 0de0550016..61877f0afa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -41,8 +41,6 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING; -import static com.android.window.flags.Flags.enableDesktopWindowingMode; -import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps; import static com.android.wm.shell.Flags.enableTinyTaskbar; import android.animation.AnimatorSet; @@ -304,7 +302,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new VoiceInteractionWindowController(this), new TaskbarTranslationController(this), new TaskbarSpringOnStashController(this), - createTaskbarRecentAppsController(), + new TaskbarRecentAppsController( + RecentsModel.INSTANCE.get(this), + LauncherActivityInterface.INSTANCE::getDesktopVisibilityController), TaskbarEduTooltipController.newInstance(this), new KeyboardQuickSwitchController(), new TaskbarPinningController(this, () -> @@ -314,16 +314,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mLauncherPrefs = LauncherPrefs.get(this); } - private TaskbarRecentAppsController createTaskbarRecentAppsController() { - // TODO(b/335401172): unify DesktopMode checks in Launcher - if (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()) { - return new DesktopTaskbarRunningAppsController( - RecentsModel.INSTANCE.get(this), - LauncherActivityInterface.INSTANCE::getDesktopVisibilityController); - } - return TaskbarRecentAppsController.DEFAULT; - } - /** Updates {@link DeviceProfile} instances for any Taskbar windows. */ public void updateDeviceProfile(DeviceProfile launcherDp) { applyDeviceProfile(launcherDp); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index f9ddc3db2f..58c5e835c9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -180,8 +180,9 @@ public class TaskbarControllers { taskbarUnfoldAnimationController, taskbarKeyguardController, stashedHandleViewController, taskbarStashController, taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController, - voiceInteractionWindowController, taskbarTranslationController, - taskbarEduTooltipController, keyboardQuickSwitchController, taskbarPinningController + voiceInteractionWindowController, taskbarRecentAppsController, + taskbarTranslationController, taskbarEduTooltipController, + keyboardQuickSwitchController, taskbarPinningController, }; mBackgroundRendererControllers = new BackgroundRendererController[] { taskbarDragLayerController, taskbarScrimViewController, diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java index 35e1c7baa9..2b0e1699cc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java @@ -79,7 +79,7 @@ public class TaskbarModelCallbacks implements public void init(TaskbarControllers controllers) { mControllers = controllers; - if (mControllers.taskbarRecentAppsController.isEnabled()) { + if (mControllers.taskbarRecentAppsController.getCanShowRunningApps()) { RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this); if (shouldShowRunningAppsInDesktopMode()) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java deleted file mode 100644 index 606ba5b633..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar; - -import static java.util.Collections.emptySet; - -import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; - -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.ItemInfo; - -import java.util.Set; - -/** - * Base class for providing recent apps functionality - */ -public class TaskbarRecentAppsController { - - public static final TaskbarRecentAppsController DEFAULT = new TaskbarRecentAppsController(); - - // Initialized in init. - protected TaskbarControllers mControllers; - - @CallSuper - protected void init(TaskbarControllers taskbarControllers) { - mControllers = taskbarControllers; - } - - @CallSuper - protected void onDestroy() { - mControllers = null; - } - - /** Stores the current {@link AppInfo} instances, no-op except in desktop environment. */ - protected void setApps(AppInfo[] apps) { - } - - /** - * Indicates whether recent apps functionality is enabled, should return false except in - * desktop environment. - */ - protected boolean isEnabled() { - return false; - } - - /** Called to update hotseatItems, no-op except in desktop environment. */ - protected ItemInfo[] updateHotseatItemInfos(@NonNull ItemInfo[] hotseatItems) { - return hotseatItems; - } - - /** Called to update the list of currently running apps, no-op except in desktop environment. */ - protected void updateRunningApps() {} - - /** Returns the currently running apps, or an empty Set if outside of Desktop environment. */ - public Set getRunningApps() { - return emptySet(); - } - - /** Returns the set of apps whose tasks are all minimized. */ - public Set getMinimizedApps() { - return emptySet(); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt similarity index 62% rename from quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt rename to quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt index d4bef28bf8..0946caf986 100644 --- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt @@ -13,37 +13,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.launcher3.taskbar import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration -import android.util.Log -import android.util.SparseArray import androidx.annotation.VisibleForTesting -import androidx.core.util.valueIterator +import com.android.launcher3.Flags.enableRecentsInTaskbar import com.android.launcher3.model.data.AppInfo import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.statehandlers.DesktopVisibilityController +import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController import com.android.quickstep.RecentsModel -import kotlin.collections.filterNotNull +import com.android.window.flags.Flags.enableDesktopWindowingMode +import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps +import java.io.PrintWriter /** - * Shows running apps when in Desktop Mode. - * - * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default - * recent-apps behaviour when outside of Desktop Mode. - * - * This class should only be used if - * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled. + * Provides recent apps functionality, when the Taskbar Recent Apps section is enabled. Behavior: + * - When in Fullscreen mode: show the N most recent Tasks + * - When in Desktop Mode: show the currently running (open) Tasks */ -class DesktopTaskbarRunningAppsController( +class TaskbarRecentAppsController( private val recentsModel: RecentsModel, // Pass a provider here instead of the actual DesktopVisibilityController instance since that // instance might not be available when this constructor is called. private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?, -) : TaskbarRecentAppsController() { +) : LoggableTaskbarController { + + // TODO(b/335401172): unify DesktopMode checks in Launcher. + val canShowRunningApps = + enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps() + + // TODO(b/343532825): Add a setting to disable Recents even when the flag is on. + @VisibleForTesting + var isEnabled = enableRecentsInTaskbar() || canShowRunningApps + + // Initialized in init. + private lateinit var controllers: TaskbarControllers private var apps: Array? = null private var allRunningDesktopAppInfos: List? = null @@ -55,22 +62,40 @@ class DesktopTaskbarRunningAppsController( private val isInDesktopMode: Boolean get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false - override fun onDestroy() { - super.onDestroy() + val runningApps: Set + get() { + if (!isEnabled || !isInDesktopMode) { + return emptySet() + } + return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet() + } + + val minimizedApps: Set + get() { + if (!isInDesktopMode) { + return emptySet() + } + return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() + ?: emptySet() + } + + fun init(taskbarControllers: TaskbarControllers) { + controllers = taskbarControllers + } + + fun onDestroy() { apps = null } - @VisibleForTesting - public override fun setApps(apps: Array?) { + /** Stores the current [AppInfo] instances, no-op except in desktop environment. */ + fun setApps(apps: Array?) { this.apps = apps } - override fun isEnabled() = true - - @VisibleForTesting - public override fun updateHotseatItemInfos(hotseatItems: Array): Array { - if (!isInDesktopMode) { - Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode") + /** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */ + // TODO(next CL): add new section of Tasks instead of changing Hotseat items + fun updateHotseatItemInfos(hotseatItems: Array): Array { + if (!isEnabled || !isInDesktopMode) { return hotseatItems } val newHotseatItemInfos = @@ -89,55 +114,6 @@ class DesktopTaskbarRunningAppsController( return newHotseatItemInfos.toTypedArray() } - override fun getRunningApps(): Set { - if (!isInDesktopMode) { - return emptySet() - } - return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet() - } - - override fun getMinimizedApps(): Set { - if (!isInDesktopMode) { - return emptySet() - } - return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet() - } - - @VisibleForTesting - public override fun updateRunningApps() { - if (!isInDesktopMode) { - Log.d(TAG, "updateRunningApps: not in Desktop Mode") - mControllers.taskbarViewController.commitRunningAppsToUI() - return - } - val runningTasks = getDesktopRunningTasks() - val runningAppInfo = getAppInfosFromRunningTasks(runningTasks) - allRunningDesktopAppInfos = runningAppInfo - updateMinimizedApps(runningTasks, runningAppInfo) - mControllers.taskbarViewController.commitRunningAppsToUI() - } - - private fun updateMinimizedApps( - runningTasks: List, - runningAppInfo: List, - ) { - val allRunningAppTasks = - runningAppInfo - .mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } } - .associate { (appInfo, targetPackage) -> - appInfo to - runningTasks - .filter { it.realActivity?.packageName == targetPackage } - .map { it.taskId } - } - val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible } - allMinimizedDesktopAppInfos = - allRunningAppTasks - .filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } } - .keys - .toList() - } - private fun getRunningDesktopAppInfosExceptHotseatApps( allRunningDesktopAppInfos: List, hotseatItems: List @@ -165,12 +141,43 @@ class DesktopTaskbarRunningAppsController( .filterNotNull() } - private fun getAppInfosFromRunningTask(task: RunningTaskInfo): AppInfo? = - apps?.firstOrNull { it.targetPackage == task.realActivity?.packageName } + /** Called to update the list of currently running apps, no-op except in desktop environment. */ + fun updateRunningApps() { + if (!isEnabled || !isInDesktopMode) { + return controllers.taskbarViewController.commitRunningAppsToUI() + } + val runningTasks = getDesktopRunningTasks() + val runningAppInfo = getAppInfosFromRunningTasks(runningTasks) + allRunningDesktopAppInfos = runningAppInfo + updateMinimizedApps(runningTasks, runningAppInfo) + controllers.taskbarViewController.commitRunningAppsToUI() + } - private fun SparseArray.toList(): List = valueIterator().asSequence().toList() + private fun updateMinimizedApps( + runningTasks: List, + runningAppInfo: List, + ) { + val allRunningAppTasks = + runningAppInfo + .mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } } + .associate { (appInfo, targetPackage) -> + appInfo to + runningTasks + .filter { it.realActivity?.packageName == targetPackage } + .map { it.taskId } + } + val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible } + allMinimizedDesktopAppInfos = + allRunningAppTasks + .filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } } + .keys + .toList() + } - companion object { - private const val TAG = "TabletDesktopTaskbarRunningAppsController" + override fun dumpLogs(prefix: String, pw: PrintWriter) { + pw.println("$prefix TaskbarRecentAppsController:") + pw.println("$prefix\tisEnabled=$isEnabled") + pw.println("$prefix\tcanShowRunningApps=$canShowRunningApps") + // TODO(next CL): add more logs } } diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt similarity index 82% rename from quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt rename to quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt index 5b567101b6..104263af5b 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt +++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt @@ -37,7 +37,7 @@ import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) -class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { +class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @get:Rule val mockitoRule = MockitoJUnit.rule() @@ -46,19 +46,18 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { private var nextTaskId: Int = 500 - private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController + private lateinit var recentAppsController: TaskbarRecentAppsController private lateinit var userHandle: UserHandle @Before fun setUp() { super.setup() userHandle = Process.myUserHandle() - taskbarRunningAppsController = - DesktopTaskbarRunningAppsController(mockRecentsModel) { - mockDesktopVisibilityController - } - taskbarRunningAppsController.init(taskbarControllers) - taskbarRunningAppsController.setApps( + recentAppsController = + TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController } + recentAppsController.init(taskbarControllers) + recentAppsController.isEnabled = true + recentAppsController.setApps( ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray() ) } @@ -69,7 +68,7 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val hotseatItems = createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) - assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) + assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) .isEqualTo(hotseatItems.toTypedArray()) } @@ -81,10 +80,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val runningTasks = createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() val newHotseatItems = - taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) + recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) assertThat(newHotseatItems.map { it?.targetPackage }) .containsExactlyElementsIn(hotseatPackages) @@ -96,7 +95,7 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val hotseatItems = createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) - assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) + assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) .isEqualTo(hotseatItems.toTypedArray()) } @@ -108,10 +107,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val runningTasks = createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() val newHotseatItems = - taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) + recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) val expectedPackages = listOf( @@ -134,10 +133,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) ) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() val newHotseatItems = - taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) + recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) val expectedPackages = listOf( @@ -156,10 +155,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val runningTasks = createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() - assertThat(taskbarRunningAppsController.runningApps).isEmpty() - assertThat(taskbarRunningAppsController.minimizedApps).isEmpty() + assertThat(recentAppsController.runningApps).isEmpty() + assertThat(recentAppsController.minimizedApps).isEmpty() } @Test @@ -168,11 +167,11 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { val runningTasks = createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() - assertThat(taskbarRunningAppsController.runningApps) + assertThat(recentAppsController.runningApps) .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) - assertThat(taskbarRunningAppsController.minimizedApps).isEmpty() + assertThat(recentAppsController.minimizedApps).isEmpty() } @Test @@ -187,12 +186,11 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() { ) ) whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) - taskbarRunningAppsController.updateRunningApps() + recentAppsController.updateRunningApps() - assertThat(taskbarRunningAppsController.runningApps) + assertThat(recentAppsController.runningApps) .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3) - assertThat(taskbarRunningAppsController.minimizedApps) - .containsExactly(RUNNING_APP_PACKAGE_3) + assertThat(recentAppsController.minimizedApps).containsExactly(RUNNING_APP_PACKAGE_3) } private fun createHotseatItemsFromPackageNames(packageNames: List): List { From e94e5094131246f878a524da4aa3f4fb101570f0 Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Mon, 10 Jun 2024 19:40:43 -0700 Subject: [PATCH 09/10] Expand touch target of split cancel button to meet a11y requirements This CL adds a TouchDelegate to the "Cancel" button on SplitInstructionsView so that it is always at least 48dp by 48dp. I.e. if the touch target is smaller than 48dp, it expands the TouchDelegate to be at least that size. Fixes: 323108127 Test: Manually verified that the touch target is larger Flag: EXEMPT bugfix Change-Id: Id14bc39660ee7767991a3b5613f1282945a2ef96 --- .../views/SplitInstructionsView.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java index a56d51e515..3d994e89a8 100644 --- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java +++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java @@ -18,13 +18,16 @@ package com.android.quickstep.views; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON; +import static com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.content.Context; +import android.graphics.Rect; import android.util.AttributeSet; import android.util.FloatProperty; +import android.view.TouchDelegate; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; @@ -41,9 +44,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StateManager; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.states.StateAnimationConfig; - import com.android.quickstep.util.SplitSelectStateController; /** @@ -133,6 +134,28 @@ public class SplitInstructionsView extends LinearLayout { cancelTextView.setVisibility(VISIBLE); cancelTextView.setOnClickListener((v) -> exitSplitSelection()); instructionTextView.setText(R.string.toast_contextual_split_select_app); + + // After layout, expand touch target of cancel button to meet minimum a11y measurements. + post(() -> { + int minTouchSize = getResources() + .getDimensionPixelSize(settingslib_preferred_minimum_touch_target); + Rect r = new Rect(); + cancelTextView.getHitRect(r); + + if (r.width() < minTouchSize) { + // add 1 to ensure ceiling on int division + int expandAmount = (minTouchSize + 1 - r.width()) / 2; + r.left -= expandAmount; + r.right += expandAmount; + } + if (r.height() < minTouchSize) { + int expandAmount = (minTouchSize + 1 - r.height()) / 2; + r.top -= expandAmount; + r.bottom += expandAmount; + } + + setTouchDelegate(new TouchDelegate(r, cancelTextView)); + }); } // Set accessibility title, will be announced by a11y tools. From 9e12c3f152eda5993408cad32e73ff9bed80d7f4 Mon Sep 17 00:00:00 2001 From: Charlie Anderson Date: Mon, 10 Jun 2024 18:31:01 -0400 Subject: [PATCH 10/10] Adding bugfix flag for archiving bug extras Bug: 322314760 Test: locally Flag: com.android.launcher3.enable_first_screen_broadcast_archiving_extras Change-Id: I33edcf09eee990727613246fb5942263feb49625 --- aconfig/launcher.aconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index 22fe82b0ec..fecc43d0b2 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -291,3 +291,14 @@ flag { description: "Replace hybrid hotseat app predictions with strictly Recent Apps" bug: "315354060" } + +flag { + name: "enable_first_screen_broadcast_archiving_extras" + namespace: "launcher" + description: "adds Extras to first screen broadcast for archived apps" + bug: "322314760" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +}