diff options
60 files changed, 877 insertions, 853 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 4c9116b02c1d..2c1df73cc6cc 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -7362,16 +7362,6 @@ public final class ActivityThread extends ClientTransactionHandler } WindowManagerGlobal.getInstance().trimMemory(level); - - if (SystemProperties.getInt("debug.am.run_gc_trim_level", Integer.MAX_VALUE) <= level) { - unscheduleGcIdler(); - doGcIfNeeded("tm"); - } - if (SystemProperties.getInt("debug.am.run_mallopt_trim_level", Integer.MAX_VALUE) - <= level) { - unschedulePurgeIdler(); - purgePendingResources(); - } } private void setupGraphicsSupport(Context context) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1210790668de..60e57b588be0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9465,24 +9465,6 @@ public final class Settings { "reduce_bright_colors_persist_across_reboots"; /** - * Setting that specifies whether Even Dimmer - a feature that allows the brightness - * slider to go below what the display can conventionally do, should be enabled. - * - * @hide - */ - public static final String EVEN_DIMMER_ACTIVATED = - "even_dimmer_activated"; - - /** - * Setting that specifies which nits level Even Dimmer should allow the screen brightness - * to go down to. - * - * @hide - */ - public static final String EVEN_DIMMER_MIN_NITS = - "even_dimmer_min_nits"; - - /** * Setting that holds EM_VALUE (proprietary) * * @hide diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 8de77469d170..ac4bac6d206e 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -295,13 +295,6 @@ message SecureSettingsProto { optional SettingProto enhanced_voice_privacy_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; - message EvenDimmer { - optional SettingProto even_dimmer_activated = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto even_dimmer_min_nits = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; - } - - optional EvenDimmer even_dimmer = 98; - optional SettingProto font_weight_adjustment = 85 [ (android.privacy).dest = DEST_AUTOMATIC ]; message Gesture { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt index 5e84019b14f5..1a66ca808dad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt @@ -47,6 +47,7 @@ class ToggleResizeDesktopTaskTransitionHandler( private var boundsAnimator: Animator? = null private var initialBounds: Rect? = null + private var callback: (() -> Unit)? = null constructor( transitions: Transitions, @@ -61,9 +62,14 @@ class ToggleResizeDesktopTaskTransitionHandler( * bounds of the actual task). This is provided so that the animation resizing can begin where * the task leash currently is for smoother UX. */ - fun startTransition(wct: WindowContainerTransaction, taskLeashBounds: Rect? = null) { + fun startTransition( + wct: WindowContainerTransaction, + taskLeashBounds: Rect? = null, + callback: (() -> Unit)? = null, + ) { transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this) initialBounds = taskLeashBounds + this.callback = callback } fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) { @@ -121,6 +127,8 @@ class ToggleResizeDesktopTaskTransitionHandler( interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW) interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW) interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE) + callback?.invoke() + callback = null }, ) addUpdateListener { anim -> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt index cb45c1732476..57f8046065b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt @@ -16,6 +16,9 @@ package com.android.wm.shell.windowdecor.tiling +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator import android.content.Context import android.content.res.Configuration import android.graphics.Path @@ -144,7 +147,6 @@ class DesktopTilingDividerWindowManager( * @param relativeLeash the task leash that the TilingDividerView should be shown on top of. */ fun generateViewHost(relativeLeash: SurfaceControl) { - val t = transactionSupplier.get() val surfaceControlViewHost = SurfaceControlViewHost(context, context.display, this, "DesktopTilingManager") val dividerView = @@ -155,22 +157,40 @@ class DesktopTilingDividerWindowManager( val tmpDividerBounds = Rect() getDividerBounds(tmpDividerBounds) dividerView.setup(this, tmpDividerBounds, handleRegionSize, isDarkMode) - t.setRelativeLayer(leash, relativeLeash, 1) - .setPosition( - leash, - dividerBounds.left.toFloat() - maxRoundedCornerRadius, - dividerBounds.top.toFloat(), - ) - .show(leash) - syncQueue.runInSync { transaction -> - transaction.merge(t) - t.close() - } - dividerShown = true + val dividerAnimatorT = transactionSupplier.get() + val dividerAnimator = + ValueAnimator.ofFloat(0f, 1f).apply { + duration = DIVIDER_FADE_IN_ALPHA_DURATION + addUpdateListener { + dividerAnimatorT.setAlpha(leash, animatedValue as Float).apply() + } + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + dividerAnimatorT + .setRelativeLayer(leash, relativeLeash, 1) + .setPosition( + leash, + dividerBounds.left.toFloat() - maxRoundedCornerRadius, + dividerBounds.top.toFloat(), + ) + .setAlpha(leash, 0f) + .show(leash) + .apply() + } + + override fun onAnimationEnd(animation: Animator) { + dividerAnimatorT.setAlpha(leash, 1f).apply() + dividerShown = true + } + } + ) + } + dividerAnimator.start() viewHost = surfaceControlViewHost - dividerView.addOnLayoutChangeListener(this) tilingDividerView = dividerView updateTouchRegion() + dividerView.addOnLayoutChangeListener(this) } /** Changes divider colour if dark/light mode is toggled. */ @@ -311,4 +331,8 @@ class DesktopTilingDividerWindowManager( ) .maxOf { position -> display.getRoundedCorner(position)?.getRadius() ?: 0 } } + + companion object { + private const val DIVIDER_FADE_IN_ALPHA_DURATION = 300L + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt index a45df045041f..c3d15df6eae5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt @@ -133,10 +133,10 @@ class DesktopTilingWindowDecoration( isDarkMode = isTaskInDarkMode(taskInfo) // Observe drag resizing to break tiling if a task is drag resized. desktopModeWindowDecoration.addDragResizeListener(this) - + val callback = { initTilingForDisplayIfNeeded(taskInfo.configuration, isFirstTiledApp) } if (isTiled) { val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) - toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentBounds) + toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentBounds, callback) } else { // Handle the case where we attempt to snap resize when already snap resized: the task // position won't need to change but we want to animate the surface going back to the @@ -147,10 +147,10 @@ class DesktopTilingWindowDecoration( resizeMetadata.getLeash(), startBounds = currentBounds, endBounds = destinationBounds, + callback, ) } } - initTilingForDisplayIfNeeded(taskInfo.configuration, isFirstTiledApp) return isTiled } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index 70a30a3ca7a9..d58f8a34c98e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -188,7 +188,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { SCREEN_ORIENTATION_LANDSCAPE, ) - verify(resizeTransitionHandler, never()).startTransition(any(), any()) + verify(resizeTransitionHandler, never()).startTransition(any(), any(), any()) } @Test @@ -209,7 +209,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { SCREEN_ORIENTATION_LANDSCAPE, ) - verify(resizeTransitionHandler, never()).startTransition(any(), any()) + verify(resizeTransitionHandler, never()).startTransition(any(), any(), any()) } @Test @@ -225,7 +225,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { handler.handleActivityOrientationChange(task, newTask) - verify(resizeTransitionHandler, never()).startTransition(any(), any()) + verify(resizeTransitionHandler, never()).startTransition(any(), any(), any()) } @Test @@ -240,7 +240,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { SCREEN_ORIENTATION_LANDSCAPE, ) - verify(resizeTransitionHandler, never()).startTransition(any(), any()) + verify(resizeTransitionHandler, never()).startTransition(any(), any(), any()) } @Test @@ -318,7 +318,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { val arg: ArgumentCaptor<WindowContainerTransaction> = ArgumentCaptor.forClass(WindowContainerTransaction::class.java) verify(resizeTransitionHandler, atLeastOnce()) - .startTransition(capture(arg), eq(currentBounds)) + .startTransition(capture(arg), eq(currentBounds), isNull()) return arg.value } 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 0bccde13cabd..857f9bfb7294 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 @@ -5253,7 +5253,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ) // Assert that task is NOT updated via WCT - verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any()) + verify(toggleResizeDesktopTaskTransitionHandler, never()) + .startTransition(any(), any(), any()) // Assert that task leash is updated via Surface Animations verify(mReturnToDragStartAnimator) .start( @@ -5738,7 +5739,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() InputMethod.TOUCH, ) // Assert that task is NOT updated via WCT - verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any()) + verify(toggleResizeDesktopTaskTransitionHandler, never()) + .startTransition(any(), any(), any()) // Assert that task leash is updated via Surface Animations verify(mReturnToDragStartAnimator) @@ -5835,7 +5837,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ) // Assert that task is NOT updated via WCT - verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any()) + verify(toggleResizeDesktopTaskTransitionHandler, never()) + .startTransition(any(), any(), any()) verify(mockToast).show() } @@ -6903,7 +6906,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ): WindowContainerTransaction { val arg = argumentCaptor<WindowContainerTransaction>() verify(toggleResizeDesktopTaskTransitionHandler, atLeastOnce()) - .startTransition(arg.capture(), eq(currentBounds)) + .startTransition(arg.capture(), eq(currentBounds), isNull()) return arg.lastValue } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt index 844205682d31..42eab14042f9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt @@ -70,6 +70,13 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() { whenever(context.display).thenReturn(display) whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner) whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS) + whenever(transactionSupplierMock.get()).thenReturn(transaction) + whenever(transaction.show(any())).thenReturn(transaction) + whenever(transaction.setAlpha(any(), any())).thenReturn(transaction) + whenever(transaction.hide(any())).thenReturn(transaction) + whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction) + whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction) + whenever(transaction.remove(any())).thenReturn(transaction) desktopTilingWindowManager = DesktopTilingDividerWindowManager( config, @@ -88,12 +95,6 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() { @Test @UiThreadTest fun testWindowManager_isInitialisedAndReleased() { - whenever(transactionSupplierMock.get()).thenReturn(transaction) - whenever(transaction.hide(any())).thenReturn(transaction) - whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction) - whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction) - whenever(transaction.remove(any())).thenReturn(transaction) - desktopTilingWindowManager.generateViewHost(surfaceControl) // Ensure a surfaceControl transaction runs to show the divider. @@ -102,18 +103,11 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() { desktopTilingWindowManager.release() verify(transaction, times(1)).hide(any()) verify(transaction, times(1)).remove(any()) - verify(transaction, times(1)).apply() } @Test @UiThreadTest fun testWindowManager_accountsForRoundedCornerDimensions() { - whenever(transactionSupplierMock.get()).thenReturn(transaction) - whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction) - whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction) - whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction) - whenever(transaction.show(any())).thenReturn(transaction) - desktopTilingWindowManager.generateViewHost(surfaceControl) // Ensure a surfaceControl transaction runs to show the divider. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt index 399a51e1ed08..bc8faedd77a9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt @@ -114,6 +114,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { private val split_divider_width = 10 @Captor private lateinit var wctCaptor: ArgumentCaptor<WindowContainerTransaction> + @Captor private lateinit var callbackCaptor: ArgumentCaptor<(() -> Unit)> @Before fun setUp() { @@ -134,7 +135,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { userRepositories, desktopModeEventLogger, focusTransitionObserver, - mainExecutor + mainExecutor, ) whenever(context.createContextAsUser(any(), any())).thenReturn(context) whenever(userRepositories.current).thenReturn(desktopRepository) @@ -158,7 +159,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { BOUNDS, ) - verify(toggleResizeDesktopTaskTransitionHandler).startTransition(capture(wctCaptor), any()) + verify(toggleResizeDesktopTaskTransitionHandler) + .startTransition(capture(wctCaptor), any(), any()) for (change in wctCaptor.value.changes) { val bounds = change.value.configuration.windowConfiguration.bounds val leftBounds = getLeftTaskBounds() @@ -185,7 +187,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { BOUNDS, ) - verify(toggleResizeDesktopTaskTransitionHandler).startTransition(capture(wctCaptor), any()) + verify(toggleResizeDesktopTaskTransitionHandler) + .startTransition(capture(wctCaptor), any(), any()) for (change in wctCaptor.value.changes) { val bounds = change.value.configuration.windowConfiguration.bounds val leftBounds = getRightTaskBounds() @@ -220,7 +223,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { ) verify(toggleResizeDesktopTaskTransitionHandler, times(1)) - .startTransition(capture(wctCaptor), any()) + .startTransition(capture(wctCaptor), any(), any()) verify(returnToDragStartAnimator, times(1)).start(any(), any(), any(), any(), anyOrNull()) for (change in wctCaptor.value.changes) { val bounds = change.value.configuration.windowConfiguration.bounds @@ -308,9 +311,13 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { DesktopTasksController.SnapPosition.LEFT, BOUNDS, ) + verify(toggleResizeDesktopTaskTransitionHandler, times(2)) + .startTransition(capture(wctCaptor), any(), capture(callbackCaptor)) + (callbackCaptor.value).invoke() task1.isFocused = true - assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)).isTrue() + assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)) + .isTrue() verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null)) } @@ -341,6 +348,9 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { ) task1.isFocused = true task3.isFocused = true + verify(toggleResizeDesktopTaskTransitionHandler, times(2)) + .startTransition(capture(wctCaptor), any(), capture(callbackCaptor)) + (callbackCaptor.value).invoke() assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, true)).isFalse() assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, true)).isTrue() @@ -372,9 +382,14 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { DesktopTasksController.SnapPosition.LEFT, BOUNDS, ) - - assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, isFocusedOnDisplay = true)).isFalse() - assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)).isTrue() + verify(toggleResizeDesktopTaskTransitionHandler, times(2)) + .startTransition(capture(wctCaptor), any(), capture(callbackCaptor)) + (callbackCaptor.value).invoke() + + assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, isFocusedOnDisplay = true)) + .isFalse() + assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)) + .isTrue() verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null)) } @@ -482,27 +497,29 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { tilingDecoration.onDividerHandleDragStart(motionEvent) // Log start event for task1 and task2, but the tasks are the same in // this test, so we verify the same log twice. - verify(desktopModeEventLogger, times(2)).logTaskResizingStarted( - ResizeTrigger.TILING_DIVIDER, - DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD, - task1, - BOUNDS.width() / 2, - BOUNDS.height(), - displayController, - ) + verify(desktopModeEventLogger, times(2)) + .logTaskResizingStarted( + ResizeTrigger.TILING_DIVIDER, + DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD, + task1, + BOUNDS.width() / 2, + BOUNDS.height(), + displayController, + ) tilingDecoration.onDividerHandleMoved(BOUNDS, transaction) tilingDecoration.onDividerHandleDragEnd(BOUNDS, transaction, motionEvent) // Log end event for task1 and task2, but the tasks are the same in // this test, so we verify the same log twice. - verify(desktopModeEventLogger, times(2)).logTaskResizingEnded( - ResizeTrigger.TILING_DIVIDER, - DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD, - task1, - BOUNDS.width(), - BOUNDS.height(), - displayController, - ) + verify(desktopModeEventLogger, times(2)) + .logTaskResizingEnded( + ResizeTrigger.TILING_DIVIDER, + DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD, + task1, + BOUNDS.width(), + BOUNDS.height(), + displayController, + ) } @Test diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 3c70fc15485a..c0105298899b 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -271,8 +271,6 @@ public class SecureSettings { Settings.Secure.DEFAULT_NOTE_TASK_PROFILE, Settings.Secure.CREDENTIAL_SERVICE, Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, - Settings.Secure.EVEN_DIMMER_ACTIVATED, - Settings.Secure.EVEN_DIMMER_MIN_NITS, Settings.Secure.STYLUS_POINTER_ICON_ENABLED, Settings.Secure.CAMERA_EXTENSIONS_FALLBACK, Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index c09e45ed81a6..0ffdf53f2036 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -114,9 +114,6 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.FONT_WEIGHT_ADJUSTMENT, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_LEVEL, PERCENTAGE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, BOOLEAN_VALIDATOR); - VALIDATORS.put(Secure.EVEN_DIMMER_ACTIVATED, BOOLEAN_VALIDATOR); - VALIDATORS.put(Secure.EVEN_DIMMER_MIN_NITS, - new InclusiveFloatRangeValidator(0.0f, Float.MAX_VALUE)); VALIDATORS.put(Secure.TTS_DEFAULT_RATE, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.TTS_DEFAULT_PITCH, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.TTS_DEFAULT_SYNTH, PACKAGE_NAME_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 167674a451b3..e07832eea65e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -2189,15 +2189,6 @@ class SettingsProtoDumpUtil { Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED, SecureSettingsProto.ENHANCED_VOICE_PRIVACY_ENABLED); - final long evenDimmerToken = p.start(SecureSettingsProto.EVEN_DIMMER); - dumpSetting(s, p, - Settings.Secure.EVEN_DIMMER_ACTIVATED, - SecureSettingsProto.EvenDimmer.EVEN_DIMMER_ACTIVATED); - dumpSetting(s, p, - Settings.Secure.EVEN_DIMMER_MIN_NITS, - SecureSettingsProto.EvenDimmer.EVEN_DIMMER_MIN_NITS); - p.end(evenDimmerToken); - dumpSetting(s, p, Settings.Secure.EM_VALUE, SecureSettingsProto.Accessibility.EM_VALUE); diff --git a/packages/SystemUI/BUILD_OWNERS b/packages/SystemUI/BUILD_OWNERS new file mode 100644 index 000000000000..4aadee173388 --- /dev/null +++ b/packages/SystemUI/BUILD_OWNERS @@ -0,0 +1,22 @@ +# Build file owners for System UI. Owners should consider the following: +# +# - Does the change negatively affect developer builds? Will it make +# the build slower? +# +# - Does the change add unnecessary dependencies or compilation steps +# that will be difficult to refactor? +# +# For more information, see http://go/sysui-build-owners + +dsandler@android.com + +caitlinshk@google.com +ccross@android.com +cinek@google.com +jernej@google.com +mankoff@google.com +nicomazz@google.com +peskal@google.com +pixel@google.com +saff@google.com +vadimt@google.com diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index f5c0233d56b1..ab3fa1b06255 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -125,3 +125,6 @@ silvajordan@google.com uwaisashraf@google.com vinayjoglekar@google.com willosborn@google.com + +per-file *.mk,{**/,}Android.bp = set noparent +per-file *.mk,{**/,}Android.bp = file:BUILD_OWNERS diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index aeea99be40dd..a2f5a30a20ff 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -193,8 +193,6 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor; @Mock - private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate; - @Mock private SelectedUserInteractor mSelectedUserInteractor; // Capture listeners so that they can be used to send events @@ -321,7 +319,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mAlternateBouncerInteractor, mInputManager, mock(DeviceEntryFaceAuthInteractor.class), - mUdfpsKeyguardAccessibilityDelegate, mSelectedUserInteractor, mKeyguardTransitionInteractor, mDeviceEntryUdfpsTouchOverlayViewModel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt deleted file mode 100644 index 921ff098753e..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2023 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.biometrics - -import android.testing.TestableLooper -import android.view.View -import android.view.accessibility.AccessibilityNodeInfo -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager -import com.android.systemui.util.mockito.argumentCaptor -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.Mock -import org.mockito.Mockito.mock -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations - -@RunWith(AndroidJUnit4::class) -@SmallTest -@TestableLooper.RunWithLooper -class UdfpsKeyguardAccessibilityDelegateTest : SysuiTestCase() { - - @Mock private lateinit var keyguardViewManager: StatusBarKeyguardViewManager - @Mock private lateinit var hostView: View - private lateinit var underTest: UdfpsKeyguardAccessibilityDelegate - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - underTest = - UdfpsKeyguardAccessibilityDelegate( - context.resources, - keyguardViewManager, - ) - } - - @Test - fun onInitializeAccessibilityNodeInfo_clickActionAdded() { - // WHEN node is initialized - val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java) - underTest.onInitializeAccessibilityNodeInfo(hostView, mockedNodeInfo) - - // THEN a11y action is added - val argumentCaptor = argumentCaptor<AccessibilityNodeInfo.AccessibilityAction>() - verify(mockedNodeInfo).addAction(argumentCaptor.capture()) - - // AND the a11y action is a click action - assertEquals( - AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id, - argumentCaptor.value.id - ) - } - - @Test - fun performAccessibilityAction_actionClick_showsPrimaryBouncer() { - // WHEN click action is performed - val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java) - underTest.performAccessibilityAction( - hostView, - AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id, - null - ) - - // THEN primary bouncer shows - verify(keyguardViewManager).showPrimaryBouncer(anyBoolean()) - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt index f91e3a612862..a083e59fe263 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationSt import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel +import com.android.systemui.statusbar.pipeline.shared.ui.model.ChipsVisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel import kotlinx.coroutines.flow.Flow @@ -52,7 +53,10 @@ class FakeHomeStatusBarViewModel( override val primaryOngoingActivityChip: MutableStateFlow<OngoingActivityChipModel> = MutableStateFlow(OngoingActivityChipModel.Inactive()) - override val ongoingActivityChips = MutableStateFlow(MultipleOngoingActivityChipsModel()) + override val ongoingActivityChips = + MutableStateFlow( + ChipsVisibilityModel(MultipleOngoingActivityChipsModel(), areChipsAllowed = false) + ) override val ongoingActivityChipsLegacy = MutableStateFlow(MultipleOngoingActivityChipsModelLegacy()) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt index 7e8ee1b156df..27aa4bab3deb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaPr import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsCallChip import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip import com.android.systemui.statusbar.core.StatusBarRootModernization @@ -88,6 +89,7 @@ import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarIconBlockList import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarInteractorShowOperatorName import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel @@ -716,7 +718,8 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { } @Test - fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hun_false() = + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOff_false() = kosmos.runTest { val latest by collectLastValue(underTest.canShowOngoingActivityChips) @@ -725,7 +728,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { headsUpNotificationRepository.setNotifications( UnconfinedFakeHeadsUpRowRepository( key = "key", - pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), ) ) @@ -733,6 +736,194 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { } @Test + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOff_true() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest).isTrue() + } + + @Test + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOn_true() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), + ) + ) + + assertThat(latest).isTrue() + } + + @Test + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOn_true() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest).isTrue() + } + + @Test + @EnableChipsModernization + fun ongoingActivityChips_statusBarHidden_noSecureCamera_noHun_notAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + // home status bar not allowed + kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen) + kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null) + + assertThat(latest!!.areChipsAllowed).isFalse() + } + + @Test + @EnableChipsModernization + fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_noHun_isAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + transitionKeyguardToGone() + + assertThat(latest!!.areChipsAllowed).isTrue() + } + + @Test + @EnableChipsModernization + fun ongoingActivityChips_statusBarNotHidden_secureCamera_noHun_notAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.OCCLUDED, + testScope = testScope, + ) + kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) + + assertThat(latest!!.areChipsAllowed).isFalse() + } + + @Test + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + @EnableChipsModernization + fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOff_notAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), + ) + ) + + assertThat(latest!!.areChipsAllowed).isFalse() + } + + @Test + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + @EnableChipsModernization + fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOff_isAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest!!.areChipsAllowed).isTrue() + } + + @Test + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + @EnableChipsModernization + fun ongoingActivityChips_tatusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOn_isAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), + ) + ) + + assertThat(latest!!.areChipsAllowed).isTrue() + } + + @Test + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + @EnableChipsModernization + fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOn_isAllowed() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest!!.areChipsAllowed).isTrue() + } + + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + @EnableChipsModernization + fun ongoingActivityChips_followsChipsViewModel() = + kosmos.runTest { + val latest by collectLastValue(underTest.ongoingActivityChips) + transitionKeyguardToGone() + + screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + assertIsScreenRecordChip(latest!!.chips.active[0]) + + addOngoingCallState(key = "call") + + assertIsScreenRecordChip(latest!!.chips.active[0]) + assertIsCallChip(latest!!.chips.active[1], "call") + } + + @Test fun isClockVisible_allowedByDisableFlags_visible() = kosmos.runTest { val latest by collectLastValue(underTest.isClockVisible) @@ -892,7 +1083,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { @Test @EnableChipsModernization - fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationOn() = + fun isNotificationIconContainerVisible_anyChipShowing_chipsModernizationOn() = kosmos.runTest { val latest by collectLastValue(underTest.isNotificationIconContainerVisible) transitionKeyguardToGone() @@ -909,7 +1100,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { @Test @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun isNotificationIconContainerVisible_anyChipShowing_PromotedNotifsOn() = + fun isNotificationIconContainerVisible_anyChipShowing_promotedNotifsOn() = kosmos.runTest { val latest by collectLastValue(underTest.isNotificationIconContainerVisible) transitionKeyguardToGone() @@ -929,7 +1120,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME, ) - fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationAndPromotedNotifsOff() = + fun isNotificationIconContainerVisible_anyChipShowing_chipsModernizationAndPromotedNotifsOff() = kosmos.runTest { val latest by collectLastValue(underTest.isNotificationIconContainerVisible) transitionKeyguardToGone() @@ -943,6 +1134,86 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { assertThat(latest!!.visibility).isEqualTo(View.VISIBLE) } + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunBySystem_noHunFlagOff_visible() = + kosmos.runTest { + val latest by collectLastValue(underTest.isNotificationIconContainerVisible) + transitionKeyguardToGone() + + // Chip + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + // HUN, PinnedBySystem + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), + ) + ) + + assertThat(latest!!.visibility).isEqualTo(View.VISIBLE) + } + + @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunByUser_noHunFlagOff_gone() = + kosmos.runTest { + val latest by collectLastValue(underTest.isNotificationIconContainerVisible) + transitionKeyguardToGone() + + // Chip + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + // HUN, PinnedByUser + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest!!.visibility).isEqualTo(View.GONE) + } + + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunBySystem_noHunFlagOn_gone() = + kosmos.runTest { + val latest by collectLastValue(underTest.isNotificationIconContainerVisible) + transitionKeyguardToGone() + + // Chip + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + // HUN, PinnedBySystem + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem), + ) + ) + + assertThat(latest!!.visibility).isEqualTo(View.GONE) + } + + @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME) + fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunByUser_noHunFlagOn_gone() = + kosmos.runTest { + val latest by collectLastValue(underTest.isNotificationIconContainerVisible) + transitionKeyguardToGone() + + // Chip + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + // HUN, PinnedByUser + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest!!.visibility).isEqualTo(View.GONE) + } + @Test fun isSystemInfoVisible_allowedByDisableFlags_visible() = kosmos.runTest { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 88694ae6db51..dfe8eb28b2a6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -179,7 +179,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull private final PowerInteractor mPowerInteractor; @NonNull private final CoroutineScope mScope; @NonNull private final InputManager mInputManager; - @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate; @NonNull private final SelectedUserInteractor mSelectedUserInteractor; private final boolean mIgnoreRefreshRate; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; @@ -292,7 +291,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { mActivityTransitionAnimator, mPrimaryBouncerInteractor, mAlternateBouncerInteractor, - mUdfpsKeyguardAccessibilityDelegate, mKeyguardTransitionInteractor, mSelectedUserInteractor, mDeviceEntryUdfpsTouchOverlayViewModel, @@ -691,7 +689,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull AlternateBouncerInteractor alternateBouncerInteractor, @NonNull InputManager inputManager, @NonNull DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor, - @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate, @NonNull SelectedUserInteractor selectedUserInteractor, @NonNull KeyguardTransitionInteractor keyguardTransitionInteractor, Lazy<DeviceEntryUdfpsTouchOverlayViewModel> deviceEntryUdfpsTouchOverlayViewModel, @@ -742,7 +739,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { mPowerInteractor = powerInteractor; mScope = scope; mInputManager = inputManager; - mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate; mSelectedUserInteractor = selectedUserInteractor; mKeyguardTransitionInteractor = keyguardTransitionInteractor; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index 702f23718ee8..bdf58275effa 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -107,7 +107,6 @@ constructor( private val primaryBouncerInteractor: PrimaryBouncerInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, private val isDebuggable: Boolean = Build.IS_DEBUGGABLE, - private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate, private val transitionInteractor: KeyguardTransitionInteractor, private val selectedUserInteractor: SelectedUserInteractor, private val deviceEntryUdfpsTouchOverlayViewModel: Lazy<DeviceEntryUdfpsTouchOverlayViewModel>, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt deleted file mode 100644 index 99da660d1fda..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2023 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.biometrics - -import android.content.res.Resources -import android.os.Bundle -import android.view.View -import android.view.accessibility.AccessibilityNodeInfo -import com.android.systemui.res.R -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager -import javax.inject.Inject - -@SysUISingleton -class UdfpsKeyguardAccessibilityDelegate -@Inject -constructor( - @Main private val resources: Resources, - private val keyguardViewManager: StatusBarKeyguardViewManager, -) : View.AccessibilityDelegate() { - override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) { - super.onInitializeAccessibilityNodeInfo(host, info) - val clickAction = - AccessibilityNodeInfo.AccessibilityAction( - AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id, - resources.getString(R.string.accessibility_bouncer) - ) - info.addAction(clickAction) - } - - override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean { - // when an a11y service is enabled, double tapping on the fingerprint sensor should - // show the primary bouncer - return if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id) { - keyguardViewManager.showPrimaryBouncer(/* scrimmed */ true) - true - } else super.performAccessibilityAction(host, action, args) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b4b3053cba42..d8fc21af9724 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1847,6 +1847,7 @@ public class KeyguardViewMediator implements CoreStartable, // explicitly DO NOT want to call // mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false) // here, since that will mess with the device lock state. + mKeyguardStateController.notifyKeyguardGoingAway(false); mUpdateMonitor.dispatchKeyguardGoingAway(false); notifyStartedGoingToSleep(); @@ -2994,7 +2995,6 @@ public class KeyguardViewMediator implements CoreStartable, startKeyguardTransition(showing, aodShowing); } else { try { - mActivityTaskManagerService.setLockScreenShown(showing, aodShowing); } catch (RemoteException ignored) { } @@ -3650,30 +3650,33 @@ public class KeyguardViewMediator implements CoreStartable, return; } - try { - int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS - | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; + int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS + | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; - // If we are unlocking to the launcher, clear the snapshot so that any changes as part - // of the in-window animations are reflected. This is needed even if we're not actually - // playing in-window animations for this particular unlock since a previous unlock might - // have changed the Launcher state. - if (mKeyguardUnlockAnimationControllerLazy.get().isSupportedLauncherUnderneath()) { - flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; - } + // If we are unlocking to the launcher, clear the snapshot so that any changes as part + // of the in-window animations are reflected. This is needed even if we're not actually + // playing in-window animations for this particular unlock since a previous unlock might + // have changed the Launcher state. + if (mKeyguardUnlockAnimationControllerLazy.get().isSupportedLauncherUnderneath()) { + flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; + } - mKeyguardStateController.notifyKeyguardGoingAway(true); + mKeyguardStateController.notifyKeyguardGoingAway(true); - if (!KeyguardWmStateRefactor.isEnabled()) { - // Handled in WmLockscreenVisibilityManager. - mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId(); + if (!KeyguardWmStateRefactor.isEnabled()) { + // Handled in WmLockscreenVisibilityManager. + mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId(); + final int goingAwayFlags = flags; + mUiBgExecutor.execute(() -> { Log.d(TAG, "keyguardGoingAway requested for userId: " + mGoingAwayRequestedForUserId); - mActivityTaskManagerService.keyguardGoingAway(flags); - } - } catch (RemoteException e) { - mSurfaceBehindRemoteAnimationRequested = false; - Log.e(TAG, "Failed to report keyguardGoingAway", e); + try { + mActivityTaskManagerService.keyguardGoingAway(goingAwayFlags); + } catch (RemoteException e) { + mSurfaceBehindRemoteAnimationRequested = false; + Log.e(TAG, "Failed to report keyguardGoingAway", e); + } + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt index 0b587ae1f58e..c031b53ab87d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt @@ -38,9 +38,15 @@ object AlternateBouncerUdfpsViewBinder { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { view.alpha = 0f + launch("$TAG#viewModel.accessibilityDelegateHint") { viewModel.accessibilityDelegateHint.collect { hint -> view.accessibilityHintType = hint + if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) { + view.setOnClickListener { viewModel.onTapped() } + } else { + view.setOnClickListener(null) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt index acd381ec3280..9038922466df 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context import com.android.settingslib.Utils +import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor @@ -26,6 +27,7 @@ import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shared.recents.utilities.Utilities.clamp +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -46,6 +48,8 @@ constructor( fingerprintPropertyInteractor: FingerprintPropertyInteractor, udfpsOverlayInteractor: UdfpsOverlayInteractor, alternateBouncerViewModel: AlternateBouncerViewModel, + private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, + private val accessibilityInteractor: AccessibilityInteractor, ) { private val isSupported: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported val alpha: Flow<Float> = @@ -74,7 +78,15 @@ constructor( } } val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> = - flowOf(DeviceEntryIconView.AccessibilityHintType.ENTER) + accessibilityInteractor.isEnabled.flatMapLatest { touchExplorationEnabled -> + flowOf( + if (touchExplorationEnabled) { + DeviceEntryIconView.AccessibilityHintType.BOUNCER + } else { + DeviceEntryIconView.AccessibilityHintType.NONE + } + ) + } private val fgIconColor: Flow<Int> = configurationInteractor.onAnyConfigurationChange @@ -93,6 +105,10 @@ constructor( ) } + fun onTapped() { + statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true) + } + val bgColor: Flow<Int> = deviceEntryBackgroundViewModel.color val bgAlpha: Flow<Float> = flowOf(1f) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt index d7348892356d..cdd02865bbee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt @@ -47,7 +47,8 @@ import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernizat import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel import javax.inject.Inject -import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch /** @@ -153,39 +154,43 @@ constructor( OngoingActivityChipBinder.createBinding(primaryChipView) launch { - viewModel.primaryOngoingActivityChip.collect { primaryChipModel -> - OngoingActivityChipBinder.bind( - primaryChipModel, - primaryChipViewBinding, - iconViewStore, + combine( + viewModel.primaryOngoingActivityChip, + viewModel.canShowOngoingActivityChips, + ::Pair, ) + .distinctUntilChanged() + .collect { (primaryChipModel, areChipsAllowed) -> + OngoingActivityChipBinder.bind( + primaryChipModel, + primaryChipViewBinding, + iconViewStore, + ) - if (StatusBarRootModernization.isEnabled) { - launch { + if (StatusBarRootModernization.isEnabled) { bindLegacyPrimaryOngoingActivityChipWithVisibility( - viewModel, + areChipsAllowed, primaryChipModel, primaryChipViewBinding, ) - } - } else { - when (primaryChipModel) { - is OngoingActivityChipModel.Active -> - listener?.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = true, - hasSecondaryOngoingActivity = false, - shouldAnimate = true, - ) - - is OngoingActivityChipModel.Inactive -> - listener?.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = false, - hasSecondaryOngoingActivity = false, - shouldAnimate = primaryChipModel.shouldAnimate, - ) + } else { + when (primaryChipModel) { + is OngoingActivityChipModel.Active -> + listener?.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = true, + hasSecondaryOngoingActivity = false, + shouldAnimate = true, + ) + + is OngoingActivityChipModel.Inactive -> + listener?.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = false, + hasSecondaryOngoingActivity = false, + shouldAnimate = primaryChipModel.shouldAnimate, + ) + } } } - } } } @@ -199,49 +204,53 @@ constructor( view.requireViewById(R.id.ongoing_activity_chip_secondary) ) launch { - viewModel.ongoingActivityChipsLegacy.collectLatest { chips -> - OngoingActivityChipBinder.bind( - chips.primary, - primaryChipViewBinding, - iconViewStore, + combine( + viewModel.ongoingActivityChipsLegacy, + viewModel.canShowOngoingActivityChips, + ::Pair, ) - OngoingActivityChipBinder.bind( - chips.secondary, - secondaryChipViewBinding, - iconViewStore, - ) - - if (StatusBarRootModernization.isEnabled) { - launch { + .distinctUntilChanged() + .collect { (chips, areChipsAllowed) -> + OngoingActivityChipBinder.bind( + chips.primary, + primaryChipViewBinding, + iconViewStore, + ) + OngoingActivityChipBinder.bind( + chips.secondary, + secondaryChipViewBinding, + iconViewStore, + ) + if (StatusBarRootModernization.isEnabled) { bindOngoingActivityChipsWithVisibility( - viewModel, + areChipsAllowed, chips, primaryChipViewBinding, secondaryChipViewBinding, ) + } else { + listener?.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = + chips.primary is OngoingActivityChipModel.Active, + hasSecondaryOngoingActivity = + chips.secondary is OngoingActivityChipModel.Active, + // TODO(b/364653005): Figure out the animation story here. + shouldAnimate = true, + ) } - } else { - listener?.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = - chips.primary is OngoingActivityChipModel.Active, - hasSecondaryOngoingActivity = - chips.secondary is OngoingActivityChipModel.Active, - // TODO(b/364653005): Figure out the animation story here. - shouldAnimate = true, - ) - } - - viewModel.contentArea.collect { _ -> - OngoingActivityChipBinder.resetPrimaryChipWidthRestrictions( - primaryChipViewBinding, - viewModel.ongoingActivityChipsLegacy.value.primary, - ) - OngoingActivityChipBinder.resetSecondaryChipWidthRestrictions( - secondaryChipViewBinding, - viewModel.ongoingActivityChipsLegacy.value.secondary, - ) - view.requestLayout() } + } + launch { + viewModel.contentArea.collect { _ -> + OngoingActivityChipBinder.resetPrimaryChipWidthRestrictions( + primaryChipViewBinding, + viewModel.ongoingActivityChipsLegacy.value.primary, + ) + OngoingActivityChipBinder.resetSecondaryChipWidthRestrictions( + secondaryChipViewBinding, + viewModel.ongoingActivityChipsLegacy.value.secondary, + ) + view.requestLayout() } } } @@ -314,48 +323,42 @@ constructor( } /** Bind the (legacy) single primary ongoing activity chip with the status bar visibility */ - private suspend fun bindLegacyPrimaryOngoingActivityChipWithVisibility( - viewModel: HomeStatusBarViewModel, + private fun bindLegacyPrimaryOngoingActivityChipWithVisibility( + areChipsAllowed: Boolean, primaryChipModel: OngoingActivityChipModel, primaryChipViewBinding: OngoingActivityChipViewBinding, ) { - viewModel.canShowOngoingActivityChips.collectLatest { visible -> - if (!visible) { - primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) - } else { - when (primaryChipModel) { - is OngoingActivityChipModel.Active -> { - primaryChipViewBinding.rootView.show(shouldAnimateChange = true) - } + if (!areChipsAllowed) { + primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + } else { + when (primaryChipModel) { + is OngoingActivityChipModel.Active -> { + primaryChipViewBinding.rootView.show(shouldAnimateChange = true) + } - is OngoingActivityChipModel.Inactive -> { - primaryChipViewBinding.rootView.hide( - state = View.GONE, - shouldAnimateChange = primaryChipModel.shouldAnimate, - ) - } + is OngoingActivityChipModel.Inactive -> { + primaryChipViewBinding.rootView.hide( + state = View.GONE, + shouldAnimateChange = primaryChipModel.shouldAnimate, + ) } } } } /** Bind the primary/secondary chips along with the home status bar's visibility */ - private suspend fun bindOngoingActivityChipsWithVisibility( - viewModel: HomeStatusBarViewModel, + private fun bindOngoingActivityChipsWithVisibility( + areChipsAllowed: Boolean, chips: MultipleOngoingActivityChipsModelLegacy, primaryChipViewBinding: OngoingActivityChipViewBinding, secondaryChipViewBinding: OngoingActivityChipViewBinding, ) { - viewModel.canShowOngoingActivityChips.collectLatest { canShow -> - if (!canShow) { - primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) - secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false) - } else { - primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel()) - secondaryChipViewBinding.rootView.adjustVisibility( - chips.secondary.toVisibilityModel() - ) - } + if (!areChipsAllowed) { + primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + } else { + primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel()) + secondaryChipViewBinding.rootView.adjustVisibility(chips.secondary.toVisibilityModel()) } } @@ -428,10 +431,15 @@ constructor( // See CollapsedStatusBarFragment#hide. private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) { animate().cancel() - if (visibility == View.INVISIBLE || visibility == View.GONE) { + + if ( + (visibility == View.INVISIBLE && state == View.INVISIBLE) || + (visibility == View.GONE && state == View.GONE) + ) { return } - if (!shouldAnimateChange) { + val isAlreadyHidden = visibility == View.INVISIBLE || visibility == View.GONE + if (!shouldAnimateChange || isAlreadyHidden) { alpha = 0f visibility = state return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt index 4189221d8a83..c91ea9a50028 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt @@ -196,13 +196,15 @@ fun StatusBarRoot( setContent { PlatformTheme { - val chips by + val chipsVisibilityModel by statusBarViewModel.ongoingActivityChips .collectAsStateWithLifecycle() - OngoingActivityChips( - chips = chips, - iconViewStore = iconViewStore, - ) + if (chipsVisibilityModel.areChipsAllowed) { + OngoingActivityChips( + chips = chipsVisibilityModel.chips, + iconViewStore = iconViewStore, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt new file mode 100644 index 000000000000..5cc432fc6771 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt @@ -0,0 +1,27 @@ +/* + * 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.statusbar.pipeline.shared.ui.model + +import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel + +data class ChipsVisibilityModel( + val chips: MultipleOngoingActivityChipsModel, + /** + * True if the chips are allowed to be shown and false otherwise (e.g. if we're on lockscreen). + */ + val areChipsAllowed: Boolean, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt index 807e90567eb7..9975aff938d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt @@ -67,6 +67,7 @@ import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernizat import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarIconBlockListInteractor import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarInteractor +import com.android.systemui.statusbar.pipeline.shared.ui.model.ChipsVisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel import dagger.assisted.Assisted @@ -125,7 +126,7 @@ interface HomeStatusBarViewModel : Activatable { val primaryOngoingActivityChip: StateFlow<OngoingActivityChipModel> /** All supported activity chips, whether they are currently active or not. */ - val ongoingActivityChips: StateFlow<MultipleOngoingActivityChipsModel> + val ongoingActivityChips: StateFlow<ChipsVisibilityModel> /** * The multiple ongoing activity chips that should be shown on the left-hand side of the status @@ -252,8 +253,6 @@ constructor( override val primaryOngoingActivityChip = ongoingActivityChipsViewModel.primaryChip - override val ongoingActivityChips = ongoingActivityChipsViewModel.chips - override val ongoingActivityChipsLegacy = ongoingActivityChipsViewModel.chipsLegacy override val popupChips @@ -369,15 +368,6 @@ constructor( ) .flowOn(bgDispatcher) - private val isAnyChipVisible = - if (StatusBarChipsModernization.isEnabled) { - ongoingActivityChips.map { it.active.any { chip -> !chip.isHidden } } - } else if (StatusBarNotifChips.isEnabled) { - ongoingActivityChipsLegacy.map { it.primary is OngoingActivityChipModel.Active } - } else { - primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Active } - } - /** * True if we need to hide the usual start side content in order to show the heads up * notification info. @@ -419,9 +409,38 @@ constructor( combine( isHomeStatusBarAllowed, keyguardInteractor.isSecureCameraActive, - headsUpNotificationInteractor.statusBarHeadsUpStatus, - ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState -> - isHomeStatusBarAllowed && !isSecureCameraActive && !headsUpState.isPinned + hideStartSideContentForHeadsUp, + ) { isHomeStatusBarAllowed, isSecureCameraActive, hideStartSideContentForHeadsUp -> + isHomeStatusBarAllowed && !isSecureCameraActive && !hideStartSideContentForHeadsUp + } + + override val ongoingActivityChips = + combine(ongoingActivityChipsViewModel.chips, canShowOngoingActivityChips) { chips, canShow + -> + ChipsVisibilityModel(chips, areChipsAllowed = canShow) + } + .stateIn( + bgScope, + SharingStarted.WhileSubscribed(), + initialValue = + ChipsVisibilityModel( + chips = MultipleOngoingActivityChipsModel(), + areChipsAllowed = false, + ), + ) + + private val hasOngoingActivityChips = + if (StatusBarChipsModernization.isEnabled) { + ongoingActivityChips.map { it.chips.active.any { chip -> !chip.isHidden } } + } else if (StatusBarNotifChips.isEnabled) { + ongoingActivityChipsLegacy.map { it.primary is OngoingActivityChipModel.Active } + } else { + primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Active } + } + + private val isAnyChipVisible = + combine(hasOngoingActivityChips, canShowOngoingActivityChips) { hasChips, canShowChips -> + hasChips && canShowChips } override val isClockVisible: Flow<VisibilityModel> = diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt index 75a5768193cf..c81900da2581 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt @@ -69,9 +69,11 @@ class FlingOnBackAnimationCallbackTest : SysuiTestCase() { callback.onBackProgressed(backEventOf(0.6f, 32)) assertTrue("Assert onBackProgressedCompat called", callback.backProgressedCalled) assertEquals("Assert interpolated progress", 0.6f, callback.progressEvent?.progress) - getInstrumentation().runOnMainSync { callback.onBackInvoked() } - // Assert that onBackInvoked is not called immediately... - assertFalse(callback.backInvokedCalled) + getInstrumentation().runOnMainSync { + callback.onBackInvoked() + // Assert that onBackInvoked is not called immediately. + assertFalse(callback.backInvokedCalled) + } // Instead the fling animation is played and eventually onBackInvoked is called. callback.backInvokedLatch.await(1000, TimeUnit.MILLISECONDS) assertTrue(callback.backInvokedCalled) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 5249620dbdd0..a1d038ad8554 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -120,9 +120,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { private lateinit var deviceEntryUdfpsTouchOverlayViewModel: DeviceEntryUdfpsTouchOverlayViewModel @Mock private lateinit var defaultUdfpsTouchOverlayViewModel: DefaultUdfpsTouchOverlayViewModel - @Mock - private lateinit var udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate - private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + @Mock private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var shadeInteractor: ShadeInteractor @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> @@ -185,7 +183,6 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable, - udfpsKeyguardAccessibilityDelegate, keyguardTransitionInteractor, mSelectedUserInteractor, { deviceEntryUdfpsTouchOverlayViewModel }, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt index 697e7b9476ca..3f3c3c0d478a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.binder import android.content.applicationContext import android.view.mockedLayoutInflater import android.view.windowManager +import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor import com.android.systemui.common.ui.domain.interactor.configurationInteractor @@ -37,6 +38,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.gesture.TapGestureDetector +import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager import com.android.systemui.util.mockito.mock val Kosmos.alternateBouncerViewBinder by @@ -76,5 +78,7 @@ private val Kosmos.alternateBouncerUdfpsIconViewModel by fingerprintPropertyInteractor = fingerprintPropertyInteractor, udfpsOverlayInteractor = udfpsOverlayInteractor, alternateBouncerViewModel = alternateBouncerViewModel, + statusBarKeyguardViewManager = statusBarKeyguardViewManager, + accessibilityInteractor = accessibilityInteractor, ) } diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java index 6c7c9b3e073d..4c62c0deb2df 100644 --- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java +++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java @@ -73,6 +73,8 @@ public class SecureChannel { private int mVerificationResult = FLAG_FAILURE_UNKNOWN; private boolean mPskVerified; + private final Object mHandshakeLock = new Object(); + /** * Create a new secure channel object. This secure channel allows secure messages to be @@ -342,20 +344,22 @@ public class SecureChannel { } private void initiateHandshake() throws IOException, BadHandleException , HandshakeException { - if (mConnectionContext != null) { - Slog.d(TAG, "Ukey2 handshake is already completed."); - return; - } + synchronized (mHandshakeLock) { + if (mConnectionContext != null) { + Slog.d(TAG, "Ukey2 handshake is already completed."); + return; + } - mRole = Role.INITIATOR; - mHandshakeContext = D2DHandshakeContext.forInitiator(); - mClientInit = mHandshakeContext.getNextHandshakeMessage(); + mRole = Role.INITIATOR; + mHandshakeContext = D2DHandshakeContext.forInitiator(); + mClientInit = mHandshakeContext.getNextHandshakeMessage(); - // Send Client Init - if (DEBUG) { - Slog.d(TAG, "Sending Ukey2 Client Init message"); + // Send Client Init + if (DEBUG) { + Slog.d(TAG, "Sending Ukey2 Client Init message"); + } + sendMessage(MessageType.HANDSHAKE_INIT, constructHandshakeInitMessage(mClientInit)); } - sendMessage(MessageType.HANDSHAKE_INIT, constructHandshakeInitMessage(mClientInit)); } // In an occasion where both participants try to initiate a handshake, resolve the conflict @@ -414,8 +418,17 @@ public class SecureChannel { // Mark "in-progress" upon receiving the first message mInProgress = true; + // Complete a series of handshake exchange and processing + synchronized (mHandshakeLock) { + completeHandshake(handshakeInitMessage); + } + } + + private void completeHandshake(byte[] initMessage) throws IOException, HandshakeException, + BadHandleException, CryptoException, AlertException { + // Handle a potential collision where both devices tried to initiate a connection - byte[] handshakeMessage = handleHandshakeCollision(handshakeInitMessage); + byte[] handshakeMessage = handleHandshakeCollision(initMessage); // Proceed with the rest of Ukey2 handshake if (mHandshakeContext == null) { // Server-side logic diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java index 69bc66fea56c..155f82a421ae 100644 --- a/services/core/java/com/android/server/display/DisplayAdapter.java +++ b/services/core/java/com/android/server/display/DisplayAdapter.java @@ -19,6 +19,7 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; import android.view.Display; +import android.view.SurfaceControl; import com.android.server.display.feature.DisplayManagerFlags; @@ -138,6 +139,21 @@ abstract class DisplayAdapter { vsyncRate, /* isSynthetic= */ false, alternativeRefreshRates, supportedHdrTypes); } + static int getPowerModeForState(int state) { + switch (state) { + case Display.STATE_OFF: + return SurfaceControl.POWER_MODE_OFF; + case Display.STATE_DOZE: + return SurfaceControl.POWER_MODE_DOZE; + case Display.STATE_DOZE_SUSPEND: + return SurfaceControl.POWER_MODE_DOZE_SUSPEND; + case Display.STATE_ON_SUSPEND: + return SurfaceControl.POWER_MODE_ON_SUSPEND; + default: + return SurfaceControl.POWER_MODE_NORMAL; + } + } + public interface Listener { void onDisplayDeviceEvent(DisplayDevice device, int event); void onTraversalRequested(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 258c95582e3a..d402f010281f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2618,8 +2618,7 @@ public final class DisplayManagerService extends SystemService { // Blank or unblank the display immediately to match the state requested // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); - if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0 - || android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { + if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); if (display == null) { return null; @@ -5580,9 +5579,7 @@ public final class DisplayManagerService extends SystemService { final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked( id).getPrimaryDisplayDeviceLocked(); final int flags = displayDevice.getDisplayDeviceInfoLocked().flags; - if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0 - || android.companion.virtualdevice.flags.Flags - .correctVirtualDisplayPowerState()) { + if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(id); if (displayPowerController != null) { diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 551202c20cbb..7b714ad2bd9e 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -208,21 +208,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } - static int getPowerModeForState(int state) { - switch (state) { - case Display.STATE_OFF: - return SurfaceControl.POWER_MODE_OFF; - case Display.STATE_DOZE: - return SurfaceControl.POWER_MODE_DOZE; - case Display.STATE_DOZE_SUSPEND: - return SurfaceControl.POWER_MODE_DOZE_SUSPEND; - case Display.STATE_ON_SUSPEND: - return SurfaceControl.POWER_MODE_ON_SUSPEND; - default: - return SurfaceControl.POWER_MODE_NORMAL; - } - } - private final class LocalDisplayDevice extends DisplayDevice { private final long mPhysicalDisplayId; private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>(); diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index e7939bb50ece..ac03a93ca9e1 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -113,6 +113,11 @@ public class VirtualDisplayAdapter extends DisplayAdapter { public void destroyDisplay(IBinder displayToken) { DisplayControl.destroyVirtualDisplay(displayToken); } + + @Override + public void setDisplayPowerMode(IBinder displayToken, int mode) { + SurfaceControl.setDisplayPowerMode(displayToken, mode); + } }, featureFlags); } @@ -340,6 +345,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { private Display.Mode mMode; private int mDisplayIdToMirror; private boolean mIsWindowManagerMirroring; + private final boolean mNeverBlank; private final DisplayCutout mDisplayCutout; private final float mDefaultBrightness; private final float mDimBrightness; @@ -371,7 +377,11 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mCallback = callback; mProjection = projection; mMediaProjectionCallback = mediaProjectionCallback; - if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { + // Private non-mirror displays are never blank and always on. + mNeverBlank = (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0 + && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0; + if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState() + && !mNeverBlank) { // The display's power state depends on the power state of the state of its // display / power group, which we don't know here. Initializing to UNKNOWN allows // the first call to requestDisplayStateLocked() to set the correct state. @@ -471,7 +481,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter { @Override public Runnable requestDisplayStateLocked(int state, float brightnessState, float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) { + Runnable runnable = null; if (state != mDisplayState) { + Slog.d(TAG, "Changing state of virtual display " + mName + " from " + + Display.stateToString(mDisplayState) + " to " + + Display.stateToString(state)); + if (state != Display.STATE_ON && state != Display.STATE_OFF) { + Slog.wtf(TAG, "Unexpected display state for Virtual Display: " + + Display.stateToString(state)); + } mDisplayState = state; mInfo = null; sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); @@ -480,6 +498,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter { } else { mCallback.dispatchDisplayResumed(); } + + if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { + final IBinder token = getDisplayTokenLocked(); + runnable = () -> { + final int mode = getPowerModeForState(state); + Slog.d(TAG, "Requesting power mode for display " + mName + " to " + mode); + mSurfaceControlDisplayFactory.setDisplayPowerMode(token, mode); + }; + } } if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower() && mBrightnessListener != null @@ -488,7 +515,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mCurrentBrightness = brightnessState; mCallback.dispatchRequestedBrightnessChanged(mCurrentBrightness); } - return null; + return runnable; } @Override @@ -572,23 +599,14 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.yDpi = mDensityDpi; mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame mInfo.flags = 0; - if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { - if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; - } - if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; - } - } else { - if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE - | DisplayDeviceInfo.FLAG_NEVER_BLANK; - } - if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { - mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; - } else { - mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; - } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; + } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + } + if (mNeverBlank) { + mInfo.flags |= DisplayDeviceInfo.FLAG_NEVER_BLANK; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; @@ -782,5 +800,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter { * @param displayToken The display token for the display to be destroyed. */ void destroyDisplay(IBinder displayToken); + + /** + * Set the display power mode in SurfaceFlinger. + * + * @param displayToken The display token for the display. + * @param mode the SurfaceControl power mode, e.g. {@link SurfaceControl#POWER_MODE_OFF}. + */ + void setDisplayPowerMode(IBinder displayToken, int mode); } } diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java index a4804e1887fe..d4b9a6ce058b 100644 --- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java +++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java @@ -49,11 +49,9 @@ public final class BrightnessReason { public static final int MODIFIER_HDR = 0x4; public static final int MODIFIER_THROTTLED = 0x8; public static final int MODIFIER_MIN_LUX = 0x10; - public static final int MODIFIER_MIN_USER_SET_LOWER_BOUND = 0x20; - public static final int MODIFIER_STYLUS_UNDER_USE = 0x40; + public static final int MODIFIER_STYLUS_UNDER_USE = 0x20; public static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR - | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_MIN_USER_SET_LOWER_BOUND - | MODIFIER_STYLUS_UNDER_USE; + | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_STYLUS_UNDER_USE; // ADJUSTMENT_* // These things can happen at any point, even if the main brightness reason doesn't @@ -157,9 +155,6 @@ public final class BrightnessReason { if ((mModifier & MODIFIER_MIN_LUX) != 0) { sb.append(" lux_lower_bound"); } - if ((mModifier & MODIFIER_MIN_USER_SET_LOWER_BOUND) != 0) { - sb.append(" user_min_pref"); - } if ((mModifier & MODIFIER_STYLUS_UNDER_USE) != 0) { sb.append(" stylus_under_use"); } diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java index c3596c3e77fe..72cb31d8d1bb 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java @@ -19,12 +19,8 @@ package com.android.server.display.brightness.clamper; import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; import android.hardware.display.DisplayManagerInternal; -import android.net.Uri; import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -49,7 +45,6 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements private static final String TAG = "BrightnessLowLuxModifier"; private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); private static final float MIN_NITS_DEFAULT = 0.2f; - private final SettingsObserver mSettingsObserver; private final ContentResolver mContentResolver; private final Handler mHandler; private final BrightnessClamperController.ClamperChangeListener mChangeListener; @@ -69,7 +64,6 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements mChangeListener = listener; mHandler = handler; mContentResolver = context.getContentResolver(); - mSettingsObserver = new SettingsObserver(mHandler); mDisplayDeviceConfig = displayDeviceConfig; mHandler.post(() -> { start(); @@ -82,12 +76,7 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements */ @VisibleForTesting public void recalculateLowerBound() { - float settingNitsLowerBound = Settings.Secure.getFloatForUser( - mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS, - /* def= */ MIN_NITS_DEFAULT, UserHandle.USER_CURRENT); - - boolean isActive = isSettingEnabled() - && mAmbientLux != BrightnessMappingStrategy.INVALID_LUX; + boolean isActive = mAmbientLux != BrightnessMappingStrategy.INVALID_LUX; final int reason; float minNitsAllowed = -1f; // undefined, if setting is off. @@ -95,12 +84,9 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements if (isActive) { float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux); - minNitsAllowed = Math.max(settingNitsLowerBound, - luxBasedNitsLowerBound); + minNitsAllowed = Math.max(MIN_NITS_DEFAULT, luxBasedNitsLowerBound); minBrightnessAllowed = getBrightnessFromNits(minNitsAllowed); - reason = settingNitsLowerBound > luxBasedNitsLowerBound - ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND - : BrightnessReason.MODIFIER_MIN_LUX; + reason = BrightnessReason.MODIFIER_MIN_LUX; } else { minBrightnessAllowed = mDisplayDeviceConfig.getEvenDimmerTransitionPoint(); reason = 0; @@ -169,7 +155,6 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements @Override public void apply(DisplayManagerInternal.DisplayPowerRequest request, DisplayBrightnessState.Builder stateBuilder) { - stateBuilder.setMinBrightness(mBrightnessLowerBound); float boundedBrightness = Math.max(mBrightnessLowerBound, stateBuilder.getBrightness()); stateBuilder.setBrightness(boundedBrightness); @@ -181,12 +166,11 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements @Override public void stop() { - mContentResolver.unregisterContentObserver(mSettingsObserver); } @Override public boolean shouldListenToLightSensor() { - return isSettingEnabled(); + return true; } @Override @@ -204,37 +188,8 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements pw.println(" mMinNitsAllowed=" + mMinNitsAllowed); } - /** - * Defaults to true, on devices where setting is unset. - * - * @return if setting indicates feature is enabled - */ - private boolean isSettingEnabled() { - return Settings.Secure.getFloatForUser(mContentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, - /* def= */ 1.0f, UserHandle.USER_CURRENT) == 1.0f; - } - private float getBrightnessFromNits(float nits) { return mDisplayDeviceConfig.getBrightnessFromBacklight( mDisplayDeviceConfig.getBacklightFromNits(nits)); } - - private final class SettingsObserver extends ContentObserver { - - SettingsObserver(Handler handler) { - super(handler); - mContentResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.EVEN_DIMMER_MIN_NITS), - false, this, UserHandle.USER_ALL); - mContentResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.EVEN_DIMMER_ACTIVATED), - false, this, UserHandle.USER_ALL); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - recalculateLowerBound(); - } - } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 60371d751c4a..0f1d28db8d82 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2809,7 +2809,6 @@ public class NotificationManagerService extends SystemService { mNotificationChannelLogger, mAppOps, mUserProfiles, - mUgmInternal, mShowReviewPermissionsNotification, Clock.systemUTC()); mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, @@ -7210,7 +7209,13 @@ public class NotificationManagerService extends SystemService { final Uri originalSoundUri = (originalChannel != null) ? originalChannel.getSound() : null; if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { - PermissionHelper.grantUriPermission(mUgmInternal, soundUri, sourceUid); + Binder.withCleanCallingIdentity(() -> { + mUgmInternal.checkGrantUriPermission(sourceUid, null, + ContentProvider.getUriWithoutUserId(soundUri), + Intent.FLAG_GRANT_READ_URI_PERMISSION, + ContentProvider.getUserIdFromUri(soundUri, + UserHandle.getUserId(sourceUid))); + }); } } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 5a58f457ba08..398894bf5273 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -37,7 +37,10 @@ import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.Person; +import android.content.ContentProvider; +import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; @@ -46,6 +49,7 @@ import android.media.AudioAttributes; import android.media.AudioSystem; import android.metrics.LogMaker; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; @@ -1532,15 +1536,21 @@ public final class NotificationRecord { * {@link #mGrantableUris}. Otherwise, this will either log or throw * {@link SecurityException} depending on target SDK of enqueuing app. */ - private void visitGrantableUri(Uri uri, boolean userOverriddenUri, - boolean isSound) { + private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) { + if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; + if (mGrantableUris != null && mGrantableUris.contains(uri)) { return; // already verified this URI } final int sourceUid = getSbn().getUid(); + final long ident = Binder.clearCallingIdentity(); try { - PermissionHelper.grantUriPermission(mUgmInternal, uri, sourceUid); + // This will throw a SecurityException if the caller can't grant. + mUgmInternal.checkGrantUriPermission(sourceUid, null, + ContentProvider.getUriWithoutUserId(uri), + Intent.FLAG_GRANT_READ_URI_PERMISSION, + ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); if (mGrantableUris == null) { mGrantableUris = new ArraySet<>(); @@ -1560,6 +1570,8 @@ public final class NotificationRecord { } } } + } finally { + Binder.restoreCallingIdentity(ident); } } diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java index 1464d481311a..b6f48890c528 100644 --- a/services/core/java/com/android/server/notification/PermissionHelper.java +++ b/services/core/java/com/android/server/notification/PermissionHelper.java @@ -25,25 +25,19 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.companion.virtual.VirtualDeviceManager; -import android.content.ContentProvider; -import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; -import android.net.Uri; import android.os.Binder; import android.os.RemoteException; -import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.internal.util.ArrayUtils; -import com.android.server.uri.UriGrantsManagerInternal; import java.util.Collections; import java.util.HashSet; @@ -64,7 +58,7 @@ public final class PermissionHelper { private final IPermissionManager mPermManager; public PermissionHelper(Context context, IPackageManager packageManager, - IPermissionManager permManager) { + IPermissionManager permManager) { mContext = context; mPackageManager = packageManager; mPermManager = permManager; @@ -304,19 +298,6 @@ public final class PermissionHelper { return false; } - static void grantUriPermission(final UriGrantsManagerInternal ugmInternal, Uri uri, - int sourceUid) { - if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; - - Binder.withCleanCallingIdentity(() -> { - // This will throw a SecurityException if the caller can't grant. - ugmInternal.checkGrantUriPermission(sourceUid, null, - ContentProvider.getUriWithoutUserId(uri), - Intent.FLAG_GRANT_READ_URI_PERMISSION, - ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); - }); - } - public static class PackagePermission { public final String packageName; public final @UserIdInt int userId; diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 46ff7983bb2d..b26b4571b07a 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -100,7 +100,6 @@ import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.notification.PermissionHelper.PackagePermission; -import com.android.server.uri.UriGrantsManagerInternal; import org.json.JSONArray; import org.json.JSONException; @@ -228,7 +227,6 @@ public class PreferencesHelper implements RankingConfig { private final NotificationChannelLogger mNotificationChannelLogger; private final AppOpsManager mAppOps; private final ManagedServices.UserProfiles mUserProfiles; - private final UriGrantsManagerInternal mUgmInternal; private SparseBooleanArray mBadgingEnabled; private SparseBooleanArray mBubblesEnabled; @@ -247,7 +245,6 @@ public class PreferencesHelper implements RankingConfig { ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles, - UriGrantsManagerInternal ugmInternal, boolean showReviewPermissionsNotification, Clock clock) { mContext = context; mZenModeHelper = zenHelper; @@ -258,7 +255,6 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; mUserProfiles = userProfiles; - mUgmInternal = ugmInternal; mShowReviewPermissionsNotification = showReviewPermissionsNotification; mIsMediaNotificationFilteringEnabled = context.getResources() .getBoolean(R.bool.config_quickSettingsShowMediaPlayer); @@ -1195,11 +1191,6 @@ public class PreferencesHelper implements RankingConfig { } clearLockedFieldsLocked(channel); - // Verify that the app has permission to read the sound Uri - // Only check for new channels, as regular apps can only set sound - // before creating. See: {@link NotificationChannel#setSound} - PermissionHelper.grantUriPermission(mUgmInternal, channel.getSound(), uid); - channel.setImportanceLockedByCriticalDeviceFunction( r.defaultAppLockedImportance || r.fixedImportance); diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java index 60d028b46970..f3797614dee0 100644 --- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java +++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java @@ -392,7 +392,7 @@ public class BackgroundInstallControlService extends SystemService { private boolean installedByAdb(String initiatingPackageName) { // GTS tests needs to adopt shell identity to install apps. - if(!SystemProperties.get("gts.transparency.bg-install-apps").isEmpty()) { + if(!SystemProperties.get("debug.gts.transparency.bg-install-apps").isEmpty()) { Slog.d(TAG, "handlePackageAdd: is GTS tests, skipping ADB check"); } else if(PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName)) { Slog.d(TAG, "handlePackageAdd: is installed by ADB, skipping"); diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 2a2ae12ab09b..2cac63c1e5e9 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -104,7 +104,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending && mControlTarget != null) { ProtoLog.d(WM_DEBUG_IME, - "onPostLayout: IME control ready to be dispatched, ws=%s", ws); + "onPostLayout: IME control ready to be dispatched, controlTarget=%s", + mControlTarget); mGivenInsetsReady = true; ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED); @@ -115,13 +116,15 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { // If the server visibility didn't change (still visible), and mGivenInsetsReady // is set, we won't call into notifyControlChanged. Therefore, we can reset the // statsToken, if available. - ProtoLog.w(WM_DEBUG_IME, "onPostLayout cancel statsToken, ws=%s", ws); + ProtoLog.w(WM_DEBUG_IME, "onPostLayout cancel statsToken, controlTarget=%s", + mControlTarget); ImeTracker.forLogging().onCancelled(mStatsToken, ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED); mStatsToken = null; } else if (wasServerVisible && !isServerVisible()) { - ProtoLog.d(WM_DEBUG_IME, "onPostLayout: setImeShowing(false) was: %s, ws=%s", - isImeShowing(), ws); + ProtoLog.d(WM_DEBUG_IME, + "onPostLayout: setImeShowing(false) was: %s, controlTarget=%s", + isImeShowing(), mControlTarget); setImeShowing(false); } } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml index d6a685378d9e..ea01fc4e6140 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml @@ -18,9 +18,6 @@ <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> - <!-- Needed for reading the app files for the test artifacts --> - <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> - <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="install-arg" value="-t" /> @@ -44,7 +41,7 @@ <!-- Collect output of DumpOnFailure --> <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> - <option name="directory-keys" value="/data/user/0/com.android.apps.inputmethod.simpleime/files" /> + <option name="directory-keys" value="/sdcard/DumpOnFailure" /> <option name="collect-on-run-ended-only" value="true" /> <option name="clean-up" value="true" /> </metrics_collector> diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index 2cd860ae6c12..e263e85f020f 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -77,6 +77,8 @@ import org.junit.Test; import org.junit.rules.TestName; import org.junit.runner.RunWith; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; @@ -1294,6 +1296,14 @@ public class InputMethodServiceTest { mInstrumentation.waitForIdleSync(); final var postScreenshot = mInstrumentation.getUiAutomation().takeScreenshot(); mDumpOnFailure.dumpOnFailure("post-getUiObject", postScreenshot); + try { + final var outputStream = new ByteArrayOutputStream(); + mUiDevice.dumpWindowHierarchy(outputStream); + final String windowHierarchy = outputStream.toString(StandardCharsets.UTF_8); + mDumpOnFailure.dumpOnFailure("post-getUiObject", windowHierarchy); + } catch (Exception e) { + Log.i(TAG, "Failed to dump windowHierarchy", e); + } assertWithMessage("UiObject with " + bySelector + " was found").that(uiObject).isNotNull(); return uiObject; } diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml index 00873de4aaed..b6965a4341d7 100644 --- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml +++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml @@ -20,6 +20,9 @@ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <!-- Enable writing output of DumpOnFailure to external storage --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <application android:debuggable="true" android:label="@string/app_name"> <service diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index c151732cec66..65585d06ff06 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -332,6 +332,10 @@ public class DisplayManagerServiceTest { @Override public void destroyDisplay(IBinder displayToken) { } + + @Override + public void setDisplayPowerMode(IBinder displayToken, int mode) { + } }, flags); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java index 9287b3004279..0bef3b89547f 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java @@ -21,19 +21,29 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.hardware.display.DisplayManager; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; import android.media.projection.IMediaProjection; +import android.os.Binder; import android.os.IBinder; import android.os.PowerManager; import android.os.Process; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.TestableContext; import android.view.Display; import android.view.Surface; +import android.view.SurfaceControl; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -67,6 +77,9 @@ public class VirtualDisplayAdapterTest { public final TestableContext mContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getContext()); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory; @@ -380,6 +393,69 @@ public class VirtualDisplayAdapterTest { } } + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE) + @Test + public void neverBlankDisplay_alwaysOn() { + // A non-public non-mirror display is considered never blank. + DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback, + /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage", + "uniqueId", /* surface= */ mSurfaceMock, /* flags= */ 0, + mVirtualDisplayConfigMock); + + DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + assertThat(info.state).isEqualTo(Display.STATE_ON); + assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) + .isEqualTo(DisplayDeviceInfo.FLAG_NEVER_BLANK); + } + + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE) + @Test + public void virtualDisplayStateChange_propagatesToSurfaceControl() throws Exception { + final String uniqueId = "uniqueId"; + final IBinder displayToken = new Binder(); + when(mMockSufaceControlDisplayFactory.createDisplay( + any(), anyBoolean(), eq(uniqueId), anyFloat())) + .thenReturn(displayToken); + + // The display needs to be public, otherwise it will be considered never blank. + DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback, + /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage", + uniqueId, /* surface= */ mSurfaceMock, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, + mVirtualDisplayConfigMock); + + DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + assertThat(info.state).isEqualTo(Display.STATE_UNKNOWN); + assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK).isEqualTo(0); + + // Any initial state change is processed because the display state is initially UNKNOWN + Runnable stateOnRunnable = device.requestDisplayStateLocked( + Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f, + /* displayOffloadSession= */ null); + assertThat(stateOnRunnable).isNotNull(); + stateOnRunnable.run(); + verify(mMockSufaceControlDisplayFactory) + .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_NORMAL); + verify(mMockCallback).onResumed(); + + // Requesting the same display state is a no-op + Runnable stateOnSecondRunnable = device.requestDisplayStateLocked( + Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f, + /* displayOffloadSession= */ null); + assertThat(stateOnSecondRunnable).isNull(); + + // A change to the display state is processed + Runnable stateOffRunnable = device.requestDisplayStateLocked( + Display.STATE_OFF, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f, + /* displayOffloadSession= */ null); + assertThat(stateOffRunnable).isNotNull(); + stateOffRunnable.run(); + verify(mMockSufaceControlDisplayFactory) + .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_OFF); + verify(mMockCallback).onPaused(); + } + private IVirtualDisplayCallback createCallback() { return new IVirtualDisplayCallback.Stub() { diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt index 6929690baaf8..d7c047768c1e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt @@ -17,7 +17,6 @@ package com.android.server.display.brightness.clamper import android.os.UserHandle import android.platform.test.annotations.RequiresFlagsEnabled -import android.provider.Settings import android.testing.TestableContext import androidx.test.platform.app.InstrumentationRegistry import com.android.server.display.DisplayDeviceConfig @@ -46,8 +45,6 @@ class BrightnessLowLuxModifierTest { private var mockDisplayDeviceConfig = mock<DisplayDeviceConfig>() private val LOW_LUX_BRIGHTNESS = 0.1f - private val TRANSITION_POINT = 0.25f - private val NORMAL_RANGE_BRIGHTNESS = 0.3f @Before fun setUp() { @@ -73,127 +70,21 @@ class BrightnessLowLuxModifierTest { whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.15f)) .thenReturn(0.24f) - // values above transition point (normal range) - // nits: 10 -> backlight 0.2 -> brightness -> 0.3 - whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 10f)) - .thenReturn(0.2f) - whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.2f)) - .thenReturn(NORMAL_RANGE_BRIGHTNESS) - // min nits when lux of 400 whenever(mockDisplayDeviceConfig.getMinNitsFromLux(/* lux= */ 400f)) .thenReturn(1.0f) - - whenever(mockDisplayDeviceConfig.evenDimmerTransitionPoint).thenReturn(TRANSITION_POINT) - - testHandler.flush() - } - - @Test - fun testSettingOffDisablesModifier() { - // test transition point ensures brightness doesn't drop when setting is off. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) - modifier.recalculateLowerBound() - testHandler.flush() - assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT) - assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off - modifier.setAmbientLux(3000f) - testHandler.flush() - assertThat(modifier.isActive).isFalse() - assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT) - assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off } @Test @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) fun testLuxRestrictsBrightnessRange() { // test that high lux prevents low brightness range. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.1f, USER_ID) - modifier.setAmbientLux(400f) - - testHandler.flush() - - assertThat(modifier.isActive).isTrue() - // Test restriction from lux setting - assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX) - assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS) - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) - fun testUserRestrictsBrightnessRange() { - // test that user minimum nits setting prevents low brightness range. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 10.0f, USER_ID) - modifier.recalculateLowerBound() - testHandler.flush() - - // Test restriction from user setting - assertThat(modifier.isActive).isTrue() - assertThat(modifier.brightnessReason) - .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND) - assertThat(modifier.brightnessLowerBound).isEqualTo(NORMAL_RANGE_BRIGHTNESS) - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) - fun testOnToOff() { - // test that high lux prevents low brightness range. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID) - modifier.setAmbientLux(400f) - - testHandler.flush() - - assertThat(modifier.isActive).isTrue() - // Test restriction from lux setting - assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX) - assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS) - - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off - - modifier.recalculateLowerBound() - testHandler.flush() - - assertThat(modifier.isActive).isFalse() - assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT) - assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) - fun testOffToOn() { - // test that high lux prevents low brightness range. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID) modifier.setAmbientLux(400f) testHandler.flush() - assertThat(modifier.isActive).isFalse() - assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT) - assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off - - - - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on - modifier.recalculateLowerBound() - testHandler.flush() - assertThat(modifier.isActive).isTrue() // Test restriction from lux setting assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX) @@ -204,11 +95,6 @@ class BrightnessLowLuxModifierTest { @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) fun testEnabledEvenWhenAutobrightnessIsOff() { // test that high lux prevents low brightness range. - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID) - modifier.setAmbientLux(400f) testHandler.flush() @@ -225,37 +111,5 @@ class BrightnessLowLuxModifierTest { assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX) assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS) } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER) - fun testUserSwitch() { - // nits: 0.5 -> backlight 0.01 -> brightness -> 0.05 - whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 0.5f)) - .thenReturn(0.01f) - whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.01f)) - .thenReturn(0.05f) - - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID) - - modifier.recalculateLowerBound() - - assertThat(modifier.isActive).isFalse() - assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT) - assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - i.e. off - - Settings.Secure.putIntForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on - Settings.Secure.putFloatForUser(context.contentResolver, - Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.5f, USER_ID) - modifier.onSwitchUser() - - assertThat(modifier.isActive).isTrue() - assertThat(modifier.brightnessReason).isEqualTo( - BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND) - assertThat(modifier.brightnessLowerBound).isEqualTo(0.05f) - } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 3727bbefb1d3..dd5c601619a0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -5211,41 +5211,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void - updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm() - throws Exception { - mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(mPkg, mUserId)) - .thenReturn(singletonList(mock(AssociationInfo.class))); - when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), - eq(mTestNotificationChannel.getId()), anyBoolean())) - .thenReturn(mTestNotificationChannel); - - // Missing Uri permissions for the old channel sound - final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI; - doThrow(new SecurityException("no access")).when(mUgmInternal) - .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri), - anyInt(), eq(Process.myUserHandle().getIdentifier())); - - // Has Uri permissions for the old channel sound - final Uri newSoundUri = Uri.parse("content://media/test/sound/uri"); - final NotificationChannel updatedNotificationChannel = new NotificationChannel( - TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); - updatedNotificationChannel.setSound(newSoundUri, - updatedNotificationChannel.getAudioAttributes()); - - mBinderService.updateNotificationChannelFromPrivilegedListener( - null, mPkg, Process.myUserHandle(), updatedNotificationChannel); - - verify(mPreferencesHelper, times(1)).updateNotificationChannel( - anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); - - verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), - eq(Process.myUserHandle()), eq(mTestNotificationChannel), - eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); - } - - @Test public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); when(mCompanionMgr.getAssociations(mPkg, mUserId)) diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 752910d6d3c1..a02f628ce9b7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -46,13 +46,11 @@ import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE; -import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE; -import static android.content.ContentResolver.SCHEME_CONTENT; -import static android.content.ContentResolver.SCHEME_FILE; import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_SYSTEM; + import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; import static android.service.notification.Adjustment.TYPE_NEWS; @@ -66,6 +64,7 @@ import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.No import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED; +import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; import static com.android.server.notification.Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA; import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER; import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE; @@ -92,7 +91,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -385,10 +383,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); resetZenModeHelper(); mAudioAttributes = new AudioAttributes.Builder() @@ -803,7 +801,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testReadXml_oldXml_migrates() throws Exception { mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock); + /* showReviewPermissionsNotification= */ true, mClock); String xml = "<ranking version=\"2\">\n" + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1 @@ -939,7 +937,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception { mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock); + /* showReviewPermissionsNotification= */ true, mClock); String xml = "<ranking version=\"3\">\n" + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" @@ -998,7 +996,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testReadXml_newXml_permissionNotificationOff() throws Exception { mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, /* showReviewPermissionsNotification= */ false, mClock); + /* showReviewPermissionsNotification= */ false, mClock); String xml = "<ranking version=\"3\">\n" + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" @@ -1057,7 +1055,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception { mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock); + /* showReviewPermissionsNotification= */ true, mClock); String xml = "<ranking version=\"4\">\n" + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" @@ -1655,7 +1653,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { // simulate load after reboot mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); loadByteArrayXml(baos.toByteArray(), false, USER_ALL); // Trigger 2nd restore pass @@ -1710,7 +1708,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { // simulate load after reboot mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); loadByteArrayXml(xml.getBytes(), false, USER_ALL); // Trigger 2nd restore pass @@ -1788,10 +1786,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper = new TestPreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); mXmlHelper = new TestPreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper, mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, - mUgmInternal, false, mClock); + false, mClock); NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); @@ -3263,61 +3261,6 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testCreateChannel_noSoundUriPermission_contentSchemeVerified() { - final Uri sound = Uri.parse(SCHEME_CONTENT + "://media/test/sound/uri"); - - doThrow(new SecurityException("no access")).when(mUgmInternal) - .checkGrantUriPermission(eq(UID_N_MR1), any(), eq(sound), - anyInt(), eq(UserHandle.getUserId(UID_N_MR1))); - - final NotificationChannel channel = new NotificationChannel("id2", "name2", - NotificationManager.IMPORTANCE_DEFAULT); - channel.setSound(sound, mAudioAttributes); - - assertThrows(SecurityException.class, - () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, - true, false, UID_N_MR1, false)); - assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true)) - .isNull(); - } - - @Test - public void testCreateChannel_noSoundUriPermission_fileSchemaIgnored() { - final Uri sound = Uri.parse(SCHEME_FILE + "://path/sound"); - - doThrow(new SecurityException("no access")).when(mUgmInternal) - .checkGrantUriPermission(eq(UID_N_MR1), any(), any(), - anyInt(), eq(UserHandle.getUserId(UID_N_MR1))); - - final NotificationChannel channel = new NotificationChannel("id2", "name2", - NotificationManager.IMPORTANCE_DEFAULT); - channel.setSound(sound, mAudioAttributes); - - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1, - false); - assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true) - .getSound()).isEqualTo(sound); - } - - @Test - public void testCreateChannel_noSoundUriPermission_resourceSchemaIgnored() { - final Uri sound = Uri.parse(SCHEME_ANDROID_RESOURCE + "://resId/sound"); - - doThrow(new SecurityException("no access")).when(mUgmInternal) - .checkGrantUriPermission(eq(UID_N_MR1), any(), any(), - anyInt(), eq(UserHandle.getUserId(UID_N_MR1))); - - final NotificationChannel channel = new NotificationChannel("id2", "name2", - NotificationManager.IMPORTANCE_DEFAULT); - channel.setSound(sound, mAudioAttributes); - - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1, - false); - assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true) - .getSound()).isEqualTo(sound); - } - - @Test public void testPermanentlyDeleteChannels() throws Exception { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); @@ -7086,10 +7029,9 @@ public class PreferencesHelperTest extends UiServiceTestCase { ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles, - UriGrantsManagerInternal ugmInternal, boolean showReviewPermissionsNotification, Clock clock) { super(context, pm, rankingHandler, zenHelper, permHelper, permManager, - notificationChannelLogger, appOpsManager, userProfiles, ugmInternal, + notificationChannelLogger, appOpsManager, userProfiles, showReviewPermissionsNotification, clock); } diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index d7f91e009c92..2093ccc86653 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -156,19 +156,6 @@ class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(f flicker.assertLayers { isVisible(testApp) } } - /** Checks that [testApp] layer covers the entire screen during the whole transition */ - @Presubmit - @Test - fun appLayerRotates() { - flicker.assertLayers { - this.invoke("entireScreenCovered") { entry -> - entry.entry.displays.map { display -> - entry.visibleRegion(testApp).coversExactly(display.layerStackSpace) - } - } - } - } - /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is full screen") @@ -225,7 +212,6 @@ class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(f visibleLayersShownMoreThanOneConsecutiveEntry() visibleWindowsShownMoreThanOneConsecutiveEntry() - runAndIgnoreAssumptionViolation { appLayerRotates() } runAndIgnoreAssumptionViolation { appLayerAlwaysVisible() } runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() } runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() } diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index 7c24a4adca3d..98af8b2f53b5 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -39,7 +39,6 @@ android:value="true" /> <activity android:name=".SimpleActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity" - android:theme="@style/CutoutShortEdges" android:label="SimpleActivity" android:exported="true"> <intent-filter> @@ -49,7 +48,6 @@ </activity> <activity android:name=".ImeActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity" - android:theme="@style/CutoutShortEdges" android:label="ImeActivity" android:exported="true"> <intent-filter> @@ -58,7 +56,6 @@ </intent-filter> </activity> <activity android:name=".ImeActivityAutoFocus" - android:theme="@style/CutoutShortEdges" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus" android:windowSoftInputMode="stateVisible" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" @@ -81,7 +78,6 @@ </activity> <activity android:name=".SeamlessRotationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:showWhenLocked="true" android:label="SeamlessActivity" @@ -92,7 +88,6 @@ </intent-filter> </activity> <activity android:name=".NonResizeableActivity" - android:theme="@style/CutoutShortEdges" android:resizeableActivity="false" android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity" android:label="NonResizeableActivity" @@ -174,7 +169,6 @@ </activity> <activity android:name=".LaunchNewActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="LaunchNewActivity" android:exported="true"> @@ -185,7 +179,6 @@ </activity> <activity android:name=".LaunchNewTaskActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewTaskActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="LaunchNewTaskActivity" android:exported="true"> @@ -207,7 +200,6 @@ </activity> <activity android:name=".PortraitOnlyActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity" - android:theme="@style/CutoutShortEdges" android:screenOrientation="portrait" android:configChanges="orientation|screenSize" android:exported="true"> @@ -219,7 +211,6 @@ <activity android:name=".ImeEditorPopupDialogActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeEditorPopupDialogActivity" android:configChanges="orientation|screenSize" - android:theme="@style/CutoutShortEdges" android:label="ImeEditorPopupDialogActivity" android:exported="true"> <intent-filter> @@ -229,7 +220,6 @@ </activity> <activity android:name=".ShowWhenLockedActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ShowWhenLockedActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="ShowWhenLockedActivity" android:showWhenLocked="true" @@ -241,7 +231,6 @@ </activity> <activity android:name=".NotificationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.NotificationActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="NotificationActivity" android:exported="true"> @@ -254,7 +243,6 @@ android:name=".ActivityEmbeddingMainActivity" android:label="ActivityEmbedding Main" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="true"> <intent-filter> @@ -266,7 +254,6 @@ android:name=".ActivityEmbeddingTrampolineActivity" android:label="ActivityEmbedding Trampoline" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"> </activity> @@ -274,7 +261,6 @@ android:name=".ActivityEmbeddingSecondaryActivity" android:label="ActivityEmbedding Secondary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:supportsPictureInPicture="true" android:exported="false"/> @@ -282,21 +268,18 @@ android:name=".ActivityEmbeddingThirdActivity" android:label="ActivityEmbedding Third" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".ActivityEmbeddingAlwaysExpandActivity" android:label="ActivityEmbedding AlwaysExpand" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".ActivityEmbeddingPlaceholderPrimaryActivity" android:label="ActivityEmbedding Placeholder Primary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"> </activity> @@ -304,7 +287,6 @@ android:name=".ActivityEmbeddingPlaceholderSecondaryActivity" android:label="ActivityEmbedding Placeholder Secondary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".MailActivity" @@ -334,7 +316,6 @@ android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity" - android:theme="@style/CutoutShortEdges" android:launchMode="singleTop" android:label="PipActivity" android:exported="true"> @@ -350,7 +331,6 @@ <activity android:name=".BottomHalfPipLaunchingActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:taskAffinity="com.android.server.wm.flicker.testapp.BottomHalfPipLaunchingActivity" - android:theme="@style/CutoutShortEdges" android:label="BottomHalfPipLaunchingActivity" android:exported="true"> <intent-filter> @@ -371,7 +351,6 @@ <activity android:name=".SplitScreenActivity" android:resizeableActivity="true" android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenActivity" - android:theme="@style/CutoutShortEdges" android:label="SplitScreenPrimaryActivity" android:exported="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> @@ -383,7 +362,6 @@ <activity android:name=".SplitScreenSecondaryActivity" android:resizeableActivity="true" android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenSecondaryActivity" - android:theme="@style/CutoutShortEdges" android:label="SplitScreenSecondaryActivity" android:exported="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> @@ -396,7 +374,6 @@ </activity> <activity android:name=".SendNotificationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SendNotificationActivity" - android:theme="@style/CutoutShortEdges" android:label="SendNotificationActivity" android:exported="true"> <intent-filter> @@ -408,7 +385,6 @@ android:name=".LaunchBubbleActivity" android:label="LaunchBubbleActivity" android:exported="true" - android:theme="@style/CutoutShortEdges" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN"/> @@ -420,7 +396,6 @@ android:name=".BubbleActivity" android:label="BubbleActivity" android:exported="false" - android:theme="@style/CutoutShortEdges" android:resizeableActivity="true"/> <activity android:name=".TransferSplashscreenActivity" @@ -468,4 +443,4 @@ </service> </application> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> -</manifest> +</manifest>
\ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml index 507c1b622613..5e5203cb0545 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml @@ -17,6 +17,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_green_light" + android:fitsSystemWindows="true" android:focusableInTouchMode="true" android:orientation="vertical"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml index 8a97433ede04..fcef791afe2e 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml @@ -19,6 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" + android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml index 5d94e5177dcc..42213d6812da 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> </LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml index 0b4693dec6e1..4d12168ca8db 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml @@ -19,6 +19,7 @@ android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <SurfaceView diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml index 837d050b73ff..ca3244820893 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml @@ -36,10 +36,6 @@ <item name="android:windowLayoutInDisplayCutoutMode">default</item> </style> - <style name="CutoutShortEdges" parent="@style/DefaultTheme"> - <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> - </style> - <style name="CutoutNever" parent="@style/DefaultTheme"> <item name="android:windowLayoutInDisplayCutoutMode">never</item> </style> @@ -78,4 +74,4 @@ <!-- Here we want to match the duration of our AVD --> <item name="android:windowSplashScreenAnimationDuration">900</item> </style> -</resources> +</resources>
\ No newline at end of file |