Merge "remove aflag declaration OEM_ENABLED_SATELLITE_FLAG" into main
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index c120e67d..33794a5 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -23,6 +23,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
@@ -268,14 +269,27 @@
public static final int ACTION_SHADE_WINDOW_DISPLAY_CHANGE = 29;
/**
- * Applicable when the user drags a full screen app's handle into the desktop drop zone to enter
- * desktop mode. This measure the time from when the user releases their finger in the drop zone
- * to when the animation for entering desktop mode visually begins. During this period, the
- * home task and app headers for each window are initialized. Both have historically been
- * expensive. See b/381396057 and b/360452034 respectively.
+ * Time it takes for the "enter desktop" mode animation to begin when initiated by dragging the
+ * app's handle into the desktop drop zone.
+ * <p>
+ * This measure the time from when the user releases their finger in the drop zone to when the
+ * animation for entering desktop mode visually begins. During this period, the home task and
+ * app headers for each window are initialized. Both have historically been expensive. See
+ * b/381396057 and b/360452034 respectively.
*/
public static final int ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG = 30;
+ /**
+ * Time it takes for the "enter desktop" mode animation to begin when initiated via the app
+ * handle's menu.
+ * <p>
+ * This measures the time from when the menu option is clicked/tapped to when the animation for
+ * entering desktop mode visually begins. During this period, the home task and app headers for
+ * each window are initialized. Both have historically been expensive. See b/381396057 and
+ * b/360452034 respectively.
+ */
+ public static final int ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU = 31;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -308,6 +322,7 @@
ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
ACTION_SHADE_WINDOW_DISPLAY_CHANGE,
ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
+ ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
};
/** @hide */
@@ -343,6 +358,7 @@
ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
ACTION_SHADE_WINDOW_DISPLAY_CHANGE,
ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
+ ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {}
@@ -380,6 +396,7 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
};
private final Object mLock = new Object();
@@ -582,6 +599,8 @@
return "ACTION_SHADE_WINDOW_DISPLAY_CHANGE";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG:
return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU:
+ return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU";
default:
throw new IllegalArgumentException("Invalid action");
}
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 5d5e4d3..59acdc5 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
@@ -44,6 +44,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.LatencyTracker;
import com.android.launcher3.icons.IconProvider;
import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
@@ -1074,8 +1075,10 @@
static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
Transitions transitions,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
- InteractionJankMonitor interactionJankMonitor) {
- return new EnterDesktopTaskTransitionHandler(transitions, interactionJankMonitor);
+ InteractionJankMonitor interactionJankMonitor,
+ LatencyTracker latencyTracker) {
+ return new EnterDesktopTaskTransitionHandler(
+ transitions, interactionJankMonitor, latencyTracker);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
index 946e795..afc48ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
@@ -68,6 +68,8 @@
// desk has been recreated here, which may result in a crash-loop if the repository is
// checking that the desk exists before adding a task to it. See b/391984373.
desktopTasksController.createDesk(displayId)
+ // TODO: b/393978539 - consider activating the desk on creation when applicable, such as
+ // for connected displays.
}
override fun onDisplayRemoved(displayId: Int) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 926e0f2..3c694ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -238,7 +238,6 @@
}
/** Returns the id of the active desk in the given display, if any. */
- @VisibleForTesting
fun getActiveDeskId(displayId: Int): Int? = desktopData.getActiveDesk(displayId)?.deskId
/** Returns the id of the desk to which this task belongs. */
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 87d9674..ea4d96a 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
@@ -1251,36 +1251,77 @@
return
}
+ val wct = WindowContainerTransaction()
val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
if (displayAreaInfo == null) {
logW("moveToDisplay: display not found")
return
}
- val wct = WindowContainerTransaction()
-
// check if the task is part of splitscreen
if (
Flags.enableNonDefaultDisplaySplit() &&
Flags.enableMoveToNextDisplayShortcut() &&
splitScreenController.isTaskInSplitScreen(task.taskId)
) {
+ val activeDeskId = taskRepository.getActiveDeskId(displayId)
+ logV("moveToDisplay: moving split root to displayId=%d", displayId)
val stageCoordinatorRootTaskToken =
splitScreenController.multiDisplayProvider.getDisplayRootForDisplayId(
DEFAULT_DISPLAY
)
-
wct.reparent(stageCoordinatorRootTaskToken, displayAreaInfo.token, true /* onTop */)
- transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+ val deactivationRunnable =
+ if (activeDeskId != null) {
+ // Split is being placed on top of an existing desk in the target display. Make
+ // sure it is cleaned up.
+ performDesktopExitCleanUp(
+ wct = wct,
+ deskId = activeDeskId,
+ displayId = displayId,
+ willExitDesktop = true,
+ shouldEndUpAtHome = false,
+ )
+ } else {
+ null
+ }
+ val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+ deactivationRunnable?.invoke(transition)
return
}
+ val destinationDeskId = taskRepository.getDefaultDeskId(displayId)
+ if (destinationDeskId == null) {
+ logW("moveToDisplay: desk not found for display: $displayId")
+ return
+ }
+
+ // TODO: b/393977830 and b/397437641 - do not assume that freeform==desktop.
if (!task.isFreeform) {
addMoveToDesktopChanges(wct, task, displayId)
} else if (Flags.enableMoveToNextDisplayShortcut()) {
applyFreeformDisplayChange(wct, task, displayId)
}
- wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true)
+
+ val activationRunnable: RunOnTransitStart?
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+ desksOrganizer.moveTaskToDesk(wct, destinationDeskId, task)
+ prepareForDeskActivation(displayId, wct)
+ desksOrganizer.activateDesk(wct, destinationDeskId)
+ activationRunnable = { transition ->
+ desksTransitionObserver.addPendingTransition(
+ DeskTransition.ActiveDeskWithTask(
+ token = transition,
+ displayId = displayId,
+ deskId = destinationDeskId,
+ enterTaskId = task.taskId,
+ )
+ )
+ }
+ } else {
+ wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true)
+ activationRunnable = null
+ }
if (Flags.enableDisplayFocusInShellTransitions()) {
// Bring the destination display to top with includingParents=true, so that the
// destination display gains the display focus, which makes the top task in the display
@@ -1288,22 +1329,31 @@
wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
}
- // TODO: b/394268248 - desk needs to be deactivated when moving the last task and going
- // home.
- if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
- performDesktopExitCleanupIfNeeded(
- taskId = task.taskId,
- displayId = task.displayId,
- wct = wct,
- forceToFullscreen = false,
- // TODO: b/371096166 - Temporary turing home relaunch off to prevent home stealing
- // display focus. Remove shouldEndUpAtHome = false when home focus handling
- // with connected display is implemented in wm core.
- shouldEndUpAtHome = false,
- )
- }
-
- transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+ val sourceDisplayId = task.displayId
+ val sourceDeskId = taskRepository.getDeskIdForTask(task.taskId)
+ val shouldExitDesktopIfNeeded =
+ Flags.enablePerDisplayDesktopWallpaperActivity() ||
+ DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
+ val deactivationRunnable =
+ if (shouldExitDesktopIfNeeded) {
+ performDesktopExitCleanupIfNeeded(
+ taskId = task.taskId,
+ deskId = sourceDeskId,
+ displayId = sourceDisplayId,
+ wct = wct,
+ forceToFullscreen = false,
+ // TODO: b/371096166 - Temporary turing home relaunch off to prevent home
+ // stealing
+ // display focus. Remove shouldEndUpAtHome = false when home focus handling
+ // with connected display is implemented in wm core.
+ shouldEndUpAtHome = false,
+ )
+ } else {
+ null
+ }
+ val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+ deactivationRunnable?.invoke(transition)
+ activationRunnable?.invoke(transition)
}
/**
@@ -2484,6 +2534,7 @@
val displayLayout = displayController.getDisplayLayout(displayId) ?: return
val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)!!
val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
+ // TODO: b/397437641 - reconsider the windowing mode choice when multiple desks is enabled.
val targetWindowingMode =
if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) {
// Display windowing is freeform, set to undefined and inherit it
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 80e106f..4c17030 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -41,6 +41,7 @@
import androidx.annotation.Nullable;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.util.LatencyTracker;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener;
@@ -63,20 +64,25 @@
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private final InteractionJankMonitor mInteractionJankMonitor;
+ private final LatencyTracker mLatencyTracker;
private OnTaskResizeAnimationListener mOnTaskResizeAnimationListener;
public EnterDesktopTaskTransitionHandler(
- Transitions transitions, InteractionJankMonitor interactionJankMonitor) {
- this(transitions, interactionJankMonitor, SurfaceControl.Transaction::new);
+ Transitions transitions,
+ InteractionJankMonitor interactionJankMonitor,
+ LatencyTracker latencyTracker) {
+ this(transitions, interactionJankMonitor, latencyTracker, SurfaceControl.Transaction::new);
}
public EnterDesktopTaskTransitionHandler(
Transitions transitions,
InteractionJankMonitor interactionJankMonitor,
+ LatencyTracker latencyTracker,
Supplier<SurfaceControl.Transaction> supplier) {
mTransitions = transitions;
mInteractionJankMonitor = interactionJankMonitor;
+ mLatencyTracker = latencyTracker;
mTransactionSupplier = supplier;
}
@@ -122,6 +128,13 @@
}
}
+ if (transitionHandled
+ && info.getType()
+ == DesktopModeTransitionTypes
+ .TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON) {
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU);
+ }
+
mPendingTransitionTokens.remove(transition);
return transitionHandled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
index e57b563..b521b2e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
@@ -31,12 +31,14 @@
private val desktopUserRepositories: DesktopUserRepositories,
private val desksOrganizer: DesksOrganizer,
) {
- private val deskTransitions = mutableMapOf<IBinder, DeskTransition>()
+ private val deskTransitions = mutableMapOf<IBinder, MutableSet<DeskTransition>>()
/** Adds a pending desk transition to be tracked. */
fun addPendingTransition(transition: DeskTransition) {
if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
- deskTransitions[transition.token] = transition
+ val transitions = deskTransitions[transition.token] ?: mutableSetOf()
+ transitions += transition
+ deskTransitions[transition.token] = transitions
}
/**
@@ -45,7 +47,11 @@
*/
fun onTransitionReady(transition: IBinder, info: TransitionInfo) {
if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
- val deskTransition = deskTransitions.remove(transition) ?: return
+ val deskTransitions = deskTransitions.remove(transition) ?: return
+ deskTransitions.forEach { deskTransition -> handleDeskTransition(info, deskTransition) }
+ }
+
+ private fun handleDeskTransition(info: TransitionInfo, deskTransition: DeskTransition) {
logD("Desk transition ready: %s", deskTransition)
val desktopRepository = desktopUserRepositories.current
when (deskTransition) {
@@ -60,16 +66,21 @@
deskTransition.onDeskRemovedListener?.onDeskRemoved(displayId, deskId)
}
is DeskTransition.ActivateDesk -> {
- val activeDeskChange =
+ val activateDeskChange =
info.changes.find { change ->
desksOrganizer.isDeskActiveAtEnd(change, deskTransition.deskId)
}
- activeDeskChange?.let {
- desktopRepository.setActiveDesk(
- displayId = deskTransition.displayId,
- deskId = deskTransition.deskId,
- )
+ if (activateDeskChange == null) {
+ // Always activate even if there is no change in the transition for the
+ // activated desk. This is necessary because some activation requests, such as
+ // those involving empty desks, may not contain visibility changes that are
+ // reported in the transition change list.
+ logD("Activating desk without transition change")
}
+ desktopRepository.setActiveDesk(
+ displayId = deskTransition.displayId,
+ deskId = deskTransition.deskId,
+ )
}
is DeskTransition.ActiveDeskWithTask -> {
val withTask =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index cf139a0..d9afd15 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -92,6 +92,7 @@
import com.android.internal.jank.Cuj;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.util.LatencyTracker;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
@@ -260,6 +261,7 @@
private final DesktopModeCompatPolicy mDesktopModeCompatPolicy;
private final DesktopTilingDecorViewModel mDesktopTilingDecorViewModel;
private final MultiDisplayDragMoveIndicatorController mMultiDisplayDragMoveIndicatorController;
+ private final LatencyTracker mLatencyTracker;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -466,6 +468,7 @@
mDesktopTilingDecorViewModel = desktopTilingDecorViewModel;
mDesktopTasksController.setSnapEventHandler(this);
mMultiDisplayDragMoveIndicatorController = multiDisplayDragMoveIndicatorController;
+ mLatencyTracker = LatencyTracker.getInstance(mContext);
shellInit.addInitCallback(this::onInit, this);
}
@@ -764,11 +767,19 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
+ mLatencyTracker.onActionStart(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU);
// App sometimes draws before the insets from WindowDecoration#relayout have
// been added, so they must be added here
decoration.addCaptionInset(wct);
- mDesktopTasksController.moveTaskToDefaultDeskAndActivate(taskId, wct, source,
- /* remoteTransition= */ null, /* moveToDesktopCallback */ null);
+ if (!mDesktopTasksController.moveTaskToDefaultDeskAndActivate(
+ taskId,
+ wct,
+ source,
+ /* remoteTransition= */ null,
+ /* moveToDesktopCallback= */ null)) {
+ mLatencyTracker.onActionCancel(
+ LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU);
+ }
decoration.closeHandleMenu();
if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) {
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 ff9fdd4..93eb396 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
@@ -2780,6 +2780,79 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveToNextDisplay_toDeskInOtherDisplay_movesToDeskAndActivates() {
+ val transition = Binder()
+ val targetDeskId = 4
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = targetDeskId)
+ taskRepository.setDeskInactive(deskId = targetDeskId)
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: second display
+ val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
+ .thenReturn(secondDisplayArea)
+ whenever(transitions.startTransition(eq(TRANSIT_CHANGE), any(), anyOrNull()))
+ .thenReturn(transition)
+
+ val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ taskRepository.addTaskToDesk(
+ displayId = DEFAULT_DISPLAY,
+ deskId = 0,
+ taskId = task.taskId,
+ isVisible = true,
+ )
+ controller.moveToNextDisplay(task.taskId)
+
+ verify(desksOrganizer).moveTaskToDesk(any(), eq(targetDeskId), eq(task))
+ verify(desksOrganizer).activateDesk(any(), eq(targetDeskId))
+ verify(desksTransitionsObserver)
+ .addPendingTransition(
+ DeskTransition.ActiveDeskWithTask(
+ token = transition,
+ displayId = SECOND_DISPLAY,
+ deskId = targetDeskId,
+ enterTaskId = task.taskId,
+ )
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveToNextDisplay_wasLastTaskInSourceDesk_deactivates() {
+ val transition = Binder()
+ val sourceDeskId = 0
+ val targetDeskId = 4
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = targetDeskId)
+ taskRepository.setDeskInactive(deskId = targetDeskId)
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: second display
+ val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
+ .thenReturn(secondDisplayArea)
+ whenever(transitions.startTransition(eq(TRANSIT_CHANGE), any(), anyOrNull()))
+ .thenReturn(transition)
+
+ val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ taskRepository.addTaskToDesk(
+ displayId = DEFAULT_DISPLAY,
+ deskId = sourceDeskId,
+ taskId = task.taskId,
+ isVisible = true,
+ )
+ controller.moveToNextDisplay(task.taskId)
+
+ verify(desksOrganizer).deactivateDesk(any(), eq(sourceDeskId))
+ verify(desksTransitionsObserver)
+ .addPendingTransition(
+ DeskTransition.DeactivateDesk(token = transition, deskId = sourceDeskId)
+ )
+ }
+
+ @Test
fun getTaskWindowingMode() {
val fullscreenTask = setUpFullscreenTask()
val freeformTask = setUpFreeformTask()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
index 4dcf669..409ca57 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
@@ -181,6 +181,23 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_activateDesk_noTransitChange_updatesRepository() {
+ val transition = Binder()
+ val activateTransition =
+ DeskTransition.ActivateDesk(transition, displayId = DEFAULT_DISPLAY, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+
+ observer.addPendingTransition(activateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_TO_FRONT, /* flags= */ 0), // no changes.
+ )
+
+ assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isEqualTo(5)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun onTransitionReady_deactivateDesk_updatesRepository() {
val transition = Binder()
val deskChange = Change(mock(), mock())
@@ -244,4 +261,28 @@
assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isNull()
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_twoPendingTransitions_handlesBoth() {
+ val transition = Binder()
+ // Active one desk and deactivate another in different displays, such as in some
+ // move-to-next-display CUJs.
+ repository.addDesk(displayId = 0, deskId = 1)
+ repository.addDesk(displayId = 1, deskId = 2)
+ repository.setActiveDesk(displayId = 0, deskId = 1)
+ repository.setDeskInactive(2)
+ val activateTransition = DeskTransition.ActivateDesk(transition, displayId = 1, deskId = 2)
+ val deactivateTransition = DeskTransition.DeactivateDesk(transition, deskId = 1)
+
+ observer.addPendingTransition(activateTransition)
+ observer.addPendingTransition(deactivateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0),
+ )
+
+ assertThat(repository.getActiveDeskId(displayId = 0)).isNull()
+ assertThat(repository.getActiveDeskId(displayId = 1)).isEqualTo(2)
+ }
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index f119102..3de8e05 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -312,7 +312,7 @@
};
// Need at least 4 because we do quad buffer. Add a few more for good measure.
- RingBuffer<SwapHistory, 7> mSwapHistory;
+ RingBuffer<SwapHistory, 8> mSwapHistory;
// Frame numbers start at 1, 0 means uninitialized
uint64_t mFrameNumber = 0;
int64_t mDamageId = 0;
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/settingslib_preference_widget_checkbox.xml
similarity index 100%
rename from packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml
rename to packages/SettingsLib/SelectorWithWidgetPreference/res/layout/settingslib_preference_widget_checkbox.xml
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/settingslib_preference_widget_radiobutton.xml
similarity index 100%
rename from packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
rename to packages/SettingsLib/SelectorWithWidgetPreference/res/layout/settingslib_preference_widget_radiobutton.xml
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index 218983a..cde8b33 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -234,9 +234,9 @@
private void init(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
if (mIsCheckBox) {
- setWidgetLayoutResource(R.layout.preference_widget_checkbox);
+ setWidgetLayoutResource(R.layout.settingslib_preference_widget_checkbox);
} else {
- setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+ setWidgetLayoutResource(R.layout.settingslib_preference_widget_radiobutton);
}
setLayoutResource(R.layout.preference_selector_with_widget);
setIconSpaceReserved(false);
diff --git a/packages/SettingsLib/res/layout-v33/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout-v33/preference_checkable_two_target.xml
index 7ad018c..60d03e3 100644
--- a/packages/SettingsLib/res/layout-v33/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout-v33/preference_checkable_two_target.xml
@@ -47,7 +47,7 @@
android:clipToPadding="false"
android:paddingTop="4dp"
android:paddingBottom="4dp">
- <include layout="@layout/preference_widget_checkbox" />
+ <include layout="@layout/settingslib_preference_widget_checkbox" />
</LinearLayout>
<RelativeLayout
diff --git a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
index f512f9b..ab7b04b 100644
--- a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
@@ -47,7 +47,7 @@
android:clipToPadding="false"
android:paddingTop="4dp"
android:paddingBottom="4dp">
- <include layout="@layout/preference_widget_checkbox" />
+ <include layout="@layout/settingslib_preference_widget_checkbox" />
</LinearLayout>
<RelativeLayout
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
index c939c77..5076dea 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
@@ -78,14 +78,14 @@
@Test
public void shouldHaveRadioButtonWidgetLayoutByDefault() {
assertThat(mPreference.getWidgetLayoutResource())
- .isEqualTo(R.layout.preference_widget_radiobutton);
+ .isEqualTo(R.layout.settingslib_preference_widget_radiobutton);
}
@Test
public void shouldHaveCheckBoxWidgetLayoutIfSet() {
mPreference = new SelectorWithWidgetPreference(mContext, true);
assertThat(mPreference.getWidgetLayoutResource())
- .isEqualTo(R.layout.preference_widget_checkbox);
+ .isEqualTo(R.layout.settingslib_preference_widget_checkbox);
}
@Test
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 9b76f15..4e1aab5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -282,6 +282,7 @@
CommunalBackgroundType.ANIMATED -> AnimatedLinearGradient()
CommunalBackgroundType.NONE -> BackgroundTopScrim()
CommunalBackgroundType.BLUR -> Background()
+ CommunalBackgroundType.SCRIM -> Scrimmed()
}
with(content) {
@@ -304,6 +305,11 @@
Box(modifier = Modifier.matchParentSize().background(Color(backgroundColor.toArgb())))
}
+@Composable
+private fun BoxScope.Scrimmed() {
+ Box(modifier = Modifier.matchParentSize().alpha(0.34f).background(Color.Black))
+}
+
/** Experimental hub background, static linear gradient */
@Composable
private fun BoxScope.StaticLinearGradient() {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
index 52ccab3..ec7e495 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
@@ -70,33 +70,29 @@
key = if (isStart) StartButtonElementKey else EndButtonElementKey,
modifier = modifier,
) {
- content {
- Shortcut(
- viewId = if (isStart) R.id.start_button else R.id.end_button,
- viewModel = if (isStart) viewModel.startButton else viewModel.endButton,
- transitionAlpha = viewModel.transitionAlpha,
- indicationController = indicationController,
- binder = keyguardQuickAffordanceViewBinder,
- modifier =
- if (applyPadding) {
- Modifier.shortcutPadding()
- } else {
- Modifier
- },
- )
- }
+ Shortcut(
+ viewId = if (isStart) R.id.start_button else R.id.end_button,
+ viewModel = if (isStart) viewModel.startButton else viewModel.endButton,
+ transitionAlpha = viewModel.transitionAlpha,
+ indicationController = indicationController,
+ binder = keyguardQuickAffordanceViewBinder,
+ modifier =
+ if (applyPadding) {
+ Modifier.shortcutPadding()
+ } else {
+ Modifier
+ },
+ )
}
}
@Composable
fun ContentScope.IndicationArea(modifier: Modifier = Modifier) {
Element(key = IndicationAreaElementKey, modifier = modifier.indicationAreaPadding()) {
- content {
- IndicationArea(
- indicationAreaViewModel = indicationAreaViewModel,
- indicationController = indicationController,
- )
- }
+ IndicationArea(
+ indicationAreaViewModel = indicationAreaViewModel,
+ indicationController = indicationController,
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index ae541dd..0583e8a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -26,11 +26,9 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.key
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
-import androidx.core.view.contains
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
@@ -132,18 +130,16 @@
}
Element(key = largeClockElementKey, modifier = modifier) {
- content {
- ClockView(
- checkNotNull(currentClock).largeClock.view,
- modifier =
- Modifier.fillMaxSize()
- .burnInAware(
- viewModel = aodBurnInViewModel,
- params = burnInParams,
- isClock = true,
- ),
- )
- }
+ ClockView(
+ checkNotNull(currentClock).largeClock.view,
+ modifier =
+ Modifier.fillMaxSize()
+ .burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ isClock = true,
+ ),
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
index c3ba7ab..c7b797d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
@@ -66,64 +66,61 @@
val resources = LocalContext.current.resources
Element(key = ClockElementKeys.smartspaceElementKey, modifier = modifier) {
- content {
- Column(
- modifier =
- modifier
- .onTopPlacementChanged(onTopChanged)
- .padding(
- top = { smartSpacePaddingTop(resources) },
- bottom = {
- resources.getDimensionPixelSize(
- R.dimen.keyguard_status_view_bottom_margin
- )
- },
- )
- ) {
- if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) {
- return@Column
- }
+ Column(
+ modifier =
+ modifier
+ .onTopPlacementChanged(onTopChanged)
+ .padding(
+ top = { smartSpacePaddingTop(resources) },
+ bottom = {
+ resources.getDimensionPixelSize(
+ R.dimen.keyguard_status_view_bottom_margin
+ )
+ },
+ )
+ ) {
+ if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) {
+ return@Column
+ }
- val paddingBelowClockStart =
- dimensionResource(R.dimen.below_clock_padding_start)
- val paddingBelowClockEnd = dimensionResource(R.dimen.below_clock_padding_end)
- val paddingCardHorizontal = paddingBelowClockEnd
+ val paddingBelowClockStart = dimensionResource(R.dimen.below_clock_padding_start)
+ val paddingBelowClockEnd = dimensionResource(R.dimen.below_clock_padding_end)
+ val paddingCardHorizontal = paddingBelowClockEnd
- if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- modifier =
- Modifier.fillMaxWidth()
- // All items will be constrained to be as tall as the shortest
- // item.
- .height(IntrinsicSize.Min)
- .padding(start = paddingBelowClockStart),
- ) {
- Date(
- modifier =
- Modifier.burnInAware(
- viewModel = aodBurnInViewModel,
- params = burnInParams,
- )
- )
- Spacer(modifier = Modifier.width(4.dp))
- Weather(
- modifier =
- Modifier.burnInAware(
- viewModel = aodBurnInViewModel,
- params = burnInParams,
- )
- )
- }
- }
-
- Card(
+ if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
modifier =
Modifier.fillMaxWidth()
- .padding(start = paddingCardHorizontal, end = paddingCardHorizontal)
- .burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
- )
+ // All items will be constrained to be as tall as the shortest
+ // item.
+ .height(IntrinsicSize.Min)
+ .padding(start = paddingBelowClockStart),
+ ) {
+ Date(
+ modifier =
+ Modifier.burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ )
+ )
+ Spacer(modifier = Modifier.width(4.dp))
+ Weather(
+ modifier =
+ Modifier.burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ )
+ )
+ }
}
+
+ Card(
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(start = paddingCardHorizontal, end = paddingCardHorizontal)
+ .burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
+ )
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index 4fcb5ca..a8b2b13 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -24,7 +24,6 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
@@ -109,14 +108,10 @@
modifier: Modifier = Modifier,
) {
Element(key = elementKey, modifier) {
- content {
- ClockView(
- clock.largeClock.layout.views.firstOrNull {
- it.id == weatherClockElementViewId
- },
- modifier,
- )
- }
+ ClockView(
+ clock.largeClock.layout.views.firstOrNull { it.id == weatherClockElementViewId },
+ modifier,
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 9c85c96..60c01722 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -116,11 +116,9 @@
QuickSettingsTheme {
// This view has its own horizontal padding
// TODO(b/321716470) This should use a lifecycle tied to the scene.
- FooterActions(
- viewModel = viewModel,
- qsVisibilityLifecycleOwner = lifecycleOwner,
- modifier = Modifier.element(QuickSettings.Elements.FooterActions),
- )
+ Element(QuickSettings.Elements.FooterActions, Modifier) {
+ FooterActions(viewModel = viewModel, qsVisibilityLifecycleOwner = lifecycleOwner)
+ }
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index db9035b..23baeac 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -440,33 +440,36 @@
private fun ContentScope.Clock(scale: Float, onClick: () -> Unit, modifier: Modifier = Modifier) {
val layoutDirection = LocalLayoutDirection.current
- Element(key = ShadeHeader.Elements.Clock, modifier = modifier) {
+ ElementWithValues(key = ShadeHeader.Elements.Clock, modifier = modifier) {
val animatedScale by animateElementFloatAsState(scale, ClockScale, canOverflow = false)
- AndroidView(
- factory = { context ->
- Clock(
- ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header),
- null,
- )
- },
- modifier =
- modifier
- // use graphicsLayer instead of Modifier.scale to anchor transform
- // to the (start, top) corner
- .graphicsLayer {
- scaleX = animatedScale
- scaleY = animatedScale
- transformOrigin =
- TransformOrigin(
- when (layoutDirection) {
- LayoutDirection.Ltr -> 0f
- LayoutDirection.Rtl -> 1f
- },
- 0.5f,
- )
- }
- .clickable { onClick() },
- )
+
+ content {
+ AndroidView(
+ factory = { context ->
+ Clock(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header),
+ null,
+ )
+ },
+ modifier =
+ modifier
+ // use graphicsLayer instead of Modifier.scale to anchor transform to the
+ // (start, top) corner
+ .graphicsLayer {
+ scaleX = animatedScale
+ scaleY = animatedScale
+ transformOrigin =
+ TransformOrigin(
+ when (layoutDirection) {
+ LayoutDirection.Ltr -> 0f
+ LayoutDirection.Rtl -> 1f
+ },
+ 0.5f,
+ )
+ }
+ .clickable { onClick() },
+ )
+ }
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index f4af5f0..eab5206 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -35,6 +35,21 @@
sceneOrOverlay: Content,
key: ElementKey,
modifier: Modifier,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ Box(
+ modifier.element(layoutImpl, sceneOrOverlay, key),
+ propagateMinConstraints = true,
+ content = content,
+ )
+}
+
+@Composable
+internal fun ElementWithValues(
+ layoutImpl: SceneTransitionLayoutImpl,
+ sceneOrOverlay: Content,
+ key: ElementKey,
+ modifier: Modifier,
content: @Composable ElementScope<ElementContentScope>.() -> Unit,
) {
Box(modifier.element(layoutImpl, sceneOrOverlay, key), propagateMinConstraints = true) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index f423bab..53d0ee1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -22,6 +22,7 @@
import androidx.compose.foundation.OverscrollEffect
import androidx.compose.foundation.OverscrollFactory
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
@@ -188,7 +189,7 @@
* Additionally, this [key] will be used to detect elements that are shared between contents to
* automatically interpolate their size and offset. If you need to animate shared element values
* (i.e. values associated to this element that change depending on which content it is composed
- * in), use [Element] instead.
+ * in), use [ElementWithValues] instead.
*
* Note that shared elements tagged using this function will be duplicated in each content they
* are part of, so any **internal** state (e.g. state created using `remember {
@@ -196,9 +197,12 @@
* [MovableElement] instead.
*
* @see Element
+ * @see ElementWithValues
* @see MovableElement
*/
- fun Modifier.element(key: ElementKey): Modifier
+ // TODO(b/389985793): Does replacing this by Element have a noticeable impact on performance and
+ // should we deprecate it?
+ @Stable fun Modifier.element(key: ElementKey): Modifier
/**
* Create an element identified by [key].
@@ -207,17 +211,29 @@
* in multiple contents and that can be transformed during transitions, the same way that
* [element] does.
*
- * The only difference with [element] is that the provided [ElementScope] allows you to
- * [animate element values][ElementScope.animateElementValueAsState] or specify its
- * [movable content][Element.movableContent] that will be "moved" and composed only once during
- * transitions (as opposed to [element] that duplicates shared elements) so that any internal
- * state is preserved during and after the transition.
+ * The only difference with [element] is that [Element] introduces its own recomposition scope
+ * and layout node, which can be helpful to avoid expensive recompositions when a transition is
+ * started or finished (see b/389985793#comment103 for details).
*
* @see element
+ * @see ElementWithValues
* @see MovableElement
*/
@Composable
- fun Element(
+ fun Element(key: ElementKey, modifier: Modifier, content: @Composable BoxScope.() -> Unit)
+
+ /**
+ * Create an element identified by [key].
+ *
+ * The only difference with [Element] is that the provided [ElementScope] allows you to
+ * [animate element values][ElementScope.animateElementValueAsState].
+ *
+ * @see element
+ * @see Element
+ * @see MovableElement
+ */
+ @Composable
+ fun ElementWithValues(
key: ElementKey,
modifier: Modifier,
@@ -230,17 +246,19 @@
/**
* Create a *movable* element identified by [key].
*
- * Similar to [Element], this creates an element that will be automatically shared when present
- * in multiple contents and that can be transformed during transitions, and you can also use the
- * provided [ElementScope] to [animate element values][ElementScope.animateElementValueAsState].
+ * Similar to [ElementWithValues], this creates an element that will be automatically shared
+ * when present in multiple contents and that can be transformed during transitions, and you can
+ * also use the provided [ElementScope] to
+ * [animate element values][ElementScope.animateElementValueAsState].
*
- * The important difference with [element] and [Element] is that this element
- * [content][ElementScope.content] will be "moved" and composed only once during transitions, as
- * opposed to [element] and [Element] that duplicates shared elements, so that any internal
- * state is preserved during and after the transition.
+ * The important difference with [element], [Element] and [ElementWithValues] is that this
+ * element [content][ElementScope.content] will be "moved" and composed only once during
+ * transitions, as opposed to [element], [Element] and [ElementWithValues] that duplicates
+ * shared elements, so that any internal state is preserved during and after the transition.
*
* @see element
* @see Element
+ * @see ElementWithValues
*/
@Composable
fun MovableElement(
@@ -415,7 +433,7 @@
*
* We can't reuse BoxScope directly because of the @LayoutScopeMarker annotation on it, which would
* prevent us from calling Modifier.element() and other methods of [ContentScope] inside any Box {}
- * in the [content][ElementScope.content] of a [ContentScope.Element] or a
+ * in the [content][ElementScope.content] of a [ContentScope.ElementWithValues] or a
* [ContentScope.MovableElement].
*/
@Stable
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 95d6440..9ca45fe 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -21,6 +21,7 @@
import androidx.compose.foundation.OverscrollEffect
import androidx.compose.foundation.OverscrollFactory
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
@@ -45,6 +46,7 @@
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementScope
import com.android.compose.animation.scene.ElementStateScope
+import com.android.compose.animation.scene.ElementWithValues
import com.android.compose.animation.scene.InternalContentScope
import com.android.compose.animation.scene.MovableElement
import com.android.compose.animation.scene.MovableElementContentScope
@@ -222,12 +224,21 @@
override fun Element(
key: ElementKey,
modifier: Modifier,
- content: @Composable (ElementScope<ElementContentScope>.() -> Unit),
+ content: @Composable BoxScope.() -> Unit,
) {
Element(layoutImpl, this@ContentScopeImpl.content, key, modifier, content)
}
@Composable
+ override fun ElementWithValues(
+ key: ElementKey,
+ modifier: Modifier,
+ content: @Composable (ElementScope<ElementContentScope>.() -> Unit),
+ ) {
+ ElementWithValues(layoutImpl, this@ContentScopeImpl.content, key, modifier, content)
+ }
+
+ @Composable
override fun MovableElement(
key: MovableElementKey,
modifier: Modifier,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
index d11e6da1..d06e040 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
@@ -67,7 +67,7 @@
@Composable
private fun ContentScope.Foo(targetValues: Values, onCurrentValueChanged: (Values) -> Unit) {
val key = TestElements.Foo
- Element(key, Modifier) {
+ ElementWithValues(key, Modifier) {
val int by animateElementIntAsState(targetValues.int, key = TestValues.Value1)
val float by animateElementFloatAsState(targetValues.float, key = TestValues.Value2)
val dp by animateElementDpAsState(targetValues.dp, key = TestValues.Value3)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 698a808..338fb9b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -1163,7 +1163,7 @@
@Composable
fun ContentScope.Foo(size: Dp, value: Float, modifier: Modifier = Modifier) {
val contentKey = this.contentKey
- Element(TestElements.Foo, modifier.size(size)) {
+ ElementWithValues(TestElements.Foo, modifier.size(size)) {
val animatedValue = animateElementFloatAsState(value, TestValues.Value1)
LaunchedEffect(animatedValue) {
snapshotFlow { animatedValue.value }.collect { lastValues[contentKey] = it }
@@ -2090,11 +2090,9 @@
TestContentScope(currentScene = SceneA) {
Column {
Element(TestElements.Foo, Modifier.size(40.dp)) {
- content {
- // Modifier.size() sets a preferred size and this should be ignored
- // because of the previously set 40dp size.
- Box(Modifier.testTag(contentTestTag).size(20.dp))
- }
+ // Modifier.size() sets a preferred size and this should be ignored because
+ // of the previously set 40dp size.
+ Box(Modifier.testTag(contentTestTag).size(20.dp))
}
MovableElement(movable, Modifier.size(40.dp)) {
@@ -2283,4 +2281,35 @@
.assertSizeIsEqualTo(50.dp)
.assertPositionInRootIsEqualTo(100.dp, 100.dp)
}
+
+ @Test
+ fun elementContentIsNotRecomposedWhenATransitionStarts() {
+ var compositions = 0
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateForTests(SceneA) }
+ val scope =
+ rule.setContentAndCreateMainScope {
+ SceneTransitionLayoutForTesting(state) {
+ scene(SceneA) {
+ Box(Modifier.fillMaxSize()) {
+ Element(TestElements.Foo, Modifier) { SideEffect { compositions++ } }
+ }
+ }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
+ scene(SceneC) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(compositions).isEqualTo(1)
+
+ scope.launch { state.startTransition(transition(SceneA, SceneB)) }
+ rule.waitForIdle()
+
+ scope.launch { state.startTransition(transition(SceneA, SceneC)) }
+ rule.waitForIdle()
+
+ scope.launch { state.startTransition(transition(SceneA, SceneB)) }
+ rule.waitForIdle()
+
+ assertThat(compositions).isEqualTo(1)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index e023936..ebbde70 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -313,7 +313,7 @@
fun elementScopeExtendsBoxScope() {
rule.setContent {
TestContentScope {
- Element(TestElements.Foo, Modifier.size(200.dp)) {
+ ElementWithValues(TestElements.Foo, Modifier.size(200.dp)) {
content {
Box {
Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 3578be4..d7f7a51 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -129,7 +129,7 @@
@Composable
private fun ContentScope.SharedFoo(size: Dp, childOffset: Dp, modifier: Modifier = Modifier) {
- Element(TestElements.Foo, modifier.size(size).background(Color.Red)) {
+ ElementWithValues(TestElements.Foo, modifier.size(size).background(Color.Red)) {
// Offset the single child of Foo by some animated shared offset.
val offset by animateElementDpAsState(childOffset, TestValues.Value1)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
deleted file mode 100644
index 052dfd5..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.keyguard.ui.viewmodel
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.kosmos.collectValues
-import com.android.systemui.kosmos.runTest
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class DozingToDreamingTransitionViewModelTest : SysuiTestCase() {
- val kosmos = testKosmos()
-
- val underTest by lazy { kosmos.dozingToDreamingTransitionViewModel }
-
- @Test
- fun notificationShadeAlpha() =
- kosmos.runTest {
- val values by collectValues(underTest.notificationAlpha)
- assertThat(values).isEmpty()
-
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.DOZING,
- to = KeyguardState.DREAMING,
- testScope,
- )
-
- assertThat(values).isNotEmpty()
- values.forEach { assertThat(it).isEqualTo(0) }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index c10fd5e..326d8ff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -19,7 +19,6 @@
import android.os.IBinder
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.platform.test.annotations.RequiresFlagsDisabled
import android.testing.TestableLooper.RunWithLooper
import android.view.Choreographer
import android.view.View
@@ -360,7 +359,7 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_NOTIFICATION_SHADE_BLUR)
+ @DisableFlags(Flags.FLAG_NOTIFICATION_SHADE_BLUR)
fun updateBlurCallback_setsOpaque_whenScrim() {
scrimVisibilityCaptor.value.accept(ScrimController.OPAQUE)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt
index 0f25225..c6708d4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.communal.data.repository
import com.android.systemui.Flags.glanceableHubBlurredBackground
+import com.android.systemui.Flags.glanceableHubV2
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import dagger.Binds
import dagger.Module
@@ -35,6 +36,10 @@
return CommunalBackgroundType.BLUR
}
+ if (glanceableHubV2()) {
+ return CommunalBackgroundType.SCRIM
+ }
+
return CommunalBackgroundType.ANIMATED
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt
index e1128ed..a84fa79 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt
@@ -17,10 +17,11 @@
package com.android.systemui.communal.shared.model
/** Models the types of background that can be shown on the hub. */
-enum class CommunalBackgroundType(val value: Int) {
- STATIC(0),
- STATIC_GRADIENT(1),
- ANIMATED(2),
- NONE(3),
- BLUR(4),
+enum class CommunalBackgroundType(val value: Int, val opaque: Boolean) {
+ STATIC(value = 0, opaque = true),
+ STATIC_GRADIENT(value = 1, opaque = true),
+ ANIMATED(value = 2, opaque = true),
+ NONE(value = 3, opaque = false),
+ BLUR(value = 4, opaque = false),
+ SCRIM(value = 5, opaque = false),
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
index 0cbbfd4..db5c7eb 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
@@ -19,6 +19,7 @@
import android.graphics.Color
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.communal.util.CommunalColors
import com.android.systemui.dagger.SysUISingleton
@@ -40,6 +41,7 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -60,6 +62,7 @@
glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel,
communalInteractor: CommunalInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
+ communalSettingsInteractor: CommunalSettingsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
) {
/**
@@ -146,13 +149,16 @@
}
val recentsBackgroundColor: Flow<Color?> =
- combine(showCommunalFromOccluded, communalColors.backgroundColor) {
- showCommunalFromOccluded,
- backgroundColor ->
- if (showCommunalFromOccluded) {
- backgroundColor
- } else {
- null
+ combine(
+ showCommunalFromOccluded,
+ communalColors.backgroundColor,
+ communalSettingsInteractor.communalBackground,
+ ) { showCommunalFromOccluded, backgroundColor, backgroundType ->
+ if (showCommunalFromOccluded && backgroundType.opaque) {
+ backgroundColor
+ } else {
+ null
+ }
}
- }
+ .distinctUntilChanged()
}
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 0700ec6..6f5f662 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
@@ -159,7 +159,6 @@
val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value
val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value
val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value
- val canStartDreaming = dreamManager.canStartDreaming(false)
if (!deviceEntryInteractor.isLockscreenEnabled()) {
if (!SceneContainerFlag.isEnabled) {
@@ -192,13 +191,6 @@
if (!SceneContainerFlag.isEnabled) {
transitionToGlanceableHub()
}
- } else if (canStartDreaming) {
- // If we're waking up to dream, transition directly to dreaming without
- // showing the lockscreen.
- startTransitionTo(
- KeyguardState.DREAMING,
- ownerReason = "moving from doze to dream",
- )
} else {
startTransitionTo(KeyguardState.LOCKSCREEN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
index 9018c58..e6a85c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
@@ -39,6 +39,4 @@
)
val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f)
- // Notifications should not be shown while transitioning to dream.
- val notificationAlpha = transitionAnimation.immediatelyTransitionTo(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 6ad8bae..71eacdf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -312,20 +312,18 @@
SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) {
scene(QuickSettings) {
LaunchedEffect(Unit) { viewModel.onQSOpen() }
- QuickSettingsElement(Modifier.element(QuickSettings.rootElementKey))
+ Element(QuickSettings.rootElementKey, Modifier) { QuickSettingsElement() }
}
scene(QuickQuickSettings) {
LaunchedEffect(Unit) { viewModel.onQQSOpen() }
// Cannot pass the element modifier in because the top element has a `testTag`
// and this would overwrite it.
- Box(Modifier.element(QuickQuickSettings.rootElementKey)) {
- QuickQuickSettingsElement()
- }
+ Element(QuickQuickSettings.rootElementKey, Modifier) { QuickQuickSettingsElement() }
}
scene(SceneKeys.EditMode) {
- EditModeElement(Modifier.element(SceneKeys.EditMode.rootElementKey))
+ Element(SceneKeys.EditMode.rootElementKey, Modifier) { EditModeElement() }
}
}
}
@@ -656,10 +654,7 @@
)
) {
if (viewModel.isQsEnabled) {
- Box(
- modifier =
- Modifier.element(ElementKeys.QuickSettingsContent).fillMaxSize().weight(1f)
- ) {
+ Element(ElementKeys.QuickSettingsContent, modifier = Modifier.weight(1f)) {
DisposableEffect(Unit) {
lifecycleScope.launch { scrollState.scrollTo(0) }
onDispose { lifecycleScope.launch { scrollState.scrollTo(0) } }
@@ -667,7 +662,8 @@
Column(
modifier =
- Modifier.onPlaced { coordinates ->
+ Modifier.fillMaxSize()
+ .onPlaced { coordinates ->
val positionOnScreen = coordinates.positionOnScreen()
val left = positionOnScreen.x
val right = left + coordinates.size.width
@@ -744,13 +740,15 @@
}
}
QuickSettingsTheme {
- FooterActions(
- viewModel = viewModel.footerActionsViewModel,
- qsVisibilityLifecycleOwner = this@QSFragmentCompose,
- modifier =
- Modifier.sysuiResTag(ResIdTags.qsFooterActions)
- .element(ElementKeys.FooterActions),
- )
+ Element(
+ ElementKeys.FooterActions,
+ Modifier.sysuiResTag(ResIdTags.qsFooterActions),
+ ) {
+ FooterActions(
+ viewModel = viewModel.footerActionsViewModel,
+ qsVisibilityLifecycleOwner = this@QSFragmentCompose,
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt
index 266e875..19ad9fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.composefragment.ui
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.android.compose.animation.scene.ContentScope
@@ -29,5 +28,5 @@
@Composable
fun ContentScope.GridAnchor(modifier: Modifier = Modifier) {
// The size of this anchor does not matter, as the tiles don't change size on expansion.
- Spacer(modifier.element(ElementKeys.GridAnchor))
+ Element(ElementKeys.GridAnchor, modifier) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index b084f79..495870f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -71,17 +71,19 @@
val it = sizedTiles[spanIndex]
val column = cellIndex % columns
cellIndex += it.width
- Tile(
- tile = it.tile,
- iconOnly = it.isIcon,
- modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
- squishiness = { squishiness },
- coroutineScope = scope,
- bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
- tileHapticsViewModelFactoryProvider = viewModel.tileHapticsViewModelFactoryProvider,
- // There should be no QuickQuickSettings when the details view is enabled.
- detailsViewModel = null,
- )
+ Element(it.tile.spec.toElementKey(spanIndex), Modifier) {
+ Tile(
+ tile = it.tile,
+ iconOnly = it.isIcon,
+ squishiness = { squishiness },
+ coroutineScope = scope,
+ bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
+ tileHapticsViewModelFactoryProvider =
+ viewModel.tileHapticsViewModelFactoryProvider,
+ // There should be no QuickQuickSettings when the details view is enabled.
+ detailsViewModel = null,
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 1c540ee..dfee4976 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -99,16 +99,17 @@
val it = sizedTiles[spanIndex]
val column = cellIndex % columns
cellIndex += it.width
- Tile(
- tile = it.tile,
- iconOnly = iconTilesViewModel.isIconTile(it.tile.spec),
- modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
- squishiness = { squishiness },
- tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider,
- coroutineScope = scope,
- bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
- detailsViewModel = detailsViewModel,
- )
+ Element(it.tile.spec.toElementKey(spanIndex), Modifier) {
+ Tile(
+ tile = it.tile,
+ iconOnly = iconTilesViewModel.isIconTile(it.tile.spec),
+ squishiness = { squishiness },
+ tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider,
+ coroutineScope = scope,
+ bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
+ detailsViewModel = detailsViewModel,
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 877aa76..33cc62c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -50,7 +50,6 @@
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel
-import com.android.systemui.keyguard.ui.viewmodel.DozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel
@@ -144,7 +143,6 @@
private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel,
private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel,
private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel,
- private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel: DozingToGlanceableHubTransitionViewModel,
private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
private val dozingToOccludedTransitionViewModel: DozingToOccludedTransitionViewModel,
@@ -603,7 +601,6 @@
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState),
aodToPrimaryBouncerTransitionViewModel.notificationAlpha,
- dozingToDreamingTransitionViewModel.notificationAlpha,
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState),
dozingToPrimaryBouncerTransitionViewModel.notificationAlpha,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
index 7b0c09c..9109b36 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
@@ -18,6 +18,7 @@
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.util.communalColors
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.dreamingToGlanceableHubTransitionViewModel
@@ -41,5 +42,6 @@
communalSceneInteractor = communalSceneInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
communalColors = communalColors,
+ communalSettingsInteractor = communalSettingsInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 51bb94f..17ef208 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -30,7 +30,6 @@
import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToPrimaryBouncerTransitionViewModel
-import com.android.systemui.keyguard.ui.viewmodel.dozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToOccludedTransitionViewModel
@@ -84,7 +83,6 @@
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel,
aodToPrimaryBouncerTransitionViewModel = aodToPrimaryBouncerTransitionViewModel,
- dozingToDreamingTransitionViewModel = dozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel = dozingToGlanceableHubTransitionViewModel,
dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
dozingToOccludedTransitionViewModel = dozingToOccludedTransitionViewModel,
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
index aa82df4..9ee7ec9 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
@@ -230,6 +230,11 @@
return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused();
}
+ @VisibleForTesting
+ void onChangeForTesting(boolean selfChange, Uri uri) {
+ mAutoclickSettingsObserver.onChange(selfChange, uri);
+ }
+
/**
* Observes autoclick setting values, and updates ClickScheduler delay and indicator size
* whenever the setting value changes.
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 2af74f6..7e8bb28 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -569,8 +569,7 @@
}
private void requestDreamInternal() {
- if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()
- && !isDozingInternal()) {
+ if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) {
return;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 980fb155..d11f5e7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1163,15 +1163,6 @@
}
}
- private boolean shouldShowHub() {
- final boolean hubEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
- 1, mCurrentUserId) == 1;
-
- return mUserManagerInternal != null && mUserManagerInternal.isUserUnlocked(mCurrentUserId)
- && hubEnabled && mDreamManagerInternal.dreamConditionActive();
- }
-
@VisibleForTesting
void powerPress(long eventTime, int count, int displayId) {
// SideFPS still needs to know about suppressed power buttons, in case it needs to block
@@ -1260,8 +1251,7 @@
mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
1, mCurrentUserId) == 1;
- if ((mDreamManagerInternal != null && mDreamManagerInternal.isDreaming())
- || isKeyguardShowing()) {
+ if (mDreamManagerInternal.isDreaming() || isKeyguardShowing()) {
// If the device is already dreaming or on keyguard, go to sleep.
sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
@@ -1271,10 +1261,9 @@
// show hub.
boolean keyguardAvailable = !mLockPatternUtils.isLockScreenDisabled(
mCurrentUserId);
- if (shouldShowHub() && keyguardAvailable) {
- // If the hub can be launched, send a message to keyguard. We do not know if
- // the hub is already running or not, keyguard handles turning screen off if
- // it is.
+ if (mUserManagerInternal.isUserUnlocked(mCurrentUserId) && hubEnabled
+ && keyguardAvailable && mDreamManagerInternal.dreamConditionActive()) {
+ // If the hub can be launched, send a message to keyguard.
Bundle options = new Bundle();
options.putBoolean(EXTRA_TRIGGER_HUB, true);
lockNow(options);
@@ -1335,14 +1324,14 @@
* @param isScreenOn Whether the screen is currently on.
* @param noDreamAction The action to perform if dreaming is not possible.
*/
- private boolean attemptToDreamFromShortPowerButtonPress(
+ private void attemptToDreamFromShortPowerButtonPress(
boolean isScreenOn, Runnable noDreamAction) {
if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP
&& mShortPressOnPowerBehavior != SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP) {
// If the power button behavior isn't one that should be able to trigger the dream, give
// up.
noDreamAction.run();
- return false;
+ return;
}
final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
@@ -1350,7 +1339,7 @@
Slog.d(TAG, "Can't start dreaming when attempting to dream from short power"
+ " press (isScreenOn=" + isScreenOn + ")");
noDreamAction.run();
- return false;
+ return;
}
synchronized (mLock) {
@@ -1361,8 +1350,6 @@
}
dreamManagerInternal.requestDream();
-
- return true;
}
/**
@@ -2340,10 +2327,6 @@
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return new WindowWakeUpPolicy(mContext);
}
-
- DreamManagerInternal getDreamManagerInternal() {
- return LocalServices.getService(DreamManagerInternal.class);
- }
}
/** {@inheritDoc} */
@@ -2362,7 +2345,7 @@
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mInputManager = mContext.getSystemService(InputManager.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mDreamManagerInternal = injector.getDreamManagerInternal();
+ mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class);
@@ -6409,17 +6392,6 @@
event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) {
return;
}
-
- if (!shouldShowHub()
- && mShortPressOnPowerBehavior == SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP
- && event.getKeyCode() == KEYCODE_POWER
- && attemptToDreamFromShortPowerButtonPress(false, () -> {})) {
- // In the case that we should wake to dream and successfully initiate dreaming, do not
- // continue waking up. Doing so will exit the dream state and cause UI to react
- // accordingly.
- return;
- }
-
wakeUpFromWakeKey(
event.getEventTime(),
event.getKeyCode(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
index 0745c68..17d8882 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
@@ -41,6 +41,7 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.server.accessibility.AccessibilityTraceManager;
import org.junit.After;
@@ -79,7 +80,9 @@
@After
public void tearDown() {
+ mController.onDestroy();
mTestableLooper.processAllMessages();
+ TestableLooper.remove(this);
}
@Test
@@ -403,6 +406,133 @@
@Test
@EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void onCursorAreaSizeSettingsChange_moveWithinCustomRadius_clickNotTriggered() {
+ // Move mouse to initialize autoclick panel before enabling ignore minor cursor movement.
+ injectFakeMouseActionHoverMoveEvent();
+ enableIgnoreMinorCursorMovement();
+
+ // Set a custom cursor area size.
+ int customSize = 250;
+ Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
+ customSize,
+ mTestableContext.getUserId());
+ mController.onChangeForTesting(/* selfChange= */ true,
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE));
+ assertThat(mController.mAutoclickIndicatorView.getRadiusForTesting()).isEqualTo(customSize);
+
+ // Move the mouse down, less than customSize radius so a click is not triggered.
+ float moveDownY = customSize - 25;
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 150,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 0f,
+ /* y= */ moveDownY,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void onCursorAreaSizeSettingsChange_moveOutsideCustomRadius_clickTriggered() {
+ // Move mouse to initialize autoclick panel before enabling ignore minor cursor movement.
+ injectFakeMouseActionHoverMoveEvent();
+ enableIgnoreMinorCursorMovement();
+
+ // Set a custom cursor area size.
+ int customSize = 250;
+ Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
+ customSize,
+ mTestableContext.getUserId());
+ mController.onChangeForTesting(/* selfChange= */ true,
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE));
+ assertThat(mController.mAutoclickIndicatorView.getRadiusForTesting()).isEqualTo(customSize);
+
+ // Move the mouse right, greater than customSize radius so a click is triggered.
+ float moveRightX = customSize + 100;
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 200,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ moveRightX,
+ /* y= */ 0,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void onIgnoreCursorMovementFromSettingsChange_clickTriggered() {
+ // Send initial mouse movement.
+ injectFakeMouseActionHoverMoveEvent();
+
+ // Set a custom cursor area size.
+ int customSize = 250;
+ Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
+ customSize,
+ mTestableContext.getUserId());
+ mController.onChangeForTesting(/* selfChange= */ true,
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE));
+
+ // Move the mouse down less than customSize radius but ignore custom movement is not enabled
+ // so a click is triggered.
+ float moveDownY = customSize - 100;
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 150,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 0f,
+ /* y= */ moveDownY,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void onIgnoreCursorMovementFromSettingsChange_clickNotTriggered() {
+ // Move mouse to initialize autoclick panel before enabling ignore minor cursor movement.
+ injectFakeMouseActionHoverMoveEvent();
+ enableIgnoreMinorCursorMovement();
+
+ // Set a custom cursor area size.
+ int customSize = 250;
+ Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
+ customSize,
+ mTestableContext.getUserId());
+ mController.onChangeForTesting(/* selfChange= */ true,
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE));
+
+ // After enabling ignore custom movement, move the mouse right, less than customSize radius
+ // so a click won't be triggered.
+ float moveRightX = customSize - 100;
+ MotionEvent hoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 200,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ moveRightX,
+ /* y= */ 0,
+ /* metaState= */ 0);
+ hoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
+ assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
public void pauseButton_flagOn_clickNotTriggeredWhenPaused() {
injectFakeMouseActionHoverMoveEvent();
@@ -473,4 +603,14 @@
/* y= */ 0,
/* metaState= */ 0);
}
+
+ private void enableIgnoreMinorCursorMovement() {
+ Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT,
+ AccessibilityUtils.State.ON,
+ mTestableContext.getUserId());
+ mController.onChangeForTesting(/* selfChange= */ true,
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index 22c86eb..32a3b7f 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -272,19 +272,6 @@
}
@Test
- public void powerPress_withoutDreamManagerInternal_doesNotCrash() {
- when(mDisplayPolicy.isAwake()).thenReturn(true);
- mDreamManagerInternal = null;
- initPhoneWindowManager();
-
- // Power button pressed.
- int eventTime = 0;
- mPhoneWindowManager.powerPress(eventTime, 1, 0);
-
- // verify no crash
- }
-
- @Test
public void powerPress_hubOrDreamOrSleep_hubAvailableLocks() {
when(mDisplayPolicy.isAwake()).thenReturn(true);
mContext.getTestablePermissions().setPermission(android.Manifest.permission.DEVICE_POWER,
@@ -365,10 +352,5 @@
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return mock(WindowWakeUpPolicy.class);
}
-
- @Override
- DreamManagerInternal getDreamManagerInternal() {
- return mDreamManagerInternal;
- }
}
}
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index cd6ab30..73192ea 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -27,8 +27,6 @@
import android.os.Build
import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS
import android.os.SystemClock
-import android.provider.Settings
-import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
import android.server.wm.CtsWindowInfoUtils.waitForStableWindowGeometry
import android.testing.PollingCheck
@@ -38,6 +36,7 @@
import androidx.test.uiautomator.Until
import com.android.cts.input.DebugInputRule
+import com.android.cts.input.ShowErrorDialogsRule
import com.android.cts.input.UinputTouchScreen
import java.time.Duration
@@ -79,18 +78,16 @@
@get:Rule
val debugInputRule = DebugInputRule()
+ @get:Rule
+ val showErrorDialogs = ShowErrorDialogsRule()
+
@Before
fun setUp() {
- val contentResolver = instrumentation.targetContext.contentResolver
- hideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
- Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage()!!.getName()
}
@After
fun tearDown() {
- val contentResolver = instrumentation.targetContext.contentResolver
- Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, hideErrorDialogs)
}
@Test