diff options
70 files changed, 1433 insertions, 365 deletions
diff --git a/cmds/am/am.sh b/cmds/am/am.sh index 76ec214cb446..f099be3e26a2 100755 --- a/cmds/am/am.sh +++ b/cmds/am/am.sh @@ -1,11 +1,10 @@ #!/system/bin/sh -# set to top-app process group -settaskprofile $$ SCHED_SP_TOP_APP >/dev/null 2>&1 || true - if [ "$1" != "instrument" ] ; then cmd activity "$@" else + # set to top-app process group for instrument + settaskprofile $$ SCHED_SP_TOP_APP >/dev/null 2>&1 || true base=/system export CLASSPATH=$base/framework/am.jar exec app_process $base/bin com.android.commands.am.Am "$@" diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index fded88212127..d8919160320a 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -641,6 +641,9 @@ public final class DisplayManager { * is triggered whenever the properties of a {@link android.view.Display}, such as size, * state, density are modified. * + * This event is not triggered for refresh rate changes as they can change very often. + * To monitor refresh rate changes, subscribe to {@link EVENT_TYPE_DISPLAY_REFRESH_RATE}. + * * @see #registerDisplayListener(DisplayListener, Handler, long) * */ @@ -839,6 +842,9 @@ public final class DisplayManager { * Registers a display listener to receive notifications about when * displays are added, removed or changed. * + * We encourage to use {@link #registerDisplayListener(Executor, long, DisplayListener)} + * instead to subscribe for explicit events of interest + * * @param listener The listener to register. * @param handler The handler on which the listener should be invoked, or null * if the listener should be invoked on the calling thread's looper. @@ -847,7 +853,9 @@ public final class DisplayManager { */ public void registerDisplayListener(DisplayListener listener, Handler handler) { registerDisplayListener(listener, handler, EVENT_TYPE_DISPLAY_ADDED - | EVENT_TYPE_DISPLAY_CHANGED | EVENT_TYPE_DISPLAY_REMOVED); + | EVENT_TYPE_DISPLAY_CHANGED + | EVENT_TYPE_DISPLAY_REFRESH_RATE + | EVENT_TYPE_DISPLAY_REMOVED); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index b5715ed25bd9..339dbf2c2029 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -1766,29 +1766,23 @@ public final class DisplayManagerGlobal { } if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_CHANGED) != 0) { - // For backward compatibility, a client subscribing to - // DisplayManager.EVENT_FLAG_DISPLAY_CHANGED will be enrolled to both Basic and - // RR changes - baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED - | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED; } - if ((eventFlags - & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) { + if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) { baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; } - if (Flags.displayListenerPerformanceImprovements()) { - if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) { - baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; - } + if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; + } + if (Flags.displayListenerPerformanceImprovements()) { if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_STATE) != 0) { baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE; } } - return baseEventMask; } } diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index 785246074cee..1ce5df7cd137 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -55,6 +55,7 @@ public enum DesktopModeFlags { Flags::enableDesktopAppLaunchAlttabTransitionsBugfix, true), ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX(Flags::enableDesktopAppLaunchTransitionsBugfix, true), + ENABLE_DESKTOP_CLOSE_SHORTCUT_BUGFIX(Flags::enableDesktopCloseShortcutBugfix, false), ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS(Flags::enableCompatUiVisibilityStatus, true), ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX( Flags::enableDesktopRecentsTransitionsCornersBugfix, false), diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 509e084e01e6..b805ac560b8d 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -695,4 +695,14 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -}
\ No newline at end of file +} + +flag { + name: "enable_desktop_close_shortcut_bugfix" + namespace: "lse_desktop_experience" + description: "Fix the window-close keyboard shortcut in Desktop Mode." + bug: "394599430" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index 05a33fe830e8..d8cf258e23ba 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -160,19 +160,21 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen Objects.requireNonNull(mConfigurationService, "A null ProtoLog Configuration Service was provided!"); - try { - var args = createConfigurationServiceRegisterClientArgs(); + mBackgroundLoggingService.execute(() -> { + try { + var args = createConfigurationServiceRegisterClientArgs(); - final var groupArgs = mLogGroups.values().stream() - .map(group -> new RegisterClientArgs - .GroupConfig(group.name(), group.isLogToLogcat())) - .toArray(RegisterClientArgs.GroupConfig[]::new); - args.setGroups(groupArgs); + final var groupArgs = mLogGroups.values().stream() + .map(group -> new RegisterClientArgs + .GroupConfig(group.name(), group.isLogToLogcat())) + .toArray(RegisterClientArgs.GroupConfig[]::new); + args.setGroups(groupArgs); - mConfigurationService.registerClient(this, args); - } catch (RemoteException e) { - throw new RuntimeException("Failed to register ProtoLog client"); - } + mConfigurationService.registerClient(this, args); + } catch (RemoteException e) { + throw new RuntimeException("Failed to register ProtoLog client"); + } + }); } /** diff --git a/core/java/com/android/internal/protolog/WmProtoLogGroups.java b/core/java/com/android/internal/protolog/WmProtoLogGroups.java index 4bd5d24b71e2..5edc2fbd4c8f 100644 --- a/core/java/com/android/internal/protolog/WmProtoLogGroups.java +++ b/core/java/com/android/internal/protolog/WmProtoLogGroups.java @@ -100,6 +100,8 @@ public enum WmProtoLogGroups implements IProtoLogGroup { WM_DEBUG_TPL(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_DEBUG_EMBEDDED_WINDOWS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_PRESENTATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagerProtoLogTest"); private final boolean mEnabled; diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d7ffcc54562c..17acf9aed278 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -7352,6 +7352,21 @@ default on this device--> <string-array translatable="false" name="config_notificationDefaultUnsupportedAdjustments" /> + <!-- Preference name of bugreport--> + <string name="prefs_bugreport" translatable="false">bugreports</string> + + <!-- key value of warning state stored in bugreport preference--> + <string name="key_warning_state" translatable="false">warning-state</string> + + <!-- Bugreport warning dialog state unknown--> + <integer name="bugreport_state_unknown">0</integer> + + <!-- Bugreport warning dialog state shows the warning dialog--> + <integer name="bugreport_state_show">1</integer> + + <!-- Bugreport warning dialog state skips the warning dialog--> + <integer name="bugreport_state_hide">2</integer> + <!-- By default ActivityOptions#makeScaleUpAnimation is only used between activities. This config enables OEMs to support its usage across tasks.--> <bool name="config_enableCrossTaskScaleUpAnimation">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6701e63c4f90..cc2897a2779e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -5906,6 +5906,12 @@ <java-symbol type="string" name="usb_apm_usb_suspicious_activity_notification_title" /> <java-symbol type="string" name="usb_apm_usb_suspicious_activity_notification_text" /> + <java-symbol type="string" name="prefs_bugreport" /> + <java-symbol type="string" name="key_warning_state" /> + <java-symbol type="integer" name="bugreport_state_unknown" /> + <java-symbol type="integer" name="bugreport_state_show" /> + <java-symbol type="integer" name="bugreport_state_hide" /> + <!-- Enable OEMs to support scale up anim across tasks.--> <java-symbol type="bool" name="config_enableCrossTaskScaleUpAnimation" /> diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index 8fa510381060..dc2f0a69375d 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -307,8 +307,10 @@ public class DisplayManagerGlobalTest { assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED, mDisplayManagerGlobal .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_ADDED, 0)); - assertEquals(DISPLAY_CHANGE_EVENTS, mDisplayManagerGlobal - .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, 0)); + assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED, + mDisplayManagerGlobal + .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, + 0)); assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, mDisplayManagerGlobal.mapFiltersToInternalEventFlag( DisplayManager.EVENT_TYPE_DISPLAY_REMOVED, 0)); diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 13d0169c47c5..a08f88a5b937 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -177,3 +177,10 @@ flag { description: "Factor task-view state tracking out of taskviewtransitions" bug: "384976265" } + +flag { + name: "enable_bubble_bar_on_phones" + namespace: "multitasking" + description: "Try out bubble bar on phones" + bug: "394869612" +} diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml index 0b1f76f5ce0e..d280083ae7f5 100644 --- a/libs/WindowManager/Shell/shared/res/values/dimen.xml +++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml @@ -17,4 +17,23 @@ <resources> <dimen name="floating_dismiss_icon_size">32dp</dimen> <dimen name="floating_dismiss_background_size">96dp</dimen> + + <!-- Bubble drag zone dimensions --> + <dimen name="drag_zone_dismiss_fold">140dp</dimen> + <dimen name="drag_zone_dismiss_tablet">200dp</dimen> + <dimen name="drag_zone_bubble_fold">140dp</dimen> + <dimen name="drag_zone_bubble_tablet">200dp</dimen> + <dimen name="drag_zone_full_screen_width">512dp</dimen> + <dimen name="drag_zone_full_screen_height">44dp</dimen> + <dimen name="drag_zone_desktop_window_width">880dp</dimen> + <dimen name="drag_zone_desktop_window_height">300dp</dimen> + <dimen name="drag_zone_desktop_window_expanded_view_width">200dp</dimen> + <dimen name="drag_zone_desktop_window_expanded_view_height">350dp</dimen> + <dimen name="drag_zone_split_from_bubble_height">100dp</dimen> + <dimen name="drag_zone_split_from_bubble_width">60dp</dimen> + <dimen name="drag_zone_h_split_from_expanded_view_width">60dp</dimen> + <dimen name="drag_zone_v_split_from_expanded_view_width">200dp</dimen> + <dimen name="drag_zone_v_split_from_expanded_view_height_tablet">285dp</dimen> + <dimen name="drag_zone_v_split_from_expanded_view_height_fold_tall">150dp</dimen> + <dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen> </resources>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt index 35802c936361..909e9d2c4428 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt @@ -16,11 +16,15 @@ package com.android.wm.shell.shared.bubbles +import android.content.Context import android.graphics.Rect +import androidx.annotation.DimenRes +import com.android.wm.shell.shared.R import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode /** A class for creating drag zones for dragging bubble objects or dragging into bubbles. */ class DragZoneFactory( + private val context: Context, private val deviceConfig: DeviceConfig, private val splitScreenModeChecker: SplitScreenModeChecker, private val desktopWindowModeChecker: DesktopWindowModeChecker, @@ -29,23 +33,65 @@ class DragZoneFactory( private val windowBounds: Rect get() = deviceConfig.windowBounds - // TODO b/393172431: move these to xml - private val dismissDragZoneSize = if (deviceConfig.isSmallTablet) 140 else 200 - private val bubbleDragZoneTabletSize = 200 - private val bubbleDragZoneFoldableSize = 140 - private val fullScreenDragZoneWidth = 512 - private val fullScreenDragZoneHeight = 44 - private val desktopWindowDragZoneWidth = 880 - private val desktopWindowDragZoneHeight = 300 - private val desktopWindowFromExpandedViewDragZoneWidth = 200 - private val desktopWindowFromExpandedViewDragZoneHeight = 350 - private val splitFromBubbleDragZoneHeight = 100 - private val splitFromBubbleDragZoneWidth = 60 - private val hSplitFromExpandedViewDragZoneWidth = 60 - private val vSplitFromExpandedViewDragZoneWidth = 200 - private val vSplitFromExpandedViewDragZoneHeightTablet = 285 - private val vSplitFromExpandedViewDragZoneHeightFoldTall = 150 - private val vSplitFromExpandedViewDragZoneHeightFoldShort = 100 + private var dismissDragZoneSize = 0 + private var bubbleDragZoneTabletSize = 0 + private var bubbleDragZoneFoldableSize = 0 + private var fullScreenDragZoneWidth = 0 + private var fullScreenDragZoneHeight = 0 + private var desktopWindowDragZoneWidth = 0 + private var desktopWindowDragZoneHeight = 0 + private var desktopWindowFromExpandedViewDragZoneWidth = 0 + private var desktopWindowFromExpandedViewDragZoneHeight = 0 + private var splitFromBubbleDragZoneHeight = 0 + private var splitFromBubbleDragZoneWidth = 0 + private var hSplitFromExpandedViewDragZoneWidth = 0 + private var vSplitFromExpandedViewDragZoneWidth = 0 + private var vSplitFromExpandedViewDragZoneHeightTablet = 0 + private var vSplitFromExpandedViewDragZoneHeightFoldTall = 0 + private var vSplitFromExpandedViewDragZoneHeightFoldShort = 0 + + init { + onConfigurationUpdated() + } + + /** Updates all dimensions after a configuration change. */ + fun onConfigurationUpdated() { + dismissDragZoneSize = + if (deviceConfig.isSmallTablet) { + context.resolveDimension(R.dimen.drag_zone_dismiss_fold) + } else { + context.resolveDimension(R.dimen.drag_zone_dismiss_tablet) + } + bubbleDragZoneTabletSize = context.resolveDimension(R.dimen.drag_zone_bubble_tablet) + bubbleDragZoneFoldableSize = context.resolveDimension(R.dimen.drag_zone_bubble_fold) + fullScreenDragZoneWidth = context.resolveDimension(R.dimen.drag_zone_full_screen_width) + fullScreenDragZoneHeight = context.resolveDimension(R.dimen.drag_zone_full_screen_height) + desktopWindowDragZoneWidth = + context.resolveDimension(R.dimen.drag_zone_desktop_window_width) + desktopWindowDragZoneHeight = + context.resolveDimension(R.dimen.drag_zone_desktop_window_height) + desktopWindowFromExpandedViewDragZoneWidth = + context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_width) + desktopWindowFromExpandedViewDragZoneHeight = + context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_height) + splitFromBubbleDragZoneHeight = + context.resolveDimension(R.dimen.drag_zone_split_from_bubble_height) + splitFromBubbleDragZoneWidth = + context.resolveDimension(R.dimen.drag_zone_split_from_bubble_width) + hSplitFromExpandedViewDragZoneWidth = + context.resolveDimension(R.dimen.drag_zone_h_split_from_expanded_view_width) + vSplitFromExpandedViewDragZoneWidth = + context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_width) + vSplitFromExpandedViewDragZoneHeightTablet = + context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_tablet) + vSplitFromExpandedViewDragZoneHeightFoldTall = + context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_tall) + vSplitFromExpandedViewDragZoneHeightFoldShort = + context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_short) + } + + private fun Context.resolveDimension(@DimenRes dimension: Int) = + resources.getDimensionPixelSize(dimension) /** * Creates the list of drag zones for the dragged object. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index b2b99d648bf4..b6012378e4d4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -914,12 +914,15 @@ public abstract class WMShellModule { Context context, Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, InteractionJankMonitor interactionJankMonitor) { return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue() ? new SpringDragToDesktopTransitionHandler( - context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor) + context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, + interactionJankMonitor) : new DefaultDragToDesktopTransitionHandler( - context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor); + context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, + interactionJankMonitor); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 7491abd4248b..531304d6922a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -1659,11 +1659,16 @@ class DesktopTasksController( private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { logV("addWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { + + // If the wallpaper activity for this display already exists, let's reorder it to top. + val wallpaperActivityToken = desktopWallpaperActivityTokenProvider.getToken(displayId) + if (wallpaperActivityToken != null) { + wct.reorder(wallpaperActivityToken, /* onTop= */ true) + return + } + val intent = Intent(context, DesktopWallpaperActivity::class.java) - if ( - desktopWallpaperActivityTokenProvider.getToken(displayId) == null && - Flags.enablePerDisplayDesktopWallpaperActivity() - ) { + if (Flags.enablePerDisplayDesktopWallpaperActivity()) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt index a5ba6612bb1a..c10752d36bf9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt @@ -90,6 +90,11 @@ class DesktopUserRepositories( return desktopRepoByUserId.getOrCreate(profileId) } + fun getUserIdForProfile(profileId: Int): Int { + if (userIdToProfileIdsMap[userId]?.contains(profileId) == true) return userId + else return profileId + } + /** Dumps [DesktopRepository] for each user. */ fun dump(pw: PrintWriter, prefix: String) { desktopRepoByUserId.forEach { key, value -> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt index 2ac76f319d32..8194d3cab445 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt @@ -70,6 +70,7 @@ sealed class DragToDesktopTransitionHandler( private val context: Context, private val transitions: Transitions, private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + private val desktopUserRepositories: DesktopUserRepositories, protected val interactionJankMonitor: InteractionJankMonitor, protected val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { @@ -127,15 +128,18 @@ sealed class DragToDesktopTransitionHandler( pendingIntentCreatorBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED } - val taskUser = UserHandle.of(taskInfo.userId) + // If we are launching home for a profile of a user, just use the [userId] of that user + // instead of the [profileId] to create the context. + val userToLaunchWith = + UserHandle.of(desktopUserRepositories.getUserIdForProfile(taskInfo.userId)) val pendingIntent = PendingIntent.getActivityAsUser( - context.createContextAsUser(taskUser, /* flags= */ 0), + context.createContextAsUser(userToLaunchWith, /* flags= */ 0), /* requestCode= */ 0, launchHomeIntent, FLAG_MUTABLE or FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT or FILL_IN_COMPONENT, options.toBundle(), - taskUser, + userToLaunchWith, ) val wct = WindowContainerTransaction() // The app that is being dragged into desktop mode might cause new transitions, make this @@ -881,6 +885,7 @@ constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() @@ -890,6 +895,7 @@ constructor( context, transitions, taskDisplayAreaOrganizer, + desktopUserRepositories, interactionJankMonitor, transactionSupplier, ) { @@ -917,6 +923,7 @@ constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() @@ -926,6 +933,7 @@ constructor( context, transitions, taskDisplayAreaOrganizer, + desktopUserRepositories, interactionJankMonitor, transactionSupplier, ) { diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml index 02b2cec8dbdb..ae73dae99d6f 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml +++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml @@ -53,10 +53,12 @@ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard"/> <option name="teardown-command" value="settings delete system show_touches"/> <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" value="settings delete secure glanceable_hub_enabled"/> <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> </target_preparer> diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 5ac615eaff35..718bf322f6a9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -546,6 +546,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun showDesktopApps_allAppsInvisible_bringsToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskHidden(task1) @@ -580,7 +581,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) // Wallpaper is moved to front. - wct.assertPendingIntentAt(index = 0, desktopWallpaperIntent) + wct.assertReorderAt(index = 0, wallpaperToken) // Desk is activated. verify(desksOrganizer).activateDesk(wct, deskId) } @@ -782,6 +783,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskVisible(task1) @@ -824,7 +826,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) - fun showDesktopApps_someAppsInvisible_reordersAll_desktopWallpaperEnabled() { + fun showDesktopApps_someAppsInvisible_desktopWallpaperEnabled_reordersOnlyFreeformTasks() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskHidden(task1) @@ -841,6 +844,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() wct.assertReorderAt(index = 2, task2) } + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + fun showDesktopApps_someAppsInvisible_desktopWallpaperEnabled_reordersAll() { + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() + markTaskHidden(task1) + markTaskVisible(task2) + + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) + + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) + assertThat(wct.hierarchyOps).hasSize(3) + // Expect order to be from bottom: wallpaper intent, task1, task2 + wct.assertReorderAt(index = 0, wallpaperToken) + wct.assertReorderAt(index = 1, task1) + wct.assertReorderAt(index = 2, task2) + } + @Test @DisableFlags( Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, @@ -859,9 +880,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - fun showDesktopApps_noActiveTasks_addDesktopWallpaper_desktopWallpaperEnabled() { - whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull())) - .thenReturn(Binder()) + fun showDesktopApps_noActiveTasks_desktopWallpaperEnabled_addsDesktopWallpaper() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) val wct = @@ -870,10 +891,18 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - @DisableFlags( - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, - Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, - ) + @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + fun showDesktopApps_noActiveTasks_desktopWallpaperEnabled_reordersDesktopWallpaper() { + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) + + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) + wct.assertReorderAt(index = 0, wallpaperToken) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperDisabled() { taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY) @@ -898,6 +927,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperEnabled() { whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull())) .thenReturn(Binder()) + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY) val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY) @@ -990,6 +1020,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() /** TODO: b/362720497 - add multi-desk version when minimization is implemented. */ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun showDesktopApps_desktopWallpaperEnabled_dontReorderMinimizedTask() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val homeTask = setUpHomeTask() val freeformTask = setUpFreeformTask() val minimizedTask = setUpFreeformTask() @@ -1568,6 +1599,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun moveTaskToDesktop_desktopWallpaperEnabled_nonRunningTask_launchesInFreeform() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task = createTaskInfo(1) whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null) whenever(recentTasksController.findTaskInBackground(anyInt())).thenReturn(task) @@ -1801,6 +1833,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun moveRunningTaskToDesktop_otherFreeformTasksBroughtToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTask = setUpFreeformTask() val fullscreenTask = setUpFullscreenTask() markTaskHidden(freeformTask) @@ -1827,6 +1860,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags( Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, ) fun moveRunningTaskToDesktop_desktopWallpaperEnabled_multiDesksEnabled() { val freeformTask = setUpFreeformTask() @@ -1839,7 +1873,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ) val wct = getLatestEnterDesktopWct() - wct.assertPendingIntentAt(index = 0, desktopWallpaperIntent) + wct.assertReorderAt(index = 0, wallpaperToken) verify(desksOrganizer).moveTaskToDesk(wct, deskId = 0, fullscreenTask) verify(desksOrganizer).activateDesk(wct, deskId = 0) verify(desktopModeEnterExitTransitionListener) @@ -1966,6 +2000,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun moveRunningTaskToDesktop_desktopWallpaperEnabled_bringsTasksOverLimit_dontShowBackTask() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() } val newTask = setUpFullscreenTask() val homeTask = setUpHomeTask() @@ -2986,6 +3021,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_fullscreenTask_noTasks_enforceDesktop_freeformDisplay_returnFreeformWCT() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true) val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!! tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM @@ -3117,6 +3153,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_desktopWallpaperEnabled_freeformNotVisible_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTask1 = setUpFreeformTask() val freeformTask2 = createFreeformTask() @@ -3151,7 +3188,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_desktopWallpaperEnabled_noOtherTasks_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task = createFreeformTask() + val result = controller.handleRequest(Binder(), createTransition(task)) assertNotNull(result, "Should handle request") @@ -3179,6 +3218,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_dskWallpaperEnabled_freeformOnOtherDisplayOnly_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val taskDefaultDisplay = createFreeformTask(displayId = DEFAULT_DISPLAY) // Second display task createFreeformTask(displayId = SECOND_DISPLAY) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt index 83e48728c4f2..030bb1ace49d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt @@ -123,8 +123,26 @@ class DesktopUserRepositoriesTest : ShellTestCase() { assertThat(desktopRepository.userId).isEqualTo(PROFILE_ID_2) } + @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_HSUM) + fun getUserForProfile_flagEnabled_returnsUserIdForProfile() { + userRepositories.onUserChanged(USER_ID_2, mock()) + val profiles: MutableList<UserInfo> = + mutableListOf( + UserInfo(USER_ID_2, "User profile", 0), + UserInfo(PROFILE_ID_1, "Work profile", 0), + ) + userRepositories.onUserProfilesChanged(profiles) + + val userIdForProfile = userRepositories.getUserIdForProfile(PROFILE_ID_1) + + assertThat(userIdForProfile).isEqualTo(USER_ID_2) + } + private companion object { const val USER_ID_1 = 7 + const val USER_ID_2 = 8 + const val PROFILE_ID_1 = 4 const val PROFILE_ID_2 = 5 } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt index 25246d9984c3..1732875f1d57 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt @@ -70,6 +70,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor @Mock private lateinit var draggedTaskLeash: SurfaceControl @Mock private lateinit var homeTaskLeash: SurfaceControl + @Mock private lateinit var desktopUserRepositories: DesktopUserRepositories private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() } @@ -84,6 +85,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { context, transitions, taskDisplayAreaOrganizer, + desktopUserRepositories, mockInteractionJankMonitor, transactionSupplier, ) @@ -93,6 +95,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { context, transitions, taskDisplayAreaOrganizer, + desktopUserRepositories, mockInteractionJankMonitor, transactionSupplier, ) @@ -484,17 +487,22 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { val mergedFinishTransaction = mock<SurfaceControl.Transaction>() val finishCallback = mock<Transitions.TransitionFinishCallback>() val task = createTask() - val startTransition = startDrag( - springHandler, task, finishTransaction = playingFinishTransaction, homeChange = null) + val startTransition = + startDrag( + springHandler, + task, + finishTransaction = playingFinishTransaction, + homeChange = null, + ) springHandler.onTaskResizeAnimationListener = mock() springHandler.mergeAnimation( transition = mock<IBinder>(), info = - createTransitionInfo( - type = TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, - draggedTask = task, - ), + createTransitionInfo( + type = TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, + draggedTask = task, + ), startT = mergedStartTransaction, finishT = mergedFinishTransaction, mergeTarget = startTransition, @@ -723,7 +731,8 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { private fun createTransitionInfo( type: Int, draggedTask: RunningTaskInfo, - homeChange: TransitionInfo.Change? = createHomeChange()) = + homeChange: TransitionInfo.Change? = createHomeChange(), + ) = TransitionInfo(type, /* flags= */ 0).apply { homeChange?.let { addChange(it) } addChange( // Dragged Task. @@ -741,11 +750,12 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { ) } - private fun createHomeChange() = TransitionInfo.Change(mock(), homeTaskLeash).apply { - parent = null - taskInfo = TestRunningTaskInfoBuilder().setActivityType(ACTIVITY_TYPE_HOME).build() - flags = flags or FLAG_IS_WALLPAPER - } + private fun createHomeChange() = + TransitionInfo.Change(mock(), homeTaskLeash).apply { + parent = null + taskInfo = TestRunningTaskInfoBuilder().setActivityType(ACTIVITY_TYPE_HOME).build() + flags = flags or FLAG_IS_WALLPAPER + } private fun systemPropertiesKey(name: String) = "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt index 7cd46af9402b..fd22a84dee5d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt @@ -16,8 +16,10 @@ package com.android.wm.shell.shared.bubbles +import android.content.Context import android.graphics.Insets import android.graphics.Rect +import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.wm.shell.shared.bubbles.DragZoneFactory.DesktopWindowModeChecker @@ -34,6 +36,7 @@ private typealias DragZoneVerifier = (dragZone: DragZone) -> Unit /** Unit tests for [DragZoneFactory]. */ class DragZoneFactoryTest { + private val context = getApplicationContext<Context>() private lateinit var dragZoneFactory: DragZoneFactory private val tabletPortrait = DeviceConfig( @@ -57,7 +60,12 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubbleBar_tablet() { dragZoneFactory = - DragZoneFactory(tabletPortrait, splitScreenModeChecker, desktopWindowModeChecker) + DragZoneFactory( + context, + tabletPortrait, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.BubbleBar(BubbleBarLocation.LEFT)) val expectedZones: List<DragZoneVerifier> = @@ -73,7 +81,12 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubble_tablet_portrait() { dragZoneFactory = - DragZoneFactory(tabletPortrait, splitScreenModeChecker, desktopWindowModeChecker) + DragZoneFactory( + context, + tabletPortrait, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT)) val expectedZones: List<DragZoneVerifier> = @@ -92,7 +105,13 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubble_tablet_landscape() { - dragZoneFactory = DragZoneFactory(tabletLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + tabletLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT)) val expectedZones: List<DragZoneVerifier> = @@ -111,7 +130,13 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubble_foldable_portrait() { - dragZoneFactory = DragZoneFactory(foldablePortrait, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldablePortrait, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT)) val expectedZones: List<DragZoneVerifier> = @@ -129,7 +154,13 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubble_foldable_landscape() { - dragZoneFactory = DragZoneFactory(foldableLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldableLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT)) val expectedZones: List<DragZoneVerifier> = @@ -148,7 +179,12 @@ class DragZoneFactoryTest { @Test fun dragZonesForExpandedView_tablet_portrait() { dragZoneFactory = - DragZoneFactory(tabletPortrait, splitScreenModeChecker, desktopWindowModeChecker) + DragZoneFactory( + context, + tabletPortrait, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones( DraggedObject.ExpandedView(BubbleBarLocation.LEFT) @@ -169,9 +205,17 @@ class DragZoneFactoryTest { @Test fun dragZonesForExpandedView_tablet_landscape() { - dragZoneFactory = DragZoneFactory(tabletLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + tabletLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = - dragZoneFactory.createSortedDragZones(DraggedObject.ExpandedView(BubbleBarLocation.LEFT)) + dragZoneFactory.createSortedDragZones( + DraggedObject.ExpandedView(BubbleBarLocation.LEFT) + ) val expectedZones: List<DragZoneVerifier> = listOf( verifyInstance<DragZone.Dismiss>(), @@ -188,9 +232,17 @@ class DragZoneFactoryTest { @Test fun dragZonesForExpandedView_foldable_portrait() { - dragZoneFactory = DragZoneFactory(foldablePortrait, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldablePortrait, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = - dragZoneFactory.createSortedDragZones(DraggedObject.ExpandedView(BubbleBarLocation.LEFT)) + dragZoneFactory.createSortedDragZones( + DraggedObject.ExpandedView(BubbleBarLocation.LEFT) + ) val expectedZones: List<DragZoneVerifier> = listOf( verifyInstance<DragZone.Dismiss>(), @@ -206,9 +258,17 @@ class DragZoneFactoryTest { @Test fun dragZonesForExpandedView_foldable_landscape() { - dragZoneFactory = DragZoneFactory(foldableLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldableLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = - dragZoneFactory.createSortedDragZones(DraggedObject.ExpandedView(BubbleBarLocation.LEFT)) + dragZoneFactory.createSortedDragZones( + DraggedObject.ExpandedView(BubbleBarLocation.LEFT) + ) val expectedZones: List<DragZoneVerifier> = listOf( verifyInstance<DragZone.Dismiss>(), @@ -225,7 +285,13 @@ class DragZoneFactoryTest { @Test fun dragZonesForBubble_tablet_desktopModeDisabled() { isDesktopWindowModeSupported = false - dragZoneFactory = DragZoneFactory(foldableLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldableLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT)) assertThat(dragZones.filterIsInstance<DragZone.DesktopWindow>()).isEmpty() @@ -234,9 +300,17 @@ class DragZoneFactoryTest { @Test fun dragZonesForExpandedView_tablet_desktopModeDisabled() { isDesktopWindowModeSupported = false - dragZoneFactory = DragZoneFactory(foldableLandscape, splitScreenModeChecker, desktopWindowModeChecker) + dragZoneFactory = + DragZoneFactory( + context, + foldableLandscape, + splitScreenModeChecker, + desktopWindowModeChecker + ) val dragZones = - dragZoneFactory.createSortedDragZones(DraggedObject.ExpandedView(BubbleBarLocation.LEFT)) + dragZoneFactory.createSortedDragZones( + DraggedObject.ExpandedView(BubbleBarLocation.LEFT) + ) assertThat(dragZones.filterIsInstance<DragZone.DesktopWindow>()).isEmpty() } diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java index 93690d48cd04..b0fd925daec3 100644 --- a/packages/Shell/src/com/android/shell/BugreportPrefs.java +++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java @@ -23,25 +23,24 @@ import android.content.SharedPreferences; * Preferences related to bug reports. */ final class BugreportPrefs { - static final String PREFS_BUGREPORT = "bugreports"; - - private static final String KEY_WARNING_STATE = "warning-state"; - - static final int STATE_UNKNOWN = 0; - // Shows the warning dialog. - static final int STATE_SHOW = 1; - // Skips the warning dialog. - static final int STATE_HIDE = 2; static int getWarningState(Context context, int def) { - final SharedPreferences prefs = context.getSharedPreferences( - PREFS_BUGREPORT, Context.MODE_PRIVATE); - return prefs.getInt(KEY_WARNING_STATE, def); + String prefsBugreport = context.getResources().getString( + com.android.internal.R.string.prefs_bugreport); + String keyWarningState = context.getResources().getString( + com.android.internal.R.string.key_warning_state); + final SharedPreferences prefs = context.getSharedPreferences(prefsBugreport, + Context.MODE_PRIVATE); + return prefs.getInt(keyWarningState, def); } static void setWarningState(Context context, int value) { - final SharedPreferences prefs = context.getSharedPreferences( - PREFS_BUGREPORT, Context.MODE_PRIVATE); - prefs.edit().putInt(KEY_WARNING_STATE, value).apply(); + String prefsBugreport = context.getResources().getString( + com.android.internal.R.string.prefs_bugreport); + String keyWarningState = context.getResources().getString( + com.android.internal.R.string.key_warning_state); + final SharedPreferences prefs = context.getSharedPreferences(prefsBugreport, + Context.MODE_PRIVATE); + prefs.edit().putInt(keyWarningState, value).apply(); } } diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 61f49db07abc..fb0678fedb56 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -21,8 +21,6 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; -import static com.android.shell.BugreportPrefs.STATE_HIDE; -import static com.android.shell.BugreportPrefs.STATE_UNKNOWN; import static com.android.shell.BugreportPrefs.getWarningState; import static com.android.shell.flags.Flags.handleBugreportsForWear; @@ -1347,7 +1345,11 @@ public class BugreportProgressService extends Service { } private boolean hasUserDecidedNotToGetWarningMessage() { - return getWarningState(mContext, STATE_UNKNOWN) == STATE_HIDE; + int bugreportStateUnknown = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_unknown); + int bugreportStateHide = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_hide); + return getWarningState(mContext, bugreportStateUnknown) == bugreportStateHide; } private void maybeShowWarningMessageAndCloseNotification(int id) { diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java index a44e23603f52..0e835f91aca6 100644 --- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java +++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java @@ -16,9 +16,6 @@ package com.android.shell; -import static com.android.shell.BugreportPrefs.STATE_HIDE; -import static com.android.shell.BugreportPrefs.STATE_SHOW; -import static com.android.shell.BugreportPrefs.STATE_UNKNOWN; import static com.android.shell.BugreportPrefs.getWarningState; import static com.android.shell.BugreportPrefs.setWarningState; import static com.android.shell.BugreportProgressService.sendShareIntent; @@ -69,12 +66,19 @@ public class BugreportWarningActivity extends AlertActivity mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox); - final int state = getWarningState(this, STATE_UNKNOWN); + int bugreportStateUnknown = getResources().getInteger( + com.android.internal.R.integer.bugreport_state_unknown); + int bugreportStateHide = getResources().getInteger( + com.android.internal.R.integer.bugreport_state_hide); + int bugreportStateShow = getResources().getInteger( + com.android.internal.R.integer.bugreport_state_show); + + final int state = getWarningState(this, bugreportStateUnknown); final boolean checked; if (Build.IS_USER) { - checked = state == STATE_HIDE; // Only checks if specifically set to. + checked = state == bugreportStateHide; // Only checks if specifically set to. } else { - checked = state != STATE_SHOW; // Checks by default. + checked = state != bugreportStateShow; // Checks by default. } mConfirmRepeat.setChecked(checked); @@ -83,9 +87,14 @@ public class BugreportWarningActivity extends AlertActivity @Override public void onClick(DialogInterface dialog, int which) { + int bugreportStateHide = getResources().getInteger( + com.android.internal.R.integer.bugreport_state_hide); + int bugreportStateShow = getResources().getInteger( + com.android.internal.R.integer.bugreport_state_show); if (which == AlertDialog.BUTTON_POSITIVE) { // Remember confirm state, and launch target - setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW); + setWarningState(this, mConfirmRepeat.isChecked() ? bugreportStateHide + : bugreportStateShow); if (mSendIntent != null) { sendShareIntent(this, mSendIntent); } diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index 7bda2ea790b0..2d6abe6cdc93 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -19,10 +19,6 @@ package com.android.shell; import static android.test.MoreAsserts.assertContainsRegex; import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME; -import static com.android.shell.BugreportPrefs.PREFS_BUGREPORT; -import static com.android.shell.BugreportPrefs.STATE_HIDE; -import static com.android.shell.BugreportPrefs.STATE_SHOW; -import static com.android.shell.BugreportPrefs.STATE_UNKNOWN; import static com.android.shell.BugreportPrefs.getWarningState; import static com.android.shell.BugreportPrefs.setWarningState; import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_REQUESTED; @@ -201,8 +197,9 @@ public class BugreportReceiverTest { return null; }).when(mMockIDumpstate).startBugreport(anyInt(), any(), any(), any(), anyInt(), anyInt(), any(), anyBoolean(), anyBoolean()); - - setWarningState(mContext, STATE_HIDE); + int bugreportStateHide = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_hide); + setWarningState(mContext, bugreportStateHide); mUiBot.turnScreenOn(); } @@ -469,22 +466,31 @@ public class BugreportReceiverTest { @Test public void testBugreportFinished_withWarningUnknownState() throws Exception { - bugreportFinishedWithWarningTest(STATE_UNKNOWN); + int bugreportStateUnknown = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_unknown); + bugreportFinishedWithWarningTest(bugreportStateUnknown); } @Test public void testBugreportFinished_withWarningShowAgain() throws Exception { - bugreportFinishedWithWarningTest(STATE_SHOW); + int bugreportStateShow = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_show); + bugreportFinishedWithWarningTest(bugreportStateShow); } private void bugreportFinishedWithWarningTest(Integer propertyState) throws Exception { + int bugreportStateUnknown = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_unknown); + int bugreportStateHide = mContext.getResources().getInteger( + com.android.internal.R.integer.bugreport_state_hide); if (propertyState == null) { // Clear properties - mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE) - .edit().clear().commit(); + mContext.getSharedPreferences( + mContext.getResources().getString(com.android.internal.R.string.prefs_bugreport) + , Context.MODE_PRIVATE).edit().clear().commit(); // Confidence check... - assertEquals("Did not reset properties", STATE_UNKNOWN, - getWarningState(mContext, STATE_UNKNOWN)); + assertEquals("Did not reset properties", bugreportStateUnknown, + getWarningState(mContext, bugreportStateUnknown)); } else { setWarningState(mContext, propertyState); } @@ -501,7 +507,8 @@ public class BugreportReceiverTest { // TODO: get ok and dontShowAgain from the dialog reference above UiObject dontShowAgain = mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat)); - final boolean firstTime = propertyState == null || propertyState == STATE_UNKNOWN; + final boolean firstTime = + propertyState == null || propertyState == bugreportStateUnknown; if (firstTime) { if (Build.IS_USER) { assertFalse("Checkbox should NOT be checked by default on user builds", @@ -524,8 +531,8 @@ public class BugreportReceiverTest { assertActionSendMultiple(extras); // Make sure it's hidden now. - int newState = getWarningState(mContext, STATE_UNKNOWN); - assertEquals("Didn't change state", STATE_HIDE, newState); + int newState = getWarningState(mContext, bugreportStateUnknown); + assertEquals("Didn't change state", bugreportStateHide, newState); } @Test diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index 2e5b5b56c982..aad1276d76e5 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -113,8 +113,8 @@ class DefaultClockProvider( companion object { // 750ms @ 120hz -> 90 frames of animation - // In practice, 45 looks good enough - const val NUM_CLOCK_FONT_ANIMATION_STEPS = 45 + // In practice, 30 looks good enough and limits our memory usage + const val NUM_CLOCK_FONT_ANIMATION_STEPS = 30 val FLEX_TYPEFACE by lazy { // TODO(b/364680873): Move constant to config_clockFontFamily when shipping diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt index e13f3f12c55a..7e93f5a8c9a8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt @@ -20,19 +20,26 @@ import android.os.PowerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization +import android.provider.Settings import android.service.dream.dreamManager import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR import com.android.systemui.Flags.FLAG_SCENE_CONTAINER +import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.SysuiTestCase +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository @@ -56,11 +63,14 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -93,7 +103,10 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT @JvmStatic @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { - return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + return FlagsParameterization.allCombinationsOf( + FLAG_COMMUNAL_SCENE_KTF_REFACTOR, + FLAG_GLANCEABLE_HUB_V2, + ) } } @@ -107,6 +120,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT // Transition to DOZING and set the power interactor asleep. kosmos.powerInteractor.setAsleepForTest() + kosmos.setCommunalV2ConfigEnabled(true) runBlocking { kosmos.transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, @@ -160,7 +174,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT @Test @EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR) - @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR, FLAG_GLANCEABLE_HUB_V2) fun testTransitionToLockscreen_onWake_canDream_glanceableHubAvailable() = kosmos.runTest { whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) @@ -179,7 +193,17 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT fun testTransitionToLockscreen_onWake_canDream_ktfRefactor() = kosmos.runTest { setCommunalAvailable(true) - whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + if (glanceableHubV2()) { + val user = fakeUserRepository.asMainUser() + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1, + user.id, + ) + batteryRepository.fake.setDevicePluggedIn(true) + } else { + whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + } clearInvocations(fakeCommunalSceneRepository) powerInteractor.setAwakeForTest() @@ -240,7 +264,17 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT fun testTransitionToGlanceableHub_onWakeup_ifAvailable() = kosmos.runTest { setCommunalAvailable(true) - whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + if (glanceableHubV2()) { + val user = fakeUserRepository.asMainUser() + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1, + user.id, + ) + batteryRepository.fake.setDevicePluggedIn(true) + } else { + whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + } // Device turns on. powerInteractor.setAwakeForTest() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt index 8e1068226431..5882cff74eb6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt @@ -19,14 +19,20 @@ package com.android.systemui.keyguard.domain.interactor import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization +import android.provider.Settings import android.service.dream.dreamManager import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 +import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -46,6 +52,8 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy @@ -66,7 +74,10 @@ class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : Sysu @JvmStatic @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { - return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + return FlagsParameterization.allCombinationsOf( + FLAG_COMMUNAL_SCENE_KTF_REFACTOR, + FLAG_GLANCEABLE_HUB_V2, + ) .andSceneContainer() } } @@ -101,6 +112,7 @@ class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : Sysu ) reset(kosmos.transitionRepository) kosmos.setCommunalAvailable(true) + kosmos.setCommunalV2ConfigEnabled(true) } kosmos.underTest.start() } @@ -202,7 +214,17 @@ class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : Sysu reset(transitionRepository) setCommunalAvailable(true) - whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + if (glanceableHubV2()) { + val user = fakeUserRepository.asMainUser() + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1, + user.id, + ) + batteryRepository.fake.setDevicePluggedIn(true) + } else { + whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + } // Device wakes up. powerInteractor.setAwakeForTest() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt index 264eda5a07eb..668c606677ba 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.settings.userFileManager import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository @@ -76,11 +77,11 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { @Test fun setLargeTilesSpecs_inSharedPreferences() { val setA = setOf("tileA", "tileB") - underTest.setLargeTilesSpecs(setA.toTileSpecs()) + underTest.writeLargeTileSpecs(setA.toTileSpecs()) assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setA) val setB = setOf("tileA", "tileB") - underTest.setLargeTilesSpecs(setB.toTileSpecs()) + underTest.writeLargeTileSpecs(setB.toTileSpecs()) assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setB) } @@ -92,12 +93,12 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) val setA = setOf("tileA", "tileB") - underTest.setLargeTilesSpecs(setA.toTileSpecs()) + underTest.writeLargeTileSpecs(setA.toTileSpecs()) assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setA) fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) val setB = setOf("tileA", "tileB") - underTest.setLargeTilesSpecs(setB.toTileSpecs()) + underTest.writeLargeTileSpecs(setB.toTileSpecs()) assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setB) fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) @@ -106,7 +107,7 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { } @Test - fun setInitialTilesFromSettings_noLargeTiles_tilesSet() = + fun setUpgradePathFromSettings_noLargeTiles_tilesSet() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -117,14 +118,17 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { assertThat(getSharedPreferences().contains(LARGE_TILES_SPECS_KEY)).isFalse() - underTest.setInitialLargeTilesSpecs(tiles, PRIMARY_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(tiles), + PRIMARY_USER_ID, + ) assertThat(largeTiles).isEqualTo(tiles) } } @Test - fun setInitialTilesFromSettings_alreadyLargeTiles_tilesNotSet() = + fun setUpgradePathFromSettings_alreadyLargeTiles_tilesNotSet() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -133,14 +137,17 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) setLargeTilesSpecsInSharedPreferences(setOf("tileC")) - underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(setOf("tileA").toTileSpecs()), + ANOTHER_USER_ID, + ) assertThat(largeTiles).isEqualTo(setOf("tileC").toTileSpecs()) } } @Test - fun setInitialTilesFromSettings_emptyLargeTiles_tilesNotSet() = + fun setUpgradePathFromSettings_emptyLargeTiles_tilesNotSet() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -149,14 +156,17 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) setLargeTilesSpecsInSharedPreferences(emptySet()) - underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(setOf("tileA").toTileSpecs()), + ANOTHER_USER_ID, + ) assertThat(largeTiles).isEmpty() } } @Test - fun setInitialTilesFromSettings_nonCurrentUser_tilesSetForCorrectUser() = + fun setUpgradePathFromSettings_nonCurrentUser_tilesSetForCorrectUser() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -164,7 +174,10 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { fakeUserRepository.setUserInfos(USERS) fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) - underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(setOf("tileA").toTileSpecs()), + ANOTHER_USER_ID, + ) assertThat(largeTiles).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles) @@ -174,7 +187,7 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { } @Test - fun setInitialTiles_afterDefaultRead_noSetOnRepository_initialTilesCorrect() = + fun setUpgradePath_afterDefaultRead_noSetOnRepository_initialTilesCorrect() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -186,14 +199,17 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { assertThat(currentLargeTiles).isNotEmpty() val tiles = setOf("tileA", "tileB") - underTest.setInitialLargeTilesSpecs(tiles.toTileSpecs(), PRIMARY_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(tiles.toTileSpecs()), + PRIMARY_USER_ID, + ) assertThat(largeTiles).isEqualTo(tiles.toTileSpecs()) } } @Test - fun setInitialTiles_afterDefaultRead_largeTilesSetOnRepository_initialTilesCorrect() = + fun setUpgradePath_afterDefaultRead_largeTilesSetOnRepository_initialTilesCorrect() = with(kosmos) { testScope.runTest { val largeTiles by collectLastValue(underTest.largeTilesSpecs) @@ -204,15 +220,80 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { assertThat(currentLargeTiles).isNotEmpty() - underTest.setLargeTilesSpecs(setOf(TileSpec.create("tileC"))) + underTest.writeLargeTileSpecs(setOf(TileSpec.create("tileC"))) val tiles = setOf("tileA", "tileB") - underTest.setInitialLargeTilesSpecs(tiles.toTileSpecs(), PRIMARY_USER_ID) + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.ReadFromSettings(tiles.toTileSpecs()), + PRIMARY_USER_ID, + ) assertThat(largeTiles).isEqualTo(setOf(TileSpec.create("tileC"))) } } + @Test + fun setTilesRestored_noLargeTiles_tilesSet() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + val tiles = setOf("tileA", "tileB").toTileSpecs() + + assertThat(getSharedPreferences().contains(LARGE_TILES_SPECS_KEY)).isFalse() + + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.RestoreFromBackup(tiles), + PRIMARY_USER_ID, + ) + + assertThat(largeTiles).isEqualTo(tiles) + } + } + + @Test + fun setDefaultTilesInitial_defaultSetLarge() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.DefaultSet, + PRIMARY_USER_ID, + ) + + assertThat(largeTiles).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles) + } + } + + @Test + fun setTilesRestored_afterDefaultSet_tilesSet() = + with(kosmos) { + testScope.runTest { + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.DefaultSet, + PRIMARY_USER_ID, + ) + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + val tiles = setOf("tileA", "tileB").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTiles( + TilesUpgradePath.RestoreFromBackup(tiles), + PRIMARY_USER_ID, + ) + + assertThat(largeTiles).isEqualTo(tiles) + } + } + private fun getSharedPreferences(): SharedPreferences = with(kosmos) { return userFileManager.getSharedPreferences( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/LargeTilesUpgradePathsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/LargeTilesUpgradePathsTest.kt new file mode 100644 index 000000000000..f3c1f0c9dba8 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/LargeTilesUpgradePathsTest.kt @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2025 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.systemui.qs.panels.domain + +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.content.res.mainResources +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.backup.BackupHelper.Companion.ACTION_RESTORE_FINISHED +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.common.shared.model.PackageChangeModel.Empty.packageName +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository +import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository +import com.android.systemui.qs.panels.domain.interactor.qsPreferencesInteractor +import com.android.systemui.qs.pipeline.data.repository.DefaultTilesQSHostRepository +import com.android.systemui.qs.pipeline.data.repository.defaultTilesRepository +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath +import com.android.systemui.settings.userFileManager +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.userRepository +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class LargeTilesUpgradePathsTest : SysuiTestCase() { + + private val kosmos = + testKosmos().apply { defaultTilesRepository = DefaultTilesQSHostRepository(mainResources) } + + private val defaultTiles = kosmos.defaultTilesRepository.defaultTiles.toSet() + + private val underTest = kosmos.qsPreferencesInteractor + + private val Kosmos.userId + get() = userRepository.getSelectedUserInfo().id + + private val Kosmos.intent + get() = + Intent(ACTION_RESTORE_FINISHED).apply { + `package` = packageName + putExtra(Intent.EXTRA_USER_ID, kosmos.userId) + flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY + } + + /** + * This test corresponds to the case of a fresh start. + * + * The resulting large tiles are the default set of large tiles. + */ + @Test + fun defaultTiles_noDataInSharedPreferences_defaultLargeTiles() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + underTest.setInitialOrUpgradeLargeTilesSpecs(TilesUpgradePath.DefaultSet, userId) + + assertThat(largeTiles).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles) + } + + /** + * This test corresponds to a user that upgraded in place from a build that didn't support large + * tiles to one that does. The current tiles of the user are read from settings. + * + * The resulting large tiles are those that were read from Settings. + */ + @Test + fun upgradeInPlace_noDataInSharedPreferences_allLargeTiles() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val tiles = setOf("a", "b", "c").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(tiles), + userId, + ) + + assertThat(largeTiles).isEqualTo(tiles) + } + + /** + * This test corresponds to a fresh start, and then the user restarts the device, without ever + * having modified the set of large tiles. + * + * The resulting large tiles are the default large tiles that were set on the fresh start + */ + @Test + fun defaultSet_restartDevice_largeTilesDontChange() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + underTest.setInitialOrUpgradeLargeTilesSpecs(TilesUpgradePath.DefaultSet, userId) + + // User restarts the device, this will send a read from settings with the default + // set of tiles + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(defaultTiles), + userId, + ) + + assertThat(largeTiles).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles) + } + + /** + * This test corresponds to a fresh start, following the user changing the sizes of some tiles. + * After that, the user restarts the device. + * + * The resulting set of large tiles are those that the user determined before restarting the + * device. + */ + @Test + fun defaultSet_someSizeChanges_restart_correctSet() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + underTest.setInitialOrUpgradeLargeTilesSpecs(TilesUpgradePath.DefaultSet, userId) + + underTest.setLargeTilesSpecs(largeTiles!! + setOf("a", "b").toTileSpecs()) + val largeTilesBeforeRestart = largeTiles!! + + // Restart + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(defaultTiles), + userId, + ) + assertThat(largeTiles).isEqualTo(largeTilesBeforeRestart) + } + + /** + * This test corresponds to a user that upgraded, and after that performed some size changes. + * After that, the user restarts the device. + * + * The resulting set of large tiles are those that the user determined before restarting the + * device. + */ + @Test + fun readFromSettings_changeSizes_restart_newLargeSet() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val readTiles = setOf("a", "b", "c").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(readTiles), + userId, + ) + underTest.setLargeTilesSpecs(emptySet()) + + assertThat(largeTiles).isEmpty() + + // Restart + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(readTiles), + userId, + ) + assertThat(largeTiles).isEmpty() + } + + /** + * This test corresponds to a user that upgraded from a build that didn't support tile sizes to + * one that does, via restore from backup. Note that there's no file in SharedPreferences to + * restore. + * + * The resulting set of large tiles are those that were restored from the backup. + */ + @Test + fun restoreFromBackup_noDataInSharedPreferences_allLargeTiles() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val tiles = setOf("a", "b", "c").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.RestoreFromBackup(tiles), + userId, + ) + + assertThat(largeTiles).isEqualTo(tiles) + } + + /** + * This test corresponds to a user that upgraded from a build that didn't support tile sizes to + * one that does, via restore from backup. However, the restore happens after SystemUI's + * initialization has set the tiles to default. Note that there's no file in SharedPreferences + * to restore. + * + * The resulting set of large tiles are those that were restored from the backup. + */ + @Test + fun restoreFromBackup_afterDefault_noDataInSharedPreferences_allLargeTiles() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + underTest.setInitialOrUpgradeLargeTilesSpecs(TilesUpgradePath.DefaultSet, userId) + + val tiles = setOf("a", "b", "c").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.RestoreFromBackup(tiles), + userId, + ) + + assertThat(largeTiles).isEqualTo(tiles) + } + + /** + * This test corresponds to a user that restored from a build that supported different sizes + * tiles. First the list of tiles is restored in Settings and then a file containing some large + * tiles overrides the current shared preferences file + * + * The resulting set of large tiles are those that were restored from the shared preferences + * backup (and not the full list). + */ + @Test + fun restoreFromBackup_thenRestoreOfSharedPrefs_sharedPrefsAreLarge() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val tiles = setOf("a", "b", "c").toTileSpecs() + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.RestoreFromBackup(tiles), + userId, + ) + + val tilesFromBackupOfSharedPrefs = setOf("a") + setLargeTilesSpecsInSharedPreferences(tilesFromBackupOfSharedPrefs) + broadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent) + + assertThat(largeTiles).isEqualTo(tilesFromBackupOfSharedPrefs.toTileSpecs()) + } + + /** + * This test corresponds to a user that restored from a build that supported different sizes + * tiles. However, this restore of settings happened after SystemUI's restore of the SharedPrefs + * containing the user's previous selections to large/small tiles. + * + * The resulting set of large tiles are those that were restored from the shared preferences + * backup (and not the full list). + */ + @Test + fun restoreFromBackup_afterRestoreOfSharedPrefs_sharedPrefsAreLarge() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val tiles = setOf("a", "b", "c").toTileSpecs() + val tilesFromBackupOfSharedPrefs = setOf("a") + + setLargeTilesSpecsInSharedPreferences(tilesFromBackupOfSharedPrefs) + broadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent) + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.RestoreFromBackup(tiles), + userId, + ) + + assertThat(largeTiles).isEqualTo(tilesFromBackupOfSharedPrefs.toTileSpecs()) + } + + /** + * This test corresponds to a user that upgraded from a build that didn't support tile sizes to + * one that does, via restore from backup. After that, the user modifies the size of some tiles + * and then restarts the device. + * + * The resulting set of large tiles are those after the user modifications. + */ + @Test + fun restoreFromBackup_changeSizes_restart_newLargeSet() = + kosmos.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + val readTiles = setOf("a", "b", "c").toTileSpecs() + + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.RestoreFromBackup(readTiles), + userId, + ) + underTest.setLargeTilesSpecs(emptySet()) + + assertThat(largeTiles).isEmpty() + + // Restart + underTest.setInitialOrUpgradeLargeTilesSpecs( + TilesUpgradePath.ReadFromSettings(readTiles), + userId, + ) + assertThat(largeTiles).isEmpty() + } + + private companion object { + private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs" + + private fun Kosmos.getSharedPreferences(): SharedPreferences = + userFileManager.getSharedPreferences( + QSPreferencesRepository.FILE_NAME, + Context.MODE_PRIVATE, + userRepository.getSelectedUserInfo().id, + ) + + private fun Kosmos.setLargeTilesSpecsInSharedPreferences(specs: Set<String>) { + getSharedPreferences().edit().putStringSet(LARGE_TILES_SPECS_KEY, specs).apply() + } + + private fun Kosmos.getLargeTilesSpecsFromSharedPreferences(): Set<String> { + return getSharedPreferences().getStringSet(LARGE_TILES_SPECS_KEY, emptySet())!! + } + + private fun Set<String>.toTileSpecs(): Set<TileSpec> { + return map { TileSpec.create(it) }.toSet() + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt index 79acfdaa415b..9838bcb86684 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt @@ -66,7 +66,7 @@ class IconTilesInteractorTest : SysuiTestCase() { runCurrent() // Resize it to large - qsPreferencesRepository.setLargeTilesSpecs(setOf(spec)) + qsPreferencesRepository.writeLargeTileSpecs(setOf(spec)) runCurrent() // Assert that the new tile was added to the large tiles set diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt index 4b8cd3742bff..d9b3926fa215 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt @@ -24,6 +24,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.res.R import com.android.systemui.retail.data.repository.FakeRetailModeRepository @@ -242,9 +243,12 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { storeTilesForUser(startingTiles, userId) val tiles by collectLastValue(underTest.tilesSpecs(userId)) - val tilesRead by collectLastValue(underTest.tilesReadFromSetting.consumeAsFlow()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) - assertThat(tilesRead).isEqualTo(startingTiles.toTileSpecs().toSet() to userId) + assertThat(tilesRead) + .isEqualTo( + TilesUpgradePath.ReadFromSettings(startingTiles.toTileSpecs().toSet()) to userId + ) } @Test @@ -258,13 +262,13 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { val tiles10 by collectLastValue(underTest.tilesSpecs(10)) val tiles11 by collectLastValue(underTest.tilesSpecs(11)) - val tilesRead by collectValues(underTest.tilesReadFromSetting.consumeAsFlow()) + val tilesRead by collectValues(underTest.tilesUpgradePath.consumeAsFlow()) assertThat(tilesRead).hasSize(2) assertThat(tilesRead) .containsExactly( - startingTiles10.toTileSpecs().toSet() to 10, - startingTiles11.toTileSpecs().toSet() to 11, + TilesUpgradePath.ReadFromSettings(startingTiles10.toTileSpecs().toSet()) to 10, + TilesUpgradePath.ReadFromSettings(startingTiles11.toTileSpecs().toSet()) to 11, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt index 1945f750efaf..29bd18d3f3a0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt @@ -7,8 +7,8 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData -import com.android.systemui.qs.pipeline.data.repository.UserTileSpecRepositoryTest.Companion.toTilesSet import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat @@ -352,11 +352,11 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { @Test fun noSettingsStored_noTilesReadFromSettings() = testScope.runTest { - val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) val tiles by collectLastValue(underTest.tiles()) assertThat(tiles).isEqualTo(getDefaultTileSpecs()) - assertThat(tilesRead).isEqualTo(null) + assertThat(tilesRead).isEqualTo(TilesUpgradePath.DefaultSet) } @Test @@ -365,19 +365,20 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { val storedTiles = "a,b" storeTiles(storedTiles) val tiles by collectLastValue(underTest.tiles()) - val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) - assertThat(tilesRead).isEqualTo(storedTiles.toTilesSet()) + assertThat(tilesRead) + .isEqualTo(TilesUpgradePath.ReadFromSettings(storedTiles.toTilesSet())) } @Test fun noSettingsStored_tilesChanged_tilesReadFromSettingsNotChanged() = testScope.runTest { - val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) val tiles by collectLastValue(underTest.tiles()) underTest.addTile(TileSpec.create("a")) - assertThat(tilesRead).isEqualTo(null) + assertThat(tilesRead).isEqualTo(TilesUpgradePath.DefaultSet) } @Test @@ -386,10 +387,34 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { val storedTiles = "a,b" storeTiles(storedTiles) val tiles by collectLastValue(underTest.tiles()) - val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) underTest.addTile(TileSpec.create("c")) - assertThat(tilesRead).isEqualTo(storedTiles.toTilesSet()) + assertThat(tilesRead) + .isEqualTo(TilesUpgradePath.ReadFromSettings(storedTiles.toTilesSet())) + } + + @Test + fun tilesRestoredFromBackup() = + testScope.runTest { + val specsBeforeRestore = "a,b,c,d,e" + val restoredSpecs = "a,c,d,f" + val autoAddedBeforeRestore = "b,d" + val restoredAutoAdded = "d,e" + + storeTiles(specsBeforeRestore) + val tiles by collectLastValue(underTest.tiles()) + val tilesRead by collectLastValue(underTest.tilesUpgradePath.consumeAsFlow()) + runCurrent() + + val restoreData = + RestoreData(restoredSpecs.toTileSpecs(), restoredAutoAdded.toTilesSet(), USER) + underTest.reconcileRestore(restoreData, autoAddedBeforeRestore.toTilesSet()) + runCurrent() + + val expected = "a,b,c,d,f" + assertThat(tilesRead) + .isEqualTo(TilesUpgradePath.RestoreFromBackup(expected.toTilesSet())) } private fun getDefaultTileSpecs(): List<TileSpec> { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt index 403ac3288128..20637cd4af33 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt @@ -293,7 +293,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) @Test - fun chipsLegacy_twoTimerChips_isSmallPortrait_andChipsModernizationDisabled_bothSquished() = + fun chipsLegacy_twoTimerChips_isSmallPortrait_bothSquished() = kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording addOngoingCallState(key = "call") @@ -307,6 +307,22 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } + @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @Test + fun chips_twoTimerChips_isSmallPortrait_bothSquished() = + kosmos.runTest { + screenRecordState.value = ScreenRecordModel.Recording + addOngoingCallState(key = "call") + + val latest by collectLastValue(underTest.chips) + + // Squished chips are icon only + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + assertThat(latest!!.active[1]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + } + @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) @Test fun chipsLegacy_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() = @@ -324,6 +340,23 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } + @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @Test + fun chips_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() = + kosmos.runTest { + screenRecordState.value = ScreenRecordModel.Starting(millisUntilStarted = 2000) + addOngoingCallState(key = "call") + + val latest by collectLastValue(underTest.chips) + + // The screen record countdown isn't squished to icon-only + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.Countdown::class.java) + // But the call chip *is* squished + assertThat(latest!!.active[1]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + } + @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) @Test fun chipsLegacy_numberOfChipsChanges_chipsGetSquishedAndUnsquished() = @@ -360,6 +393,38 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Inactive::class.java) } + @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @Test + fun chips_numberOfChipsChanges_chipsGetSquishedAndUnsquished() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + + // WHEN there's only one chip + screenRecordState.value = ScreenRecordModel.Recording + removeOngoingCallState(key = "call") + + // The screen record isn't squished because it's the only one + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + + // WHEN there's 2 chips + addOngoingCallState(key = "call") + + // THEN they both become squished + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + // But the call chip *is* squished + assertThat(latest!!.active[1]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + + // WHEN we go back down to 1 chip + screenRecordState.value = ScreenRecordModel.DoingNothing + + // THEN the remaining chip unsquishes + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + } + @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) @Test fun chipsLegacy_twoChips_isLandscape_notSquished() = @@ -383,6 +448,29 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } + @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @Test + fun chips_twoChips_isLandscape_notSquished() = + kosmos.runTest { + screenRecordState.value = ScreenRecordModel.Recording + addOngoingCallState(key = "call") + + // WHEN we're in landscape + val config = + Configuration(kosmos.mainResources.configuration).apply { + orientation = Configuration.ORIENTATION_LANDSCAPE + } + kosmos.fakeConfigurationRepository.onConfigurationChange(config) + + val latest by collectLastValue(underTest.chips) + + // THEN the chips aren't squished (squished chips would be icon only) + assertThat(latest!!.active[0]) + .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + assertThat(latest!!.active[1]) + .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + } + @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) @Test fun chipsLegacy_twoChips_isLargeScreen_notSquished() = @@ -402,16 +490,19 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @Test @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) - fun chips_twoChips_chipsModernizationEnabled_notSquished() = + @Test + fun chips_twoChips_isLargeScreen_notSquished() = kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording addOngoingCallState(key = "call") + // WHEN we're on a large screen + kosmos.displayStateRepository.setIsLargeScreen(true) + val latest by collectLastValue(underTest.chips) - // Squished chips would be icon only + // THEN the chips aren't squished (squished chips would be icon only) assertThat(latest!!.active[0]) .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) assertThat(latest!!.active[1]) diff --git a/packages/SystemUI/res/drawable/clipboard_minimized_background_inset.xml b/packages/SystemUI/res/drawable/clipboard_minimized_background_inset.xml new file mode 100644 index 000000000000..1ba637f379c1 --- /dev/null +++ b/packages/SystemUI/res/drawable/clipboard_minimized_background_inset.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 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. + --> +<inset + xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/clipboard_minimized_background" + android:inset="4dp"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml index 448b3e7d5ea0..915563b1ae20 100644 --- a/packages/SystemUI/res/layout/clipboard_overlay.xml +++ b/packages/SystemUI/res/layout/clipboard_overlay.xml @@ -171,12 +171,12 @@ android:layout_height="wrap_content" android:visibility="gone" android:elevation="7dp" - android:padding="8dp" + android:padding="12dp" app:layout_constraintBottom_toTopOf="@id/indication_container" app:layout_constraintStart_toStartOf="parent" - android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" - android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom" - android:background="@drawable/clipboard_minimized_background"> + android:layout_marginStart="4dp" + android:layout_marginBottom="2dp" + android:background="@drawable/clipboard_minimized_background_inset"> <ImageView android:src="@drawable/ic_content_paste" android:tint="?attr/overlayButtonTextColor" diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 67f620f6fc54..8ad99abccdfe 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -16,7 +16,7 @@ <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/volume_dialog_root" + android:id="@+id/volume_dialog" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0" diff --git a/packages/SystemUI/res/layout/volume_ringer_button.xml b/packages/SystemUI/res/layout/volume_ringer_button.xml index 6748cfa05c35..4e3c8cc4413b 100644 --- a/packages/SystemUI/res/layout/volume_ringer_button.xml +++ b/packages/SystemUI/res/layout/volume_ringer_button.xml @@ -13,20 +13,13 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<ImageButton xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" > - - <ImageButton - android:id="@+id/volume_drawer_button" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:padding="@dimen/volume_dialog_ringer_drawer_button_icon_radius" - android:contentDescription="@string/volume_ringer_mode" - android:gravity="center" - android:tint="@androidprv:color/materialColorOnSurface" - android:src="@drawable/volume_ringer_item_bg" - android:background="@drawable/volume_ringer_item_bg"/> - -</FrameLayout> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/volume_ringer_item_bg" + android:contentDescription="@string/volume_ringer_mode" + android:gravity="center" + android:padding="@dimen/volume_dialog_ringer_drawer_button_icon_radius" + android:src="@drawable/volume_ringer_item_bg" + android:tint="@androidprv:color/materialColorOnSurface" /> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index f85a23c1f091..eb96c921c181 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -24,6 +24,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags.communalSceneKtfRefactor import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -57,6 +58,7 @@ constructor( keyguardInteractor: KeyguardInteractor, powerInteractor: PowerInteractor, private val communalInteractor: CommunalInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, private val communalSceneInteractor: CommunalSceneInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, val deviceEntryInteractor: DeviceEntryInteractor, @@ -116,6 +118,17 @@ constructor( } } + @SuppressLint("MissingPermission") + private fun shouldTransitionToCommunal( + shouldShowCommunal: Boolean, + isCommunalAvailable: Boolean, + ) = + if (communalSettingsInteractor.isV2FlagEnabled()) { + shouldShowCommunal + } else { + isCommunalAvailable && dreamManager.canStartDreaming(false) + } + @OptIn(FlowPreview::class) @SuppressLint("MissingPermission") private fun listenForDozingToDreaming() { @@ -141,9 +154,10 @@ constructor( .filterRelevantKeyguardStateAnd { isAwake -> isAwake } .sample( communalInteractor.isCommunalAvailable, + communalInteractor.shouldShowCommunal, communalSceneInteractor.isIdleOnCommunal, ) - .collect { (_, isCommunalAvailable, isIdleOnCommunal) -> + .collect { (_, isCommunalAvailable, shouldShowCommunal, isIdleOnCommunal) -> val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value @@ -177,11 +191,9 @@ constructor( if (!SceneContainerFlag.isEnabled) { startTransitionTo(KeyguardState.GLANCEABLE_HUB) } - } else if (isCommunalAvailable && dreamManager.canStartDreaming(false)) { - // Using false for isScreenOn as canStartDreaming returns false if any - // dream, including doze, is active. - // This case handles tapping the power button to transition through - // dream -> off -> hub. + } else if ( + shouldTransitionToCommunal(shouldShowCommunal, isCommunalAvailable) + ) { if (!SceneContainerFlag.isEnabled) { transitionToGlanceableHub() } @@ -203,6 +215,7 @@ constructor( powerInteractor.detailedWakefulness .filterRelevantKeyguardStateAnd { it.isAwake() } .sample( + communalInteractor.shouldShowCommunal, communalInteractor.isCommunalAvailable, communalSceneInteractor.isIdleOnCommunal, keyguardInteractor.biometricUnlockState, @@ -212,6 +225,7 @@ constructor( .collect { ( _, + shouldShowCommunal, isCommunalAvailable, isIdleOnCommunal, biometricUnlockState, @@ -245,7 +259,9 @@ constructor( ownerReason = "waking from dozing", ) } - } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) { + } else if ( + shouldTransitionToCommunal(shouldShowCommunal, isCommunalAvailable) + ) { if (!SceneContainerFlag.isEnabled) { transitionToGlanceableHub() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 251af11f7fe6..c1c509b8fd57 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -129,20 +129,37 @@ constructor( if (!communalSettingsInteractor.isCommunalFlagEnabled()) return if (SceneContainerFlag.isEnabled) return scope.launch { - powerInteractor.isAwake - .debounce(50L) - .filterRelevantKeyguardStateAnd { isAwake -> isAwake } - .sample(communalInteractor.isCommunalAvailable) - .collect { isCommunalAvailable -> - if (isCommunalAvailable && dreamManager.canStartDreaming(false)) { - // This case handles tapping the power button to transition through - // dream -> off -> hub. - communalSceneInteractor.snapToScene( - newScene = CommunalScenes.Communal, - loggingReason = "from dreaming to hub", - ) + if (communalSettingsInteractor.isV2FlagEnabled()) { + powerInteractor.isAwake + .debounce(50L) + .filterRelevantKeyguardStateAnd { isAwake -> isAwake } + .sample(communalInteractor.shouldShowCommunal) + .collect { shouldShowCommunal -> + if (shouldShowCommunal) { + // This case handles tapping the power button to transition through + // dream -> off -> hub. + communalSceneInteractor.snapToScene( + newScene = CommunalScenes.Communal, + loggingReason = "from dreaming to hub", + ) + } } - } + } else { + powerInteractor.isAwake + .debounce(50L) + .filterRelevantKeyguardStateAnd { isAwake -> isAwake } + .sample(communalInteractor.isCommunalAvailable) + .collect { isCommunalAvailable -> + if (isCommunalAvailable && dreamManager.canStartDreaming(false)) { + // This case handles tapping the power button to transition through + // dream -> off -> hub. + communalSceneInteractor.snapToScene( + newScene = CommunalScenes.Communal, + loggingReason = "from dreaming to hub", + ) + } + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt index 16dff7d11002..11b014c2147f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt @@ -28,6 +28,7 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.qs.panels.shared.model.PanelsLog import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.settings.UserFileManager import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.SharedPreferencesExt.observe @@ -83,34 +84,78 @@ constructor( .flowOn(backgroundDispatcher) /** Sets for the current user the set of [TileSpec] to display as large tiles. */ - fun setLargeTilesSpecs(specs: Set<TileSpec>) { - setLargeTilesSpecsForUser(specs, userRepository.getSelectedUserInfo().id) + fun writeLargeTileSpecs(specs: Set<TileSpec>) { + with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) { + writeLargeTileSpecs(specs) + setLargeTilesDefault(false) + } } - private fun setLargeTilesSpecsForUser(specs: Set<TileSpec>, userId: Int) { - with(getSharedPrefs(userId)) { - edit().putStringSet(LARGE_TILES_SPECS_KEY, specs.map { it.spec }.toSet()).apply() + suspend fun deleteLargeTileDataJob() { + userRepository.selectedUserInfo.collect { userInfo -> + getSharedPrefs(userInfo.id) + .edit() + .remove(LARGE_TILES_SPECS_KEY) + .remove(LARGE_TILES_DEFAULT_KEY) + .apply() } } + private fun SharedPreferences.writeLargeTileSpecs(specs: Set<TileSpec>) { + edit().putStringSet(LARGE_TILES_SPECS_KEY, specs.map { it.spec }.toSet()).apply() + } + /** - * Sets the initial tiles as large, if there is no set in SharedPrefs for the [userId]. This is - * to be used when upgrading to a build that supports large/small tiles. + * Sets the initial set of large tiles. One of the following cases will happen: + * * If we are setting the default set (no value stored in settings for the list of tiles), set + * the large tiles based on [defaultLargeTilesRepository]. We do this to signal future reboots + * that we have performed the upgrade path once. In this case, we will mark that we set them + * as the default in case a restore needs to modify them later. + * * If we got a list of tiles restored from a device and nothing has modified the list of + * tiles, set all the restored tiles to large. Note that if we also restored a set of large + * tiles before this was called, [LARGE_TILES_DEFAULT_KEY] will be false and we won't + * overwrite it. + * * If we got a list of tiles from settings, we consider that we upgraded in place and then we + * will set all those tiles to large IF there's no current set of large tiles. * * Even if largeTilesSpec is read Eagerly before we know if we are in an initial state, because * we are not writing the default values to the SharedPreferences, the file will not contain the * key and this call will succeed, as long as there hasn't been any calls to setLargeTilesSpecs * for that user before. */ - fun setInitialLargeTilesSpecs(specs: Set<TileSpec>, userId: Int) { + fun setInitialOrUpgradeLargeTiles(upgradePath: TilesUpgradePath, userId: Int) { with(getSharedPrefs(userId)) { - if (!contains(LARGE_TILES_SPECS_KEY)) { - logger.i("Setting upgraded large tiles for user $userId: $specs") - setLargeTilesSpecsForUser(specs, userId) + when (upgradePath) { + is TilesUpgradePath.DefaultSet -> { + writeLargeTileSpecs(defaultLargeTilesRepository.defaultLargeTiles) + logger.i("Large tiles set to default on init") + setLargeTilesDefault(true) + } + is TilesUpgradePath.RestoreFromBackup -> { + if ( + getBoolean(LARGE_TILES_DEFAULT_KEY, false) || + !contains(LARGE_TILES_SPECS_KEY) + ) { + writeLargeTileSpecs(upgradePath.value) + logger.i("Tiles restored from backup set to large: ${upgradePath.value}") + setLargeTilesDefault(false) + } + } + is TilesUpgradePath.ReadFromSettings -> { + if (!contains(LARGE_TILES_SPECS_KEY)) { + writeLargeTileSpecs(upgradePath.value) + logger.i("Tiles read from settings set to large: ${upgradePath.value}") + setLargeTilesDefault(false) + } + } } } } + private fun SharedPreferences.setLargeTilesDefault(value: Boolean) { + edit().putBoolean(LARGE_TILES_DEFAULT_KEY, value).apply() + } + private fun getSharedPrefs(userId: Int): SharedPreferences { return userFileManager.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, userId) } @@ -118,6 +163,7 @@ constructor( companion object { private const val TAG = "QSPreferencesRepository" private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs" + private const val LARGE_TILES_DEFAULT_KEY = "large_tiles_default" const val FILE_NAME = "quick_settings_prefs" } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt index 86838b438bc6..9b98797ef393 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -27,10 +28,20 @@ class QSPreferencesInteractor @Inject constructor(private val repo: QSPreference val largeTilesSpecs: Flow<Set<TileSpec>> = repo.largeTilesSpecs fun setLargeTilesSpecs(specs: Set<TileSpec>) { - repo.setLargeTilesSpecs(specs) + repo.writeLargeTileSpecs(specs) } - fun setInitialLargeTilesSpecs(specs: Set<TileSpec>, user: Int) { - repo.setInitialLargeTilesSpecs(specs, user) + /** + * This method should be called to indicate that a "new" set of tiles has been determined for a + * particular user coming from different upgrade sources. + * + * @see TilesUpgradePath for more information + */ + fun setInitialOrUpgradeLargeTilesSpecs(specs: TilesUpgradePath, user: Int) { + repo.setInitialOrUpgradeLargeTiles(specs, user) + } + + suspend fun deleteLargeTilesDataJob() { + repo.deleteLargeTileDataJob() } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt index a8ac5c34d8f9..e2797356fa96 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt @@ -19,11 +19,13 @@ package com.android.systemui.qs.panels.domain.startable import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.CoreStartable import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.qs.flags.QsInCompose import com.android.systemui.qs.panels.domain.interactor.QSPreferencesInteractor import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch class QSPanelsCoreStartable @Inject @@ -33,10 +35,14 @@ constructor( @Background private val backgroundApplicationScope: CoroutineScope, ) : CoreStartable { override fun start() { - backgroundApplicationScope.launchTraced("QSPanelsCoreStartable.startingLargeTiles") { - tileSpecRepository.tilesReadFromSetting.receiveAsFlow().collect { (tiles, userId) -> - preferenceInteractor.setInitialLargeTilesSpecs(tiles, userId) + if (QsInCompose.isEnabled) { + backgroundApplicationScope.launchTraced("QSPanelsCoreStartable.startingLargeTiles") { + tileSpecRepository.tilesUpgradePath.receiveAsFlow().collect { (tiles, userId) -> + preferenceInteractor.setInitialOrUpgradeLargeTilesSpecs(tiles, userId) + } } + } else { + backgroundApplicationScope.launch { preferenceInteractor.deleteLargeTilesDataJob() } } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt index 6b7dd386bb46..c50d5dad10c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt @@ -24,6 +24,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.res.R import com.android.systemui.retail.data.repository.RetailModeRepository @@ -78,7 +79,7 @@ interface TileSpecRepository { /** Reset the current set of tiles to the default list of tiles */ suspend fun resetToDefault(userId: Int) - val tilesReadFromSetting: ReceiveChannel<Pair<Set<TileSpec>, Int>> + val tilesUpgradePath: ReceiveChannel<Pair<TilesUpgradePath, Int>> companion object { /** Position to indicate the end of the list */ @@ -112,8 +113,8 @@ constructor( .filter { it !is TileSpec.Invalid } } - private val _tilesReadFromSetting = Channel<Pair<Set<TileSpec>, Int>>(capacity = 5) - override val tilesReadFromSetting = _tilesReadFromSetting + private val _tilesUpgradePath = Channel<Pair<TilesUpgradePath, Int>>(capacity = 5) + override val tilesUpgradePath = _tilesUpgradePath private val userTileRepositories = SparseArray<UserTileSpecRepository>() @@ -122,8 +123,8 @@ constructor( val userTileRepository = userTileSpecRepositoryFactory.create(userId) userTileRepositories.put(userId, userTileRepository) applicationScope.launchTraced("TileSpecRepository.aggregateTilesPerUser") { - for (tilesFromSettings in userTileRepository.tilesReadFromSettings) { - _tilesReadFromSetting.send(tilesFromSettings to userId) + for (tileUpgrade in userTileRepository.tilesUpgradePath) { + _tilesUpgradePath.send(tileUpgrade to userId) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt index 7b56cd92a081..5aa5edaa726e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt @@ -9,6 +9,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.util.settings.SecureSettings import dagger.assisted.Assisted @@ -49,8 +50,8 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, ) { - private val _tilesReadFromSettings = Channel<Set<TileSpec>>(capacity = 2) - val tilesReadFromSettings: ReceiveChannel<Set<TileSpec>> = _tilesReadFromSettings + private val _tilesUpgradePath = Channel<TilesUpgradePath>(capacity = 3) + val tilesUpgradePath: ReceiveChannel<TilesUpgradePath> = _tilesUpgradePath private val defaultTiles: List<TileSpec> get() = defaultTilesRepository.defaultTiles @@ -67,14 +68,23 @@ constructor( .scan(loadTilesFromSettingsAndParse(userId)) { current, change -> change .apply(current) - .also { - if (current != it) { + .also { afterRestore -> + if (current != afterRestore) { if (change is RestoreTiles) { - logger.logTilesRestoredAndReconciled(current, it, userId) + logger.logTilesRestoredAndReconciled( + current, + afterRestore, + userId, + ) } else { - logger.logProcessTileChange(change, it, userId) + logger.logProcessTileChange(change, afterRestore, userId) } } + if (change is RestoreTiles) { + _tilesUpgradePath.send( + TilesUpgradePath.RestoreFromBackup(afterRestore.toSet()) + ) + } } // Distinct preserves the order of the elements removing later // duplicates, @@ -154,7 +164,9 @@ constructor( private suspend fun loadTilesFromSettingsAndParse(userId: Int): List<TileSpec> { val loadedTiles = loadTilesFromSettings(userId) if (loadedTiles.isNotEmpty()) { - _tilesReadFromSettings.send(loadedTiles.toSet()) + _tilesUpgradePath.send(TilesUpgradePath.ReadFromSettings(loadedTiles.toSet())) + } else { + _tilesUpgradePath.send(TilesUpgradePath.DefaultSet) } return parseTileSpecs(loadedTiles, userId) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TilesUpgradePath.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TilesUpgradePath.kt new file mode 100644 index 000000000000..98f30c22d0f3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TilesUpgradePath.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 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.systemui.qs.pipeline.shared + +/** Upgrade paths indicating the source of the list of QS tiles. */ +sealed interface TilesUpgradePath { + + sealed interface UpgradeWithTiles : TilesUpgradePath { + val value: Set<TileSpec> + } + + /** This indicates a set of tiles that was read from Settings on user start */ + @JvmInline value class ReadFromSettings(override val value: Set<TileSpec>) : UpgradeWithTiles + + /** This indicates a set of tiles that was restored from backup */ + @JvmInline value class RestoreFromBackup(override val value: Set<TileSpec>) : UpgradeWithTiles + + /** + * This indicates that no tiles were read from Settings on user start so the default has been + * stored. + */ + data object DefaultSet : TilesUpgradePath +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt index 3ba0ae3b3cb6..1a30caf0150b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt @@ -214,7 +214,6 @@ constructor( if ( secondaryChip is InternalChipModel.Active && StatusBarNotifChips.isEnabled && - !StatusBarChipsModernization.isEnabled && !isScreenReasonablyLarge ) { // If we have two showing chips and we don't have a ton of room @@ -222,8 +221,10 @@ constructor( // possible so that we have the highest chance of showing both chips (as // opposed to showing the primary chip with a lot of text and completely // hiding the secondary chip). - // Also: If StatusBarChipsModernization is enabled, then we'll do the - // squishing in Compose instead. + // TODO(b/392895330): If StatusBarChipsModernization is enabled, do the + // squishing in Compose instead, and be smart about it (e.g. if we have + // room for the first chip to show text and the second chip to be icon-only, + // do that instead of always squishing both chips.) InternalMultipleOngoingActivityChipsModel( primaryChip.squish(), secondaryChip.squish(), @@ -237,24 +238,31 @@ constructor( /** Squishes the chip down to the smallest content possible. */ private fun InternalChipModel.Active.squish(): InternalChipModel.Active { - return when (model) { + return if (model.shouldSquish()) { + InternalChipModel.Active(this.type, this.model.toIconOnly()) + } else { + this + } + } + + private fun OngoingActivityChipModel.Active.shouldSquish(): Boolean { + return when (this) { // Icon-only is already maximum squished - is OngoingActivityChipModel.Active.IconOnly -> this + is OngoingActivityChipModel.Active.IconOnly, // Countdown shows just a single digit, so already maximum squished - is OngoingActivityChipModel.Active.Countdown -> this - // The other chips have icon+text, so we should hide the text + is OngoingActivityChipModel.Active.Countdown -> false + // The other chips have icon+text, so we can squish them by hiding text is OngoingActivityChipModel.Active.Timer, is OngoingActivityChipModel.Active.ShortTimeDelta, - is OngoingActivityChipModel.Active.Text -> - InternalChipModel.Active(this.type, this.model.toIconOnly()) + is OngoingActivityChipModel.Active.Text -> true } } private fun OngoingActivityChipModel.Active.toIconOnly(): OngoingActivityChipModel.Active { // If this chip doesn't have an icon, then it only has text and we should continue showing // its text. (This is theoretically impossible because - // [OngoingActivityChipModel.Active.Countdown] is the only chip without an icon, but protect - // against it just in case.) + // [OngoingActivityChipModel.Active.Countdown] is the only chip without an icon and + // [shouldSquish] returns false for that model, but protect against it just in case.) val currentIcon = icon ?: return this return OngoingActivityChipModel.Active.IconOnly( key, @@ -271,8 +279,38 @@ constructor( */ val chips: StateFlow<MultipleOngoingActivityChipsModel> = if (StatusBarChipsModernization.isEnabled) { - incomingChipBundle - .map { bundle -> rankChips(bundle) } + combine( + incomingChipBundle.map { bundle -> rankChips(bundle) }, + isScreenReasonablyLarge, + ) { rankedChips, isScreenReasonablyLarge -> + if ( + StatusBarNotifChips.isEnabled && + !isScreenReasonablyLarge && + rankedChips.active.filter { !it.isHidden }.size >= 2 + ) { + // If we have at least two showing chips and we don't have a ton of room + // (!isScreenReasonablyLarge), then we want to make both of them as small as + // possible so that we have the highest chance of showing both chips (as + // opposed to showing the first chip with a lot of text and completely + // hiding the other chips). + val squishedActiveChips = + rankedChips.active.map { + if (!it.isHidden && it.shouldSquish()) { + it.toIconOnly() + } else { + it + } + } + + MultipleOngoingActivityChipsModel( + active = squishedActiveChips, + overflow = rankedChips.overflow, + inactive = rankedChips.inactive, + ) + } else { + rankedChips + } + } .stateIn(scope, SharingStarted.Lazily, MultipleOngoingActivityChipsModel()) } else { MutableStateFlow(MultipleOngoingActivityChipsModel()).asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index e33baf7c33ae..ded964d8a1cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -57,11 +57,11 @@ import com.android.systemui.animation.ActivityTransitionAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.power.domain.interactor.PowerInteractor; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; +import com.android.systemui.shade.ShadeDisplayAware; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; import com.android.systemui.statusbar.CommandQueue; @@ -76,11 +76,11 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; +import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; -import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.wmshell.BubblesManager; @@ -115,7 +115,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final static String TAG = "StatusBarNotificationActivityStarter"; private final Context mContext; - private final int mDisplayId; private final Handler mMainThreadHandler; private final Executor mUiBgExecutor; @@ -155,8 +154,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Inject StatusBarNotificationActivityStarter( - Context context, - @DisplayId int displayId, + @ShadeDisplayAware Context context, Handler mainThreadHandler, @Background Executor uiBgExecutor, NotificationVisibilityProvider visibilityProvider, @@ -189,7 +187,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit PowerInteractor powerInteractor, UserTracker userTracker) { mContext = context; - mDisplayId = displayId; mMainThreadHandler = mainThreadHandler; mUiBgExecutor = uiBgExecutor; mVisibilityProvider = visibilityProvider; @@ -493,6 +490,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit boolean animate, boolean isActivityIntent) { mLogger.logStartNotificationIntent(entry); + final int displayId = mContext.getDisplayId(); try { ActivityTransitionAnimator.Controller animationController = new StatusBarTransitionAnimatorController( @@ -501,7 +499,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController, mNotificationShadeWindowController, mCommandQueue, - mDisplayId, + displayId, isActivityIntent); mActivityTransitionAnimator.startPendingIntentWithAnimation( animationController, @@ -511,11 +509,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit long eventTime = row.getAndResetLastActionUpTime(); Bundle options = eventTime > 0 ? getActivityOptions( - mDisplayId, + displayId, adapter, mKeyguardStateController.isShowing(), eventTime) - : getActivityOptions(mDisplayId, adapter); + : getActivityOptions(displayId, adapter); int result = intent.sendAndReturnResult(mContext, 0, fillInIntent, null, null, null, options); mLogger.logSendPendingIntent(entry, intent, result); @@ -533,6 +531,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit public void startNotificationGutsIntent(@NonNull final Intent intent, final int appUid, @NonNull ExpandableNotificationRow row) { boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); + final int displayId = mContext.getDisplayId(); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override public boolean onDismiss() { @@ -544,7 +543,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController, mNotificationShadeWindowController, mCommandQueue, - mDisplayId, + displayId, true /* isActivityIntent */); mActivityTransitionAnimator.startIntentWithAnimation( @@ -552,7 +551,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit (adapter) -> TaskStackBuilder.create(mContext) .addNextIntentWithParentStack(intent) .startActivities(getActivityOptions( - mDisplayId, + displayId, adapter), new UserHandle(UserHandle.getUserId(appUid)))); }); @@ -571,6 +570,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startHistoryIntent(View view, boolean showHistory) { ModesEmptyShadeFix.assertInLegacyMode(); + final int displayId = mContext.getDisplayId(); boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override @@ -597,13 +597,13 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController, mNotificationShadeWindowController, mCommandQueue, - mDisplayId, + displayId, true /* isActivityIntent */); mActivityTransitionAnimator.startIntentWithAnimation( animationController, animate, intent.getPackage(), (adapter) -> tsb.startActivities( - getActivityOptions(mDisplayId, adapter), + getActivityOptions(displayId, adapter), mUserTracker.getUserHandle())); }); return true; @@ -620,6 +620,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startSettingsIntent(@NonNull View view, @NonNull SettingsIntent intentInfo) { + final int displayId = mContext.getDisplayId(); boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override @@ -642,13 +643,13 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController, mNotificationShadeWindowController, mCommandQueue, - mDisplayId, + displayId, true /* isActivityIntent */); mActivityTransitionAnimator.startIntentWithAnimation( animationController, animate, intentInfo.getTargetIntent().getPackage(), (adapter) -> tsb.startActivities( - getActivityOptions(mDisplayId, adapter), + getActivityOptions(displayId, adapter), mUserTracker.getUserHandle())); }); return true; diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt index 83b7c1818341..86defff4a120 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt @@ -68,7 +68,7 @@ constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.volume_dialog) - requireViewById<View>(R.id.volume_dialog_root).repeatWhenAttached { + requireViewById<View>(R.id.volume_dialog).repeatWhenAttached { coroutineScopeTraced("[Volume]dialog") { val component = componentFactory.create(this) with(component.volumeDialogViewBinder()) { bind(this@VolumeDialog) } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt index 20a74b027db5..afe3d7bf217a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt @@ -17,7 +17,9 @@ package com.android.systemui.volume.dialog.domain.interactor import android.annotation.SuppressLint +import android.provider.Settings import com.android.systemui.plugins.VolumeDialogController +import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository import com.android.systemui.volume.Events import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope @@ -28,8 +30,9 @@ import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityMod import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Visible import com.android.systemui.volume.dialog.utils.VolumeTracer import javax.inject.Inject -import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds +import kotlin.time.DurationUnit import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow @@ -43,8 +46,6 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn -private val MAX_DIALOG_SHOW_TIME: Duration = 3.seconds - /** * Handles Volume Dialog visibility state. It might change from several sources: * - [com.android.systemui.plugins.VolumeDialogController] requests visibility change; @@ -60,8 +61,11 @@ constructor( private val tracer: VolumeTracer, private val repository: VolumeDialogVisibilityRepository, private val controller: VolumeDialogController, + private val secureSettingsRepository: SecureSettingsRepository, ) { + private val defaultTimeout = 3.seconds + @SuppressLint("SharedFlowCreation") private val mutableDismissDialogEvents = MutableSharedFlow<Unit>(extraBufferCapacity = 1) val dialogVisibility: Flow<VolumeDialogVisibilityModel> = @@ -73,7 +77,14 @@ constructor( init { merge( mutableDismissDialogEvents.mapLatest { - delay(MAX_DIALOG_SHOW_TIME) + delay( + secureSettingsRepository + .getInt( + Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, + defaultTimeout.toInt(DurationUnit.MILLISECONDS), + ) + .milliseconds + ) VolumeDialogEventModel.DismissRequested(Events.DISMISS_REASON_TIMEOUT) }, callbacksInteractor.event, diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt index 3d0c7d64b2a4..92ec4f554548 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt @@ -246,16 +246,12 @@ constructor( uiModel.drawerState.currentMode != uiModel.drawerState.previousMode ) { val count = uiModel.availableButtons.size - val selectedButton = - getChildAt(count - uiModel.currentButtonIndex) - .requireViewById<ImageButton>(R.id.volume_drawer_button) + val selectedButton = getChildAt(count - uiModel.currentButtonIndex) as ImageButton val previousIndex = uiModel.availableButtons.indexOfFirst { it.ringerMode == uiModel.drawerState.previousMode } - val unselectedButton = - getChildAt(count - previousIndex) - .requireViewById<ImageButton>(R.id.volume_drawer_button) + val unselectedButton = getChildAt(count - previousIndex) as ImageButton // We only need to execute on roundness animation end and volume dialog background // progress update once because these changes should be applied once on volume dialog // background and ringer drawer views. @@ -306,7 +302,7 @@ constructor( ) { val count = uiModel.availableButtons.size uiModel.availableButtons.fastForEachIndexed { index, ringerButton -> - val view = getChildAt(count - index) + val view = getChildAt(count - index) as ImageButton val isOpen = uiModel.drawerState is RingerDrawerState.Open if (index == uiModel.currentButtonIndex) { view.bindDrawerButton( @@ -323,37 +319,37 @@ constructor( onAnimationEnd?.run() } - private fun View.bindDrawerButton( + private fun ImageButton.bindDrawerButton( buttonViewModel: RingerButtonViewModel, viewModel: VolumeDialogRingerDrawerViewModel, isOpen: Boolean, isSelected: Boolean = false, isAnimated: Boolean = false, ) { + // id = buttonViewModel.viewId + setSelected(isSelected) val ringerContentDesc = context.getString(buttonViewModel.contentDescriptionResId) - with(requireViewById<ImageButton>(R.id.volume_drawer_button)) { - setImageResource(buttonViewModel.imageResId) - contentDescription = - if (isSelected && !isOpen) { - context.getString( - R.string.volume_ringer_drawer_closed_content_description, - ringerContentDesc, - ) - } else { - ringerContentDesc - } - if (isSelected && !isAnimated) { - setBackgroundResource(R.drawable.volume_drawer_selection_bg) - setColorFilter(context.getColor(internalR.color.materialColorOnPrimary)) - background = background.mutate() - } else if (!isAnimated) { - setBackgroundResource(R.drawable.volume_ringer_item_bg) - setColorFilter(context.getColor(internalR.color.materialColorOnSurface)) - background = background.mutate() - } - setOnClickListener { - viewModel.onRingerButtonClicked(buttonViewModel.ringerMode, isSelected) + setImageResource(buttonViewModel.imageResId) + contentDescription = + if (isSelected && !isOpen) { + context.getString( + R.string.volume_ringer_drawer_closed_content_description, + ringerContentDesc, + ) + } else { + ringerContentDesc } + if (isSelected && !isAnimated) { + setBackgroundResource(R.drawable.volume_drawer_selection_bg) + setColorFilter(context.getColor(internalR.color.materialColorOnPrimary)) + background = background.mutate() + } else if (!isAnimated) { + setBackgroundResource(R.drawable.volume_ringer_item_bg) + setColorFilter(context.getColor(internalR.color.materialColorOnSurface)) + background = background.mutate() + } + setOnClickListener { + viewModel.onRingerButtonClicked(buttonViewModel.ringerMode, isSelected) } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt index f2d7d956291c..7cc4bcc4e11c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt @@ -74,7 +74,7 @@ constructor( val insets: MutableStateFlow<WindowInsets> = MutableStateFlow(WindowInsets.Builder().build()) // Root view of the Volume Dialog. - val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root) + val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog) animateVisibility(root, dialog, viewModel.dialogVisibilityModel) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 2f30b745a4a3..3190d3ae8f16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -91,11 +91,11 @@ import com.android.systemui.statusbar.notification.collection.provider.LaunchFul import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository; import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -122,7 +122,6 @@ import java.util.Optional; @TestableLooper.RunWithLooper(setAsMainLooper = true) public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { - private static final int DISPLAY_ID = 0; private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock @@ -233,7 +232,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter = new StatusBarNotificationActivityStarter( getContext(), - DISPLAY_ID, mHandler, mUiBgExecutor, mVisibilityProvider, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt index fcdda9f13099..9da8e80283b6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import android.service.dream.dreamManager import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos @@ -44,5 +45,6 @@ var Kosmos.fromDozingTransitionInteractor by deviceEntryInteractor = deviceEntryInteractor, wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor, dreamManager = dreamManager, + communalSettingsInteractor = communalSettingsInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt index 5fc31f8b9e10..f2871149de11 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.pipeline.data.repository import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.TilesUpgradePath import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -79,9 +80,9 @@ class FakeTileSpecRepository( with(getFlow(userId)) { value = defaultTilesRepository.defaultTiles } } - override val tilesReadFromSetting: Channel<Pair<Set<TileSpec>, Int>> = Channel(capacity = 10) + override val tilesUpgradePath: Channel<Pair<TilesUpgradePath, Int>> = Channel(capacity = 10) - suspend fun sendTilesReadFromSetting(tiles: Set<TileSpec>, userId: Int) { - tilesReadFromSetting.send(tiles to userId) + suspend fun sendTilesFromUpgradePath(upgradePath: TilesUpgradePath, userId: Int) { + tilesUpgradePath.send(upgradePath to userId) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt index 5ff44e5d33c5..c5de02a7281b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt @@ -26,7 +26,7 @@ val Kosmos.minimumTilesRepository: MinimumTilesRepository by Kosmos.Fixture { fakeMinimumTilesRepository } var Kosmos.fakeDefaultTilesRepository by Kosmos.Fixture { FakeDefaultTilesRepository() } -val Kosmos.defaultTilesRepository: DefaultTilesRepository by +var Kosmos.defaultTilesRepository: DefaultTilesRepository by Kosmos.Fixture { fakeDefaultTilesRepository } val Kosmos.fakeTileSpecRepository by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt index 0d6ac4481742..d787e2c190c8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt @@ -52,7 +52,6 @@ val Kosmos.statusBarNotificationActivityStarter by Kosmos.Fixture { StatusBarNotificationActivityStarter( applicationContext, - applicationContext.displayId, fakeExecutorHandler, fakeExecutor, notificationVisibilityProvider, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt index 0d2aa4c79753..888b7e625524 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.volume.dialog.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.volumeDialogController +import com.android.systemui.shared.settings.data.repository.secureSettingsRepository import com.android.systemui.volume.dialog.data.repository.volumeDialogVisibilityRepository import com.android.systemui.volume.dialog.utils.volumeTracer @@ -30,5 +31,6 @@ val Kosmos.volumeDialogVisibilityInteractor by volumeTracer, volumeDialogVisibilityRepository, volumeDialogController, + secureSettingsRepository, ) } diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index a1e8f08db0a6..aab2760dbc66 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -122,11 +122,6 @@ public class DisplayManagerFlags { Flags.FLAG_ALWAYS_ROTATE_DISPLAY_DEVICE, Flags::alwaysRotateDisplayDevice); - private final FlagState mRefreshRateVotingTelemetry = new FlagState( - Flags.FLAG_REFRESH_RATE_VOTING_TELEMETRY, - Flags::refreshRateVotingTelemetry - ); - private final FlagState mPixelAnisotropyCorrectionEnabled = new FlagState( Flags.FLAG_ENABLE_PIXEL_ANISOTROPY_CORRECTION, Flags::enablePixelAnisotropyCorrection @@ -403,10 +398,6 @@ public class DisplayManagerFlags { return mAlwaysRotateDisplayDevice.isEnabled(); } - public boolean isRefreshRateVotingTelemetryEnabled() { - return mRefreshRateVotingTelemetry.isEnabled(); - } - public boolean isPixelAnisotropyCorrectionInLogicalDisplayEnabled() { return mPixelAnisotropyCorrectionEnabled.isEnabled(); } @@ -626,7 +617,6 @@ public class DisplayManagerFlags { pw.println(" " + mAutoBrightnessModesFlagState); pw.println(" " + mFastHdrTransitions); pw.println(" " + mAlwaysRotateDisplayDevice); - pw.println(" " + mRefreshRateVotingTelemetry); pw.println(" " + mPixelAnisotropyCorrectionEnabled); pw.println(" " + mSensorBasedBrightnessThrottling); pw.println(" " + mIdleScreenRefreshRateTimeout); diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index cc0bbde370fe..8211febade60 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -191,14 +191,6 @@ flag { } flag { - name: "refresh_rate_voting_telemetry" - namespace: "display_manager" - description: "Feature flag for enabling telemetry for refresh rate voting in DisplayManager" - bug: "310029108" - is_fixed_read_only: true -} - -flag { name: "enable_pixel_anisotropy_correction" namespace: "display_manager" description: "Feature flag for enabling display anisotropy correction through LogicalDisplay upscaling" diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 1dd4a9b93277..c37733b05fba 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -229,8 +229,7 @@ public class DisplayModeDirector { mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); mInjector = injector; - mVotesStatsReporter = injector.getVotesStatsReporter( - displayManagerFlags.isRefreshRateVotingTelemetryEnabled()); + mVotesStatsReporter = injector.getVotesStatsReporter(); mSupportedModesByDisplay = new SparseArray<>(); mAppSupportedModesByDisplay = new SparseArray<>(); mDefaultModeByDisplay = new SparseArray<>(); @@ -3141,7 +3140,7 @@ public class DisplayModeDirector { SensorManagerInternal getSensorManagerInternal(); @Nullable - VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled); + VotesStatsReporter getVotesStatsReporter(); } @VisibleForTesting @@ -3281,10 +3280,9 @@ public class DisplayModeDirector { } @Override - public VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled) { + public VotesStatsReporter getVotesStatsReporter() { // if frame rate override supported, renderRates will be ignored in mode selection - return new VotesStatsReporter(supportsFrameRateOverride(), - refreshRateVotingTelemetryEnabled); + return new VotesStatsReporter(supportsFrameRateOverride()); } private DisplayManager getDisplayManager() { diff --git a/services/core/java/com/android/server/display/mode/VotesStatsReporter.java b/services/core/java/com/android/server/display/mode/VotesStatsReporter.java index 7562a525b5f6..d3d49c272338 100644 --- a/services/core/java/com/android/server/display/mode/VotesStatsReporter.java +++ b/services/core/java/com/android/server/display/mode/VotesStatsReporter.java @@ -36,13 +36,11 @@ class VotesStatsReporter { private static final String TAG = "VotesStatsReporter"; private static final int REFRESH_RATE_NOT_LIMITED = 1000; private final boolean mIgnoredRenderRate; - private final boolean mFrameworkStatsLogReportingEnabled; private int mLastMinPriorityReported = Vote.MAX_PRIORITY + 1; - public VotesStatsReporter(boolean ignoreRenderRate, boolean refreshRateVotingTelemetryEnabled) { + VotesStatsReporter(boolean ignoreRenderRate) { mIgnoredRenderRate = ignoreRenderRate; - mFrameworkStatsLogReportingEnabled = refreshRateVotingTelemetryEnabled; } void reportVoteChanged(int displayId, int priority, @Nullable Vote vote) { @@ -57,29 +55,22 @@ class VotesStatsReporter { int maxRefreshRate = getMaxRefreshRate(vote, mIgnoredRenderRate); Trace.traceCounter(Trace.TRACE_TAG_POWER, TAG + "." + displayId + ":" + Vote.priorityToString(priority), maxRefreshRate); - if (mFrameworkStatsLogReportingEnabled) { - FrameworkStatsLog.write( - DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority, - DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ADDED, - maxRefreshRate, -1); - } + FrameworkStatsLog.write( + DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority, + DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ADDED, + maxRefreshRate, -1); } private void reportVoteRemoved(int displayId, int priority) { Trace.traceCounter(Trace.TRACE_TAG_POWER, TAG + "." + displayId + ":" + Vote.priorityToString(priority), -1); - if (mFrameworkStatsLogReportingEnabled) { - FrameworkStatsLog.write( - DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority, - DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_REMOVED, -1, -1); - } + FrameworkStatsLog.write( + DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority, + DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_REMOVED, -1, -1); } void reportVotesActivated(int displayId, int minPriority, @Nullable Display.Mode baseMode, SparseArray<Vote> votes) { - if (!mFrameworkStatsLogReportingEnabled) { - return; - } int selectedRefreshRate = baseMode != null ? (int) baseMode.getRefreshRate() : -1; for (int priority = Vote.MIN_PRIORITY; priority <= Vote.MAX_PRIORITY; priority++) { if (priority < mLastMinPriorityReported && priority < minPriority) { diff --git a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java index e2889fa9cbf6..18bccd8411d7 100644 --- a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java @@ -91,7 +91,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor updateAttributes = true; } if (restrictAudioAttributesAlarm() - && record.getNotification().category != CATEGORY_ALARM + && !CATEGORY_ALARM.equals(record.getNotification().category) && attributes.getUsage() == AudioAttributes.USAGE_ALARM) { updateAttributes = true; } diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS index fa4bf228c683..7a31a0006bb9 100644 --- a/services/core/java/com/android/server/security/OWNERS +++ b/services/core/java/com/android/server/security/OWNERS @@ -3,5 +3,6 @@ include /core/java/android/security/OWNERS per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS +per-file *CertificateRevocationStatus* = file:/core/java/android/security/attestationverification/OWNERS per-file FileIntegrity*.java = victorhsieh@google.com per-file KeyChainSystemService.java = file:platform/packages/apps/KeyChain:/OWNERS diff --git a/services/core/java/com/android/server/wm/PresentationController.java b/services/core/java/com/android/server/wm/PresentationController.java index 9630b8fd524b..69463433827f 100644 --- a/services/core/java/com/android/server/wm/PresentationController.java +++ b/services/core/java/com/android/server/wm/PresentationController.java @@ -21,6 +21,9 @@ import static com.android.window.flags.Flags.enablePresentationForConnectedDispl import android.annotation.NonNull; import android.util.IntArray; +import com.android.internal.protolog.ProtoLog; +import com.android.internal.protolog.WmProtoLogGroups; + /** * Manages presentation windows. */ @@ -50,7 +53,9 @@ class PresentationController { if (isPresenting(displayId)) { return; } - mPresentingDisplayIds.add(displayId); + ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, "Presentation added to display %d: %s", + win.getDisplayId(), win); + mPresentingDisplayIds.add(win.getDisplayId()); if (enablePresentationForConnectedDisplays()) { // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, @@ -64,6 +69,8 @@ class PresentationController { if (!isPresenting(displayId)) { return; } + ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, + "Presentation removed from display %d: %s", win.getDisplayId(), win); // TODO(b/393945496): Make sure that there's one presentation at most per display. final int displayIdIndex = mPresentingDisplayIds.indexOf(displayId); if (displayIdIndex != -1) { diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index f154dbcee21a..09ce263e9b2f 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -3962,7 +3962,7 @@ public class DisplayModeDirectorTest { } @Override - public VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled) { + public VotesStatsReporter getVotesStatsReporter() { return null; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java index 770712a191fd..41011928f8b3 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java @@ -204,7 +204,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { .build()); final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") - .setCategory(CATEGORY_ALARM) + .setCategory(new String("alarm")) .setSmallIcon(android.R.drawable.sym_def_app_icon) .build(); NotificationRecord r = getRecord(channel, n); diff --git a/tests/FlickerTests/IME/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml index 12670cda74b2..ac704e5e7c39 100644 --- a/tests/FlickerTests/IME/AndroidTestTemplate.xml +++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml @@ -52,10 +52,12 @@ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard"/> <option name="teardown-command" value="settings delete system show_touches"/> <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" value="settings delete secure glanceable_hub_enabled"/> <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> </target_preparer> diff --git a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml index 481a8bb66fee..1b2007deae27 100644 --- a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml +++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml @@ -50,10 +50,12 @@ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard"/> <option name="teardown-command" value="settings delete system show_touches"/> <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" value="settings delete secure glanceable_hub_enabled"/> <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> </target_preparer> |