summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayManager.java10
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java18
-rw-r--r--core/java/android/os/PowerManager.java8
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java6
-rw-r--r--media/java/android/media/OWNERS3
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt222
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt500
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt76
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java112
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt139
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt130
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt2
-rw-r--r--services/core/java/com/android/server/DockObserver.java68
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java22
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java85
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java65
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java50
-rw-r--r--tests/CompanionDeviceMultiDeviceTests/host/Android.bp9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt4
70 files changed, 1653 insertions, 887 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 0590a06f3f82..34e86a414533 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -623,6 +623,9 @@ public final class DisplayManager {
* is triggered whenever the properties of a {@link android.view.Display}, such as size,
* state, density are modified.
*
+ * This event is not triggered for refresh rate changes as they can change very often.
+ * To monitor refresh rate changes, subscribe to {@link EVENT_TYPE_DISPLAY_REFRESH_RATE}.
+ *
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
*/
@@ -801,6 +804,9 @@ public final class DisplayManager {
* Registers a display listener to receive notifications about when
* displays are added, removed or changed.
*
+ * We encourage to use {@link #registerDisplayListener(Executor, long, DisplayListener)}
+ * instead to subscribe for explicit events of interest
+ *
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
@@ -809,7 +815,9 @@ public final class DisplayManager {
*/
public void registerDisplayListener(DisplayListener listener, Handler handler) {
registerDisplayListener(listener, handler, EVENT_TYPE_DISPLAY_ADDED
- | EVENT_TYPE_DISPLAY_CHANGED | EVENT_TYPE_DISPLAY_REMOVED);
+ | EVENT_TYPE_DISPLAY_CHANGED
+ | EVENT_TYPE_DISPLAY_REFRESH_RATE
+ | EVENT_TYPE_DISPLAY_REMOVED);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index b5715ed25bd9..339dbf2c2029 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -1766,29 +1766,23 @@ public final class DisplayManagerGlobal {
}
if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_CHANGED) != 0) {
- // For backward compatibility, a client subscribing to
- // DisplayManager.EVENT_FLAG_DISPLAY_CHANGED will be enrolled to both Basic and
- // RR changes
- baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED
- | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+ baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED;
}
- if ((eventFlags
- & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) {
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
}
- if (Flags.displayListenerPerformanceImprovements()) {
- if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) {
- baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
- }
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) {
+ baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+ }
+ if (Flags.displayListenerPerformanceImprovements()) {
if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_STATE) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE;
}
}
-
return baseEventMask;
}
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 2a5666cbe83c..e769abec7dd9 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -624,6 +624,7 @@ public final class PowerManager {
WAKE_REASON_TAP,
WAKE_REASON_LIFT,
WAKE_REASON_BIOMETRIC,
+ WAKE_REASON_DOCK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WakeReason{}
@@ -765,6 +766,12 @@ public final class PowerManager {
public static final int WAKE_REASON_BIOMETRIC = 17;
/**
+ * Wake up reason code: Waking up due to a user docking the device.
+ * @hide
+ */
+ public static final int WAKE_REASON_DOCK = 18;
+
+ /**
* Convert the wake reason to a string for debugging purposes.
* @hide
*/
@@ -788,6 +795,7 @@ public final class PowerManager {
case WAKE_REASON_TAP: return "WAKE_REASON_TAP";
case WAKE_REASON_LIFT: return "WAKE_REASON_LIFT";
case WAKE_REASON_BIOMETRIC: return "WAKE_REASON_BIOMETRIC";
+ case WAKE_REASON_DOCK: return "WAKE_REASON_DOCK";
default: return Integer.toString(wakeReason);
}
}
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index 8fa510381060..dc2f0a69375d 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -307,8 +307,10 @@ public class DisplayManagerGlobalTest {
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
mDisplayManagerGlobal
.mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_ADDED, 0));
- assertEquals(DISPLAY_CHANGE_EVENTS, mDisplayManagerGlobal
- .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, 0));
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED,
+ mDisplayManagerGlobal
+ .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED,
+ 0));
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED,
mDisplayManagerGlobal.mapFiltersToInternalEventFlag(
DisplayManager.EVENT_TYPE_DISPLAY_REMOVED, 0));
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index b6096a1acd85..a600017119e2 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -1,6 +1,7 @@
# Bug component: 1344
-fgoldfain@google.com
+pshehane@google.com
elaurent@google.com
+etalvala@google.com
lajos@google.com
jmtrivi@google.com
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index dace50fafbf1..b421e69f5171 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -196,6 +196,18 @@ flag {
}
flag {
+ name: "notification_undo_guts_on_config_changed"
+ namespace: "systemui"
+ description: "Fixes a bug where a theme or font change while notification guts were open"
+ " (e.g. the snooze options or notification info) would show an empty notification by"
+ " closing the guts and undoing changes."
+ bug: "379267630"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "pss_app_selector_recents_split_screen"
namespace: "systemui"
description: "Allows recent apps selected for partial screenshare to be launched in split screen mode"
@@ -575,20 +587,6 @@ flag {
}
flag {
- name: "clock_reactive_variants"
- namespace: "systemui"
- description: "Add reactive variant fonts to some clocks"
- bug: "343495953"
-}
-
-flag {
- name: "lockscreen_custom_clocks"
- namespace: "systemui"
- description: "Enable lockscreen custom clocks"
- bug: "378486437"
-}
-
-flag {
name: "faster_unlock_transition"
namespace: "systemui"
description: "Faster wallpaper unlock transition"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index 809099e0d464..eb1f1d9c52f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -38,19 +38,19 @@ import com.android.systemui.communal.data.model.DisabledReason
import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl.Companion.GLANCEABLE_HUB_BACKGROUND_SETTING
import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled
import com.android.systemui.communal.shared.model.CommunalBackgroundType
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
-import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,9 +62,11 @@ import platform.test.runner.parameterized.Parameters
@RunWith(ParameterizedAndroidJunit4::class)
class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val kosmos =
- testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources }
- private val testScope = kosmos.testScope
- private lateinit var underTest: CommunalSettingsRepository
+ testKosmos()
+ .apply { mainResources = mContext.orCreateTestableResources.resources }
+ .useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by Kosmos.Fixture { communalSettingsRepository }
init {
mSetFlagsRule.setFlagsParameterization(flags!!)
@@ -76,98 +78,105 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE)
setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE)
setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE)
- underTest = kosmos.communalSettingsRepository
}
@EnableFlags(FLAG_COMMUNAL_HUB)
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
@Test
- fun getFlagEnabled_bothEnabled() {
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
+ fun getFlagEnabled_bothEnabled() =
+ kosmos.runTest {
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
- assertThat(underTest.getFlagEnabled()).isTrue()
- }
+ assertThat(underTest.getFlagEnabled()).isTrue()
+ }
@DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
@Test
- fun getFlagEnabled_bothDisabled() {
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
+ fun getFlagEnabled_bothDisabled() =
+ kosmos.runTest {
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
- assertThat(underTest.getFlagEnabled()).isFalse()
- }
+ assertThat(underTest.getFlagEnabled()).isFalse()
+ }
@DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
@Test
- fun getFlagEnabled_onlyClassicFlagEnabled() {
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
+ fun getFlagEnabled_onlyClassicFlagEnabled() =
+ kosmos.runTest {
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
- assertThat(underTest.getFlagEnabled()).isFalse()
- }
+ assertThat(underTest.getFlagEnabled()).isFalse()
+ }
@EnableFlags(FLAG_COMMUNAL_HUB)
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
@Test
- fun getFlagEnabled_onlyTrunkFlagEnabled() {
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
+ fun getFlagEnabled_onlyTrunkFlagEnabled() =
+ kosmos.runTest {
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
- assertThat(underTest.getFlagEnabled()).isFalse()
- }
+ assertThat(underTest.getFlagEnabled()).isFalse()
+ }
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
@DisableFlags(FLAG_COMMUNAL_HUB)
@Test
- fun getFlagEnabled_mobileConfigEnabled() {
- mContext.orCreateTestableResources.addOverride(
- com.android.internal.R.bool.config_glanceableHubEnabled,
- true,
- )
+ fun getFlagEnabled_mobileConfigEnabled() =
+ kosmos.runTest {
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_glanceableHubEnabled,
+ true,
+ )
- assertThat(underTest.getFlagEnabled()).isTrue()
- }
+ assertThat(underTest.getFlagEnabled()).isTrue()
+ }
@DisableFlags(FLAG_GLANCEABLE_HUB_V2, FLAG_COMMUNAL_HUB)
@Test
- fun getFlagEnabled_onlyMobileConfigEnabled() {
- mContext.orCreateTestableResources.addOverride(
- com.android.internal.R.bool.config_glanceableHubEnabled,
- true,
- )
+ fun getFlagEnabled_onlyMobileConfigEnabled() =
+ kosmos.runTest {
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_glanceableHubEnabled,
+ true,
+ )
- assertThat(underTest.getFlagEnabled()).isFalse()
- }
+ assertThat(underTest.getFlagEnabled()).isFalse()
+ }
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
@DisableFlags(FLAG_COMMUNAL_HUB)
@Test
- fun getFlagEnabled_onlyMobileFlagEnabled() {
- mContext.orCreateTestableResources.addOverride(
- com.android.internal.R.bool.config_glanceableHubEnabled,
- false,
- )
+ fun getFlagEnabled_onlyMobileFlagEnabled() =
+ kosmos.runTest {
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_glanceableHubEnabled,
+ false,
+ )
- assertThat(underTest.getFlagEnabled()).isFalse()
- }
+ assertThat(underTest.getFlagEnabled()).isFalse()
+ }
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
@DisableFlags(FLAG_COMMUNAL_HUB)
@Test
- fun getFlagEnabled_oldFlagIgnored() {
- // New config flag enabled.
- mContext.orCreateTestableResources.addOverride(
- com.android.internal.R.bool.config_glanceableHubEnabled,
- true,
- )
+ fun getFlagEnabled_oldFlagIgnored() =
+ kosmos.runTest {
+ // New config flag enabled.
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_glanceableHubEnabled,
+ true,
+ )
- // Old config flag disabled.
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
+ // Old config flag disabled.
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
- assertThat(underTest.getFlagEnabled()).isTrue()
- }
+ assertThat(underTest.getFlagEnabled()).isTrue()
+ }
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun secondaryUserIsInvalid() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getEnabledState(SECONDARY_USER))
assertThat(enabledState?.enabled).isFalse()
@@ -187,7 +196,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
@Test
fun communalHubFlagIsDisabled() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
assertThat(enabledState?.enabled).isFalse()
assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG)
@@ -196,35 +205,23 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun hubIsDisabledByUser() =
- testScope.runTest {
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.GLANCEABLE_HUB_ENABLED,
- 0,
- PRIMARY_USER.id,
- )
+ kosmos.runTest {
+ fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id)
val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
assertThat(enabledState?.enabled).isFalse()
assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_USER_SETTING)
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.GLANCEABLE_HUB_ENABLED,
- 1,
- SECONDARY_USER.id,
- )
+ fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, SECONDARY_USER.id)
assertThat(enabledState?.enabled).isFalse()
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.GLANCEABLE_HUB_ENABLED,
- 1,
- PRIMARY_USER.id,
- )
+ fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, PRIMARY_USER.id)
assertThat(enabledState?.enabled).isTrue()
}
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun hubIsDisabledByDevicePolicy() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
assertThat(enabledState?.enabled).isTrue()
@@ -236,7 +233,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() =
- testScope.runTest {
+ kosmos.runTest {
val widgetsAllowedForWorkProfile by
collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE))
assertThat(widgetsAllowedForWorkProfile).isTrue()
@@ -248,7 +245,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() =
- testScope.runTest {
+ kosmos.runTest {
val enabledStateForPrimaryUser by
collectLastValue(underTest.getEnabledState(PRIMARY_USER))
assertThat(enabledStateForPrimaryUser?.enabled).isTrue()
@@ -260,15 +257,11 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
fun hubIsDisabledByUserAndDevicePolicy() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
assertThat(enabledState?.enabled).isTrue()
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.GLANCEABLE_HUB_ENABLED,
- 0,
- PRIMARY_USER.id,
- )
+ fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id)
setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL)
assertThat(enabledState?.enabled).isFalse()
@@ -282,17 +275,17 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@Test
@DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND)
fun backgroundType_defaultValue() =
- testScope.runTest {
+ kosmos.runTest {
val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER))
assertThat(backgroundType).isEqualTo(CommunalBackgroundType.ANIMATED)
}
@Test
fun backgroundType_verifyAllValues() =
- testScope.runTest {
+ kosmos.runTest {
val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER))
for (type in CommunalBackgroundType.entries) {
- kosmos.fakeSettings.putIntForUser(
+ fakeSettings.putIntForUser(
GLANCEABLE_HUB_BACKGROUND_SETTING,
type.value,
PRIMARY_USER.id,
@@ -308,30 +301,71 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT
@Test
fun screensaverDisabledByUser() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER))
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.SCREENSAVER_ENABLED,
- 0,
- PRIMARY_USER.id,
- )
+ fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 0, PRIMARY_USER.id)
assertThat(enabledState).isFalse()
}
@Test
fun screensaverEnabledByUser() =
- testScope.runTest {
+ kosmos.runTest {
val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER))
- kosmos.fakeSettings.putIntForUser(
- Settings.Secure.SCREENSAVER_ENABLED,
+ fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 1, PRIMARY_USER.id)
+
+ assertThat(enabledState).isTrue()
+ }
+
+ @Test
+ fun whenToDream_charging() =
+ kosmos.runTest {
+ val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))
+
+ fakeSettings.putIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
1,
PRIMARY_USER.id,
)
- assertThat(enabledState).isTrue()
+ assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_CHARGING)
+ }
+
+ @Test
+ fun whenToDream_docked() =
+ kosmos.runTest {
+ val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))
+
+ fakeSettings.putIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 1,
+ PRIMARY_USER.id,
+ )
+
+ assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_DOCKED)
+ }
+
+ @Test
+ fun whenToDream_postured() =
+ kosmos.runTest {
+ val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))
+
+ fakeSettings.putIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1,
+ PRIMARY_USER.id,
+ )
+
+ assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_POSTURED)
+ }
+
+ @Test
+ fun whenToDream_default() =
+ kosmos.runTest {
+ val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER))
+ assertThat(whenToDreamState).isEqualTo(WhenToDream.NEVER)
}
private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 7ae0577bd289..c9e7a5d7df05 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -38,13 +38,9 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.common.data.repository.batteryRepository
+import com.android.systemui.common.data.repository.fake
import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
-import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
-import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository
-import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
-import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
@@ -53,52 +49,49 @@ import com.android.systemui.communal.data.repository.fakeCommunalTutorialReposit
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
+import com.android.systemui.communal.posturing.data.repository.fake
+import com.android.systemui.communal.posturing.data.repository.posturingRepository
+import com.android.systemui.communal.posturing.shared.model.PosturedState
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.EditModeState
-import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
-import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.plugins.activityStarter
-import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.statusbar.phone.fakeManagedProfileController
import com.android.systemui.testKosmos
-import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.utils.leaks.FakeManagedProfileController
+import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -107,32 +100,15 @@ import platform.test.runner.parameterized.Parameters
* [CommunalInteractorCommunalDisabledTest].
*/
@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(ParameterizedAndroidJunit4::class)
class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
- @Mock private lateinit var mainUser: UserInfo
- @Mock private lateinit var secondaryUser: UserInfo
-
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
-
- private lateinit var tutorialRepository: FakeCommunalTutorialRepository
- private lateinit var communalRepository: FakeCommunalSceneRepository
- private lateinit var mediaRepository: FakeCommunalMediaRepository
- private lateinit var widgetRepository: FakeCommunalWidgetRepository
- private lateinit var smartspaceRepository: FakeCommunalSmartspaceRepository
- private lateinit var userRepository: FakeUserRepository
- private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var communalPrefsRepository: FakeCommunalPrefsRepository
- private lateinit var editWidgetsActivityStarter: EditWidgetsActivityStarter
- private lateinit var sceneInteractor: SceneInteractor
- private lateinit var communalSceneInteractor: CommunalSceneInteractor
- private lateinit var userTracker: FakeUserTracker
- private lateinit var activityStarter: ActivityStarter
- private lateinit var userManager: UserManager
- private lateinit var managedProfileController: FakeManagedProfileController
-
- private lateinit var underTest: CommunalInteractor
+ private val mainUser =
+ UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)
+ private val secondaryUser = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0)
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by Kosmos.Fixture { communalInteractor }
init {
mSetFlagsRule.setFlagsParameterization(flags)
@@ -140,128 +116,104 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- tutorialRepository = kosmos.fakeCommunalTutorialRepository
- communalRepository = kosmos.fakeCommunalSceneRepository
- mediaRepository = kosmos.fakeCommunalMediaRepository
- widgetRepository = kosmos.fakeCommunalWidgetRepository
- smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
- userRepository = kosmos.fakeUserRepository
- keyguardRepository = kosmos.fakeKeyguardRepository
- editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter
- communalPrefsRepository = kosmos.fakeCommunalPrefsRepository
- sceneInteractor = kosmos.sceneInteractor
- communalSceneInteractor = kosmos.communalSceneInteractor
- userTracker = kosmos.fakeUserTracker
- activityStarter = kosmos.activityStarter
- userManager = kosmos.userManager
- managedProfileController = kosmos.fakeManagedProfileController
-
- whenever(mainUser.isMain).thenReturn(true)
- whenever(secondaryUser.isMain).thenReturn(false)
- whenever(userManager.isQuietModeEnabled(any<UserHandle>())).thenReturn(false)
- whenever(userManager.isManagedProfile(anyInt())).thenReturn(false)
- userRepository.setUserInfos(listOf(mainUser, secondaryUser))
+ whenever(kosmos.userManager.isQuietModeEnabled(any<UserHandle>())).thenReturn(false)
+ whenever(kosmos.userManager.isManagedProfile(anyInt())).thenReturn(false)
+ kosmos.fakeUserRepository.setUserInfos(listOf(mainUser, secondaryUser))
kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
-
- underTest = kosmos.communalInteractor
}
@Test
fun communalEnabled_true() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(mainUser)
- runCurrent()
+ kosmos.runTest {
+ fakeUserRepository.setSelectedUserInfo(mainUser)
assertThat(underTest.isCommunalEnabled.value).isTrue()
}
@Test
fun isCommunalAvailable_storageUnlockedAndMainUser_true() =
- testScope.runTest {
+ kosmos.runTest {
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
- keyguardRepository.setIsEncryptedOrLockdown(false)
- userRepository.setSelectedUserInfo(mainUser)
- keyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isTrue()
}
@Test
fun isCommunalAvailable_storageLockedAndMainUser_false() =
- testScope.runTest {
+ kosmos.runTest {
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
- keyguardRepository.setIsEncryptedOrLockdown(true)
- userRepository.setSelectedUserInfo(mainUser)
- keyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(true)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isFalse()
}
@Test
fun isCommunalAvailable_storageUnlockedAndSecondaryUser_false() =
- testScope.runTest {
+ kosmos.runTest {
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
- keyguardRepository.setIsEncryptedOrLockdown(false)
- userRepository.setSelectedUserInfo(secondaryUser)
- keyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(secondaryUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isFalse()
}
@Test
fun isCommunalAvailable_whenKeyguardShowing_true() =
- testScope.runTest {
+ kosmos.runTest {
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
- keyguardRepository.setIsEncryptedOrLockdown(false)
- userRepository.setSelectedUserInfo(mainUser)
- keyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isTrue()
}
@Test
fun isCommunalAvailable_communalDisabled_false() =
- testScope.runTest {
+ kosmos.runTest {
mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
val isAvailable by collectLastValue(underTest.isCommunalAvailable)
assertThat(isAvailable).isFalse()
- keyguardRepository.setIsEncryptedOrLockdown(false)
- userRepository.setSelectedUserInfo(mainUser)
- keyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
assertThat(isAvailable).isFalse()
}
@Test
fun widget_tutorialCompletedAndWidgetsAvailable_showWidgetContent() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// Widgets available.
- widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
- widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
- widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
val widgetContent by collectLastValue(underTest.widgetContent)
@@ -356,18 +308,18 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
totalTargets: Int,
expectedSizes: List<CommunalContentSize>,
) =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
val targets = mutableListOf<CommunalSmartspaceTimer>()
for (index in 0 until totalTargets) {
targets.add(smartspaceTimer(index.toString()))
}
- smartspaceRepository.setTimers(targets)
+ fakeCommunalSmartspaceRepository.setTimers(targets)
val smartspaceContent by collectLastValue(underTest.ongoingContent(false))
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
@@ -378,12 +330,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun umo_mediaPlaying_showsUmo() =
- testScope.runTest {
+ kosmos.runTest {
// Tutorial completed.
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
// Media is playing.
- mediaRepository.mediaActive()
+ fakeCommunalMediaRepository.mediaActive()
val umoContent by collectLastValue(underTest.ongoingContent(true))
@@ -394,12 +346,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun umo_mediaPlaying_mediaHostNotVisible_hidesUmo() =
- testScope.runTest {
+ kosmos.runTest {
// Tutorial completed.
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
// Media is playing.
- mediaRepository.mediaActive()
+ fakeCommunalMediaRepository.mediaActive()
val umoContent by collectLastValue(underTest.ongoingContent(false))
assertThat(umoContent?.size).isEqualTo(0)
@@ -409,26 +361,26 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
@DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
fun ongoing_shouldOrderAndSizeByTimestamp() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
// Timer1 started
val timer1 = smartspaceTimer("timer1", timestamp = 1L)
- smartspaceRepository.setTimers(listOf(timer1))
+ fakeCommunalSmartspaceRepository.setTimers(listOf(timer1))
// Umo started
- mediaRepository.mediaActive(timestamp = 2L)
+ fakeCommunalMediaRepository.mediaActive(timestamp = 2L)
// Timer2 started
val timer2 = smartspaceTimer("timer2", timestamp = 3L)
- smartspaceRepository.setTimers(listOf(timer1, timer2))
+ fakeCommunalSmartspaceRepository.setTimers(listOf(timer1, timer2))
// Timer3 started
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
- smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
+ fakeCommunalSmartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
val ongoingContent by collectLastValue(underTest.ongoingContent(true))
assertThat(ongoingContent?.size).isEqualTo(4)
@@ -447,8 +399,8 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun ctaTile_showsByDefault() =
- testScope.runTest {
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ kosmos.runTest {
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
val ctaTileContent by collectLastValue(underTest.ctaTileContent)
@@ -461,14 +413,13 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun ctaTile_afterDismiss_doesNotShow() =
- testScope.runTest {
+ kosmos.runTest {
// Set to main user, so we can dismiss the tile for the main user.
- val user = userRepository.asMainUser()
- userTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
- runCurrent()
+ val user = fakeUserRepository.asMainUser()
+ fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
- communalPrefsRepository.setCtaDismissed(user)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeCommunalPrefsRepository.setCtaDismissed(user)
val ctaTileContent by collectLastValue(underTest.ctaTileContent)
@@ -477,36 +428,30 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun listensToSceneChange() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
- runCurrent()
- var desiredScene = collectLastValue(underTest.desiredScene)
- runCurrent()
- assertThat(desiredScene()).isEqualTo(CommunalScenes.Blank)
+ val desiredScene by collectLastValue(underTest.desiredScene)
+ assertThat(desiredScene).isEqualTo(CommunalScenes.Blank)
val targetScene = CommunalScenes.Communal
- communalRepository.changeScene(targetScene)
- desiredScene = collectLastValue(underTest.desiredScene)
- runCurrent()
- assertThat(desiredScene()).isEqualTo(targetScene)
+ fakeCommunalSceneRepository.changeScene(targetScene)
+ assertThat(desiredScene).isEqualTo(targetScene)
}
@Test
fun updatesScene() =
- testScope.runTest {
+ kosmos.runTest {
val targetScene = CommunalScenes.Communal
-
underTest.changeScene(targetScene, "test")
- val desiredScene = collectLastValue(communalRepository.currentScene)
- runCurrent()
- assertThat(desiredScene()).isEqualTo(targetScene)
+ val desiredScene by collectLastValue(fakeCommunalSceneRepository.currentScene)
+ assertThat(desiredScene).isEqualTo(targetScene)
}
@Test
fun transitionProgress_onTargetScene_fullProgress() =
- testScope.runTest {
+ kosmos.runTest {
val targetScene = CommunalScenes.Blank
val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
val transitionProgress by collectLastValue(transitionProgressFlow)
@@ -524,7 +469,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun transitionProgress_notOnTargetScene_noProgress() =
- testScope.runTest {
+ kosmos.runTest {
val targetScene = CommunalScenes.Blank
val currentScene = CommunalScenes.Communal
val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
@@ -543,7 +488,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun transitionProgress_transitioningToTrackedScene() =
- testScope.runTest {
+ kosmos.runTest {
val currentScene = CommunalScenes.Communal
val targetScene = CommunalScenes.Blank
val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
@@ -591,7 +536,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun transitionProgress_transitioningAwayFromTrackedScene() =
- testScope.runTest {
+ kosmos.runTest {
val currentScene = CommunalScenes.Blank
val targetScene = CommunalScenes.Communal
val transitionProgressFlow = underTest.transitionProgressToScene(currentScene)
@@ -642,52 +587,42 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun isCommunalShowing() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
- runCurrent()
- var isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
- runCurrent()
- assertThat(isCommunalShowing()).isEqualTo(false)
+ val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
+ assertThat(isCommunalShowing).isEqualTo(false)
underTest.changeScene(CommunalScenes.Communal, "test")
-
- isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
- runCurrent()
- assertThat(isCommunalShowing()).isEqualTo(true)
+ assertThat(isCommunalShowing).isEqualTo(true)
}
@Test
fun isCommunalShowing_whenSceneContainerDisabled() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
- runCurrent()
// Verify default is false
val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
- runCurrent()
assertThat(isCommunalShowing).isFalse()
// Verify scene changes with the flag doesn't have any impact
sceneInteractor.changeScene(Scenes.Communal, loggingReason = "")
- runCurrent()
assertThat(isCommunalShowing).isFalse()
// Verify scene changes (without the flag) to communal sets the value to true
underTest.changeScene(CommunalScenes.Communal, "test")
- runCurrent()
assertThat(isCommunalShowing).isTrue()
// Verify scene changes (without the flag) to blank sets the value back to false
underTest.changeScene(CommunalScenes.Blank, "test")
- runCurrent()
assertThat(isCommunalShowing).isFalse()
}
@Test
@EnableSceneContainer
fun isCommunalShowing_whenSceneContainerEnabled() =
- testScope.runTest {
+ kosmos.runTest {
// Verify default is false
val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
assertThat(isCommunalShowing).isFalse()
@@ -704,7 +639,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
@EnableSceneContainer
fun isCommunalShowing_whenSceneContainerEnabledAndChangeToLegacyScene() =
- testScope.runTest {
+ kosmos.runTest {
// Verify default is false
val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
assertThat(isCommunalShowing).isFalse()
@@ -720,21 +655,19 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun isIdleOnCommunal() =
- testScope.runTest {
+ kosmos.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(CommunalScenes.Blank)
)
- communalRepository.setTransitionState(transitionState)
+ fakeCommunalSceneRepository.setTransitionState(transitionState)
// isIdleOnCommunal is false when not on communal.
val isIdleOnCommunal by collectLastValue(underTest.isIdleOnCommunal)
- runCurrent()
assertThat(isIdleOnCommunal).isEqualTo(false)
// Transition to communal.
transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)
- runCurrent()
// isIdleOnCommunal is now true since we're on communal.
assertThat(isIdleOnCommunal).isEqualTo(true)
@@ -749,7 +682,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
isInitiatedByUserInput = false,
isUserInputOngoing = flowOf(false),
)
- runCurrent()
// isIdleOnCommunal turns false as soon as transition away starts.
assertThat(isIdleOnCommunal).isEqualTo(false)
@@ -757,12 +689,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun isCommunalVisible() =
- testScope.runTest {
+ kosmos.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(CommunalScenes.Blank)
)
- communalRepository.setTransitionState(transitionState)
+ fakeCommunalSceneRepository.setTransitionState(transitionState)
// isCommunalVisible is false when not on communal.
val isCommunalVisible by collectLastValue(underTest.isCommunalVisible)
@@ -805,7 +737,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun testShowWidgetEditorStartsActivity() =
- testScope.runTest {
+ kosmos.runTest {
val editModeState by collectLastValue(communalSceneInteractor.editModeState)
underTest.showWidgetEditor()
@@ -816,14 +748,14 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showWidgetEditor_openWidgetPickerOnStart_startsActivity() =
- testScope.runTest {
+ kosmos.runTest {
underTest.showWidgetEditor(shouldOpenWidgetPickerOnStart = true)
verify(editWidgetsActivityStarter).startActivity(shouldOpenWidgetPickerOnStart = true)
}
@Test
fun navigateToCommunalWidgetSettings_startsActivity() =
- testScope.runTest {
+ kosmos.runTest {
underTest.navigateToCommunalWidgetSettings()
val intentCaptor = argumentCaptor<Intent>()
verify(activityStarter)
@@ -833,23 +765,22 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun filterWidgets_whenUserProfileRemoved() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
// Only main user exists.
val userInfos = listOf(MAIN_USER_INFO)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
val widgetContent by collectLastValue(underTest.widgetContent)
// Given three widgets, and one of them is associated with pre-existing work profile.
- widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
- widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
- widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
// One widget is filtered out and the remaining two link to main user id.
assertThat(checkNotNull(widgetContent).size).isEqualTo(2)
@@ -867,17 +798,16 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun widgetContent_inQuietMode() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
// Work profile is set up.
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// When work profile is paused.
whenever(userManager.isQuietModeEnabled(eq(UserHandle.of(USER_INFO_WORK.id))))
@@ -885,9 +815,9 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
whenever(userManager.isManagedProfile(eq(USER_INFO_WORK.id))).thenReturn(true)
val widgetContent by collectLastValue(underTest.widgetContent)
- widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
- widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
- widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
// The work profile widget is in quiet mode, while other widgets are not.
assertThat(widgetContent).hasSize(3)
@@ -911,23 +841,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- userRepository.setSelectedUserInfo(MAIN_USER_INFO)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+ fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
val widgetContent by collectLastValue(underTest.widgetContent)
// One available work widget, one pending work widget, and one regular available widget.
- widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
- widgetRepository.addPendingWidget(appWidgetId = 2, userId = USER_INFO_WORK.id)
- widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
+ fakeCommunalWidgetRepository.addPendingWidget(
+ appWidgetId = 2,
+ userId = USER_INFO_WORK.id,
+ )
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
@@ -941,23 +873,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun filterWidgets_whenAllowedByDevicePolicyForWorkProfile() =
- testScope.runTest {
+ kosmos.runTest {
// Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- userRepository.setSelectedUserInfo(MAIN_USER_INFO)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+ fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
val widgetContent by collectLastValue(underTest.widgetContent)
// Given three widgets, and one of them is associated with work profile.
- widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
- widgetRepository.addPendingWidget(appWidgetId = 2, userId = USER_INFO_WORK.id)
- widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
+ fakeCommunalWidgetRepository.addPendingWidget(
+ appWidgetId = 2,
+ userId = USER_INFO_WORK.id,
+ )
+ fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
@@ -973,7 +907,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showCommunalFromOccluded_enteredOccludedFromHub() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
assertThat(showCommunalFromOccluded).isFalse()
@@ -989,7 +923,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showCommunalFromOccluded_enteredOccludedFromLockscreen() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
assertThat(showCommunalFromOccluded).isFalse()
@@ -1005,7 +939,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showCommunalFromOccluded_communalBecomesUnavailableWhileOccluded() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
assertThat(showCommunalFromOccluded).isFalse()
@@ -1015,7 +949,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
to = KeyguardState.OCCLUDED,
testScope,
)
- runCurrent()
kosmos.setCommunalAvailable(false)
assertThat(showCommunalFromOccluded).isFalse()
@@ -1023,7 +956,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showCommunalFromOccluded_showBouncerWhileOccluded() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
assertThat(showCommunalFromOccluded).isFalse()
@@ -1033,7 +966,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
to = KeyguardState.OCCLUDED,
testScope,
)
- runCurrent()
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.OCCLUDED,
to = KeyguardState.PRIMARY_BOUNCER,
@@ -1045,7 +977,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun showCommunalFromOccluded_enteredOccludedFromDreaming() =
- testScope.runTest {
+ kosmos.runTest {
kosmos.setCommunalAvailable(true)
val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
assertThat(showCommunalFromOccluded).isFalse()
@@ -1069,7 +1001,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun dismissDisclaimerSetsDismissedFlag() =
- testScope.runTest {
+ kosmos.runTest {
val disclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed)
assertThat(disclaimerDismissed).isFalse()
underTest.setDisclaimerDismissed()
@@ -1078,17 +1010,17 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun dismissDisclaimerTimeoutResetsDismissedFlag() =
- testScope.runTest {
+ kosmos.runTest {
val disclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed)
underTest.setDisclaimerDismissed()
assertThat(disclaimerDismissed).isTrue()
- advanceTimeBy(CommunalInteractor.DISCLAIMER_RESET_MILLIS)
+ testScope.advanceTimeBy(CommunalInteractor.DISCLAIMER_RESET_MILLIS)
assertThat(disclaimerDismissed).isFalse()
}
@Test
fun settingSelectedKey_flowUpdated() {
- testScope.runTest {
+ kosmos.runTest {
val key = "test"
val selectedKey by collectLastValue(underTest.selectedKey)
underTest.setSelectedKey(key)
@@ -1098,36 +1030,35 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
fun unpauseWorkProfileEnablesWorkMode() =
- testScope.runTest {
+ kosmos.runTest {
underTest.unpauseWorkProfile()
- assertThat(managedProfileController.isWorkModeEnabled()).isTrue()
+ assertThat(fakeManagedProfileController.isWorkModeEnabled()).isTrue()
}
@Test
@EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
@DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
fun resizeWidget_withoutUpdatingOrder() =
- testScope.runTest {
+ kosmos.runTest {
val userInfos = listOf(MAIN_USER_INFO)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// Widgets available.
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 1,
userId = MAIN_USER_INFO.id,
rank = 0,
spanY = CommunalContentSize.FixedSize.HALF.span,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 2,
userId = MAIN_USER_INFO.id,
rank = 1,
spanY = CommunalContentSize.FixedSize.HALF.span,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 3,
userId = MAIN_USER_INFO.id,
rank = 2,
@@ -1159,26 +1090,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
@EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID)
fun resizeWidget_withoutUpdatingOrder_responsive() =
- testScope.runTest {
+ kosmos.runTest {
val userInfos = listOf(MAIN_USER_INFO)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// Widgets available.
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 1,
userId = MAIN_USER_INFO.id,
rank = 0,
spanY = 1,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 2,
userId = MAIN_USER_INFO.id,
rank = 1,
spanY = 1,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 3,
userId = MAIN_USER_INFO.id,
rank = 2,
@@ -1211,26 +1141,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
@DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
fun resizeWidget_andUpdateOrder() =
- testScope.runTest {
+ kosmos.runTest {
val userInfos = listOf(MAIN_USER_INFO)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// Widgets available.
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 1,
userId = MAIN_USER_INFO.id,
rank = 0,
spanY = CommunalContentSize.FixedSize.HALF.span,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 2,
userId = MAIN_USER_INFO.id,
rank = 1,
spanY = CommunalContentSize.FixedSize.HALF.span,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 3,
userId = MAIN_USER_INFO.id,
rank = 2,
@@ -1266,26 +1195,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
@EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID)
fun resizeWidget_andUpdateOrder_responsive() =
- testScope.runTest {
+ kosmos.runTest {
val userInfos = listOf(MAIN_USER_INFO)
- userRepository.setUserInfos(userInfos)
- userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
- runCurrent()
+ fakeUserRepository.setUserInfos(userInfos)
+ fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
// Widgets available.
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 1,
userId = MAIN_USER_INFO.id,
rank = 0,
spanY = 1,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 2,
userId = MAIN_USER_INFO.id,
rank = 1,
spanY = 1,
)
- widgetRepository.addWidget(
+ fakeCommunalWidgetRepository.addWidget(
appWidgetId = 3,
userId = MAIN_USER_INFO.id,
rank = 2,
@@ -1318,6 +1246,66 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
.inOrder()
}
+ @Test
+ fun showCommunalWhileCharging() =
+ kosmos.runTest {
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeSettings.putIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 1,
+ mainUser.id,
+ )
+
+ val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal)
+ batteryRepository.fake.setDevicePluggedIn(false)
+ assertThat(shouldShowCommunal).isFalse()
+
+ batteryRepository.fake.setDevicePluggedIn(true)
+ assertThat(shouldShowCommunal).isTrue()
+ }
+
+ @Test
+ fun showCommunalWhilePosturedAndCharging() =
+ kosmos.runTest {
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeSettings.putIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1,
+ mainUser.id,
+ )
+
+ val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal)
+ batteryRepository.fake.setDevicePluggedIn(true)
+ posturingRepository.fake.setPosturedState(PosturedState.NotPostured)
+ assertThat(shouldShowCommunal).isFalse()
+
+ posturingRepository.fake.setPosturedState(PosturedState.Postured(1f))
+ assertThat(shouldShowCommunal).isTrue()
+ }
+
+ @Test
+ fun showCommunalWhileDocked() =
+ kosmos.runTest {
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+ fakeUserRepository.setSelectedUserInfo(mainUser)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 1, mainUser.id)
+
+ batteryRepository.fake.setDevicePluggedIn(true)
+ fakeDockManager.setIsDocked(false)
+
+ val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal)
+ assertThat(shouldShowCommunal).isFalse()
+
+ fakeDockManager.setIsDocked(true)
+ fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
+ assertThat(shouldShowCommunal).isTrue()
+ }
+
private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id)))
.thenReturn(disabledFlags)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt
index e4916b1a7e46..310bf6486413 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt
@@ -21,19 +21,17 @@ import android.app.admin.devicePolicyManager
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserManager
-import android.os.userManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
-import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
-import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@@ -48,34 +46,20 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class CommunalSettingsInteractorTest : SysuiTestCase() {
- private lateinit var userManager: UserManager
- private lateinit var userRepository: FakeUserRepository
- private lateinit var userTracker: FakeUserTracker
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
-
- private lateinit var underTest: CommunalSettingsInteractor
+ private val Kosmos.underTest by Kosmos.Fixture { communalSettingsInteractor }
@Before
fun setUp() {
- userManager = kosmos.userManager
- userRepository = kosmos.fakeUserRepository
- userTracker = kosmos.fakeUserTracker
-
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
- userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
-
- underTest = kosmos.communalSettingsInteractor
+ kosmos.fakeUserRepository.setUserInfos(userInfos)
+ kosmos.fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0)
}
@Test
fun filterUsers_dontFilteredUsersWhenAllAreAllowed() =
- testScope.runTest {
+ kosmos.runTest {
// If no users have any keyguard features disabled...
val disallowedUser by
collectLastValue(underTest.workProfileUserDisallowedByDevicePolicy)
@@ -85,11 +69,11 @@ class CommunalSettingsInteractorTest : SysuiTestCase() {
@Test
fun filterUsers_filterWorkProfileUserWhenDisallowed() =
- testScope.runTest {
+ kosmos.runTest {
// If the work profile user has keyguard widgets disabled...
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
+ DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL,
)
// ...then the disallowed user match the work profile
val disallowedUser by
@@ -102,7 +86,7 @@ class CommunalSettingsInteractorTest : SysuiTestCase() {
whenever(
kosmos.devicePolicyManager.getKeyguardDisabledFeatures(
anyOrNull(),
- ArgumentMatchers.eq(user.id)
+ ArgumentMatchers.eq(user.id),
)
)
.thenReturn(disabledFlags)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
index 6c955bf1818d..5fd480f90ac9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
@@ -176,14 +176,14 @@ class DeviceEntryHapticsInteractorTest : SysuiTestCase() {
}
@Test
- fun nonPowerButtonFPS_coExFaceFailure_doNotVibrateError() =
+ fun nonPowerButtonFPS_coExFaceFailure_vibrateError() =
testScope.runTest {
val playErrorHaptic by collectLastValue(underTest.playErrorHaptic)
enrollFingerprint(FingerprintSensorType.UDFPS_ULTRASONIC)
enrollFace()
runCurrent()
faceFailure()
- assertThat(playErrorHaptic).isNull()
+ assertThat(playErrorHaptic).isNotNull()
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index ef70305a3f47..af30e435da73 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -1149,7 +1149,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
@DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
- fun skipsFaceErrorHaptics_nonSfps_coEx() =
+ fun playsFaceErrorHaptics_nonSfps_coEx() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
@@ -1161,14 +1161,15 @@ class SceneContainerStartableTest : SysuiTestCase() {
underTest.start()
updateFaceAuthStatus(isSuccess = false)
- assertThat(playErrorHaptic).isNull()
- verify(vibratorHelper, never()).vibrateAuthError(anyString())
+ assertThat(playErrorHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ verify(vibratorHelper).vibrateAuthError(anyString())
verify(vibratorHelper, never()).vibrateAuthSuccess(anyString())
}
@Test
@EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
- fun skipsMSDLFaceErrorHaptics_nonSfps_coEx() =
+ fun playsMSDLFaceErrorHaptics_nonSfps_coEx() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
@@ -1180,9 +1181,10 @@ class SceneContainerStartableTest : SysuiTestCase() {
underTest.start()
updateFaceAuthStatus(isSuccess = false)
- assertThat(playErrorHaptic).isNull()
- assertThat(msdlPlayer.latestTokenPlayed).isNull()
- assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
+ assertThat(playErrorHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
+ assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index 39c42f183481..28b2ee8dde06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -269,6 +269,36 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
}
@Test
+ fun testOpenAndCloseGutsWithoutSave() {
+ val guts = spy(NotificationGuts(mContext))
+ whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock ->
+ handler.post(((invocation.arguments[0] as Runnable)))
+ null
+ }
+
+ // Test doesn't support animation since the guts view is not attached.
+ doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any())
+
+ val realRow = createTestNotificationRow()
+ val menuItem = createTestMenuItem(realRow)
+
+ val row = spy(realRow)
+ whenever(row.windowToken).thenReturn(Binder())
+ whenever(row.guts).thenReturn(guts)
+
+ assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
+ executor.runAllReady()
+ verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
+
+ gutsManager.closeAndUndoGuts()
+
+ verify(guts).closeControls(anyInt(), anyInt(), eq(false), eq(false))
+ verify(row, times(1)).setGutsView(any<MenuItem>())
+ executor.runAllReady()
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
+
+ @Test
fun testLockscreenShadeVisible_visible_gutsNotClosed() =
testScope.runTest {
// First, start out lockscreen or shade as not visible
@@ -377,52 +407,6 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
}
@Test
- fun testChangeDensityOrFontScale() {
- val guts = spy(NotificationGuts(mContext))
- whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock ->
- handler.post(((invocation.arguments[0] as Runnable)))
- null
- }
-
- // Test doesn't support animation since the guts view is not attached.
- doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
-
- val realRow = createTestNotificationRow()
- val menuItem = createTestMenuItem(realRow)
-
- val row = spy(realRow)
-
- whenever(row.windowToken).thenReturn(Binder())
- whenever(row.guts).thenReturn(guts)
- doNothing().whenever(row).ensureGutsInflated()
-
- val realEntry = realRow.entry
- val entry = spy(realEntry)
-
- whenever(entry.row).thenReturn(row)
- whenever(entry.guts).thenReturn(guts)
-
- assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
- executor.runAllReady()
- verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
-
- // called once by mGutsManager.bindGuts() in mGutsManager.openGuts()
- verify(row).setGutsView(any<MenuItem>())
-
- row.onDensityOrFontScaleChanged()
- gutsManager.onDensityOrFontScaleChanged(entry)
-
- executor.runAllReady()
-
- gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false)
-
- verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
-
- // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged()
- verify(row, times(2)).setGutsView(any<MenuItem>())
- }
-
- @Test
fun testAppOpsSettingsIntent_camera() {
val row = createTestNotificationRow()
val ops = ArraySet<Int>()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
index 6435e8203d3d..af67a04d2f2a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
@@ -16,29 +16,44 @@
package com.android.systemui.statusbar.notification.row;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.TestableResources;
-import android.util.KeyValueListParser;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.res.R;
+import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -46,8 +61,12 @@ import java.util.ArrayList;
public class NotificationSnoozeTest extends SysuiTestCase {
private static final int RES_DEFAULT = 2;
private static final int[] RES_OPTIONS = {1, 2, 3};
- private NotificationSnooze mNotificationSnooze;
- private KeyValueListParser mMockParser;
+ private final NotificationSwipeActionHelper mSnoozeListener = mock(
+ NotificationSwipeActionHelper.class);
+ private NotificationSnooze mUnderTest;
+
+ @Rule
+ public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(this);
@Before
public void setUp() throws Exception {
@@ -56,62 +75,117 @@ public class NotificationSnoozeTest extends SysuiTestCase {
TestableResources resources = mContext.getOrCreateTestableResources();
resources.addOverride(R.integer.config_notification_snooze_time_default, RES_DEFAULT);
resources.addOverride(R.array.config_notification_snooze_times, RES_OPTIONS);
- mNotificationSnooze = new NotificationSnooze(mContext, null);
- mMockParser = mock(KeyValueListParser.class);
+
+ mUnderTest = new NotificationSnooze(mContext, null);
+ mUnderTest.setSnoozeListener(mSnoozeListener);
+ mUnderTest.mExpandButton = mock(ImageView.class);
+ mUnderTest.mSnoozeView = mock(View.class);
+ mUnderTest.mSelectedOptionText = mock(TextView.class);
+ mUnderTest.mDivider = mock(View.class);
+ mUnderTest.mSnoozeOptionContainer = mock(ViewGroup.class);
+ mUnderTest.mSnoozeOptions = mock(List.class);
+ }
+
+ @After
+ public void tearDown() {
+ // Make sure all animations are finished
+ mAnimatorTestRule.advanceTimeBy(1000L);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NOTIFICATION_UNDO_GUTS_ON_CONFIG_CHANGED)
+ public void closeControls_withoutSave_performsUndo() {
+ ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions();
+ mUnderTest.mSelectedOption = options.getFirst();
+ mUnderTest.showSnoozeOptions(true);
+
+ assertThat(
+ mUnderTest.handleCloseControls(/* save = */ false, /* force = */ false)).isFalse();
+
+ assertThat(mUnderTest.mSelectedOption).isNull();
+ assertThat(mUnderTest.isExpanded()).isFalse();
+ verify(mSnoozeListener, times(0)).snooze(any(), any());
+ }
+
+ @Test
+ public void closeControls_whenExpanded_collapsesOptions() {
+ ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions();
+ mUnderTest.mSelectedOption = options.getFirst();
+ mUnderTest.showSnoozeOptions(true);
+
+ assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ false)).isTrue();
+
+ assertThat(mUnderTest.mSelectedOption).isNotNull();
+ assertThat(mUnderTest.isExpanded()).isFalse();
+ }
+
+ @Test
+ public void closeControls_whenCollapsed_commitsChanges() {
+ ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions();
+ mUnderTest.mSelectedOption = options.getFirst();
+
+ assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ false)).isTrue();
+
+ verify(mSnoozeListener).snooze(any(), any());
+ }
+
+ @Test
+ public void closeControls_withForce_returnsFalse() {
+ assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ true)).isFalse();
}
@Test
- public void testGetOptionsWithNoConfig() throws Exception {
- ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ public void testGetOptionsWithNoConfig() {
+ ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions();
assertEquals(3, result.size());
assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order
assertEquals(2, result.get(1).getMinutesToSnoozeFor());
assertEquals(3, result.get(2).getMinutesToSnoozeFor());
- assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ assertEquals(2, mUnderTest.getDefaultOption().getMinutesToSnoozeFor());
}
@Test
- public void testGetOptionsWithInvalidConfig() throws Exception {
+ public void testGetOptionsWithInvalidConfig() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
"this is garbage");
- ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions();
assertEquals(3, result.size());
assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order
assertEquals(2, result.get(1).getMinutesToSnoozeFor());
assertEquals(3, result.get(2).getMinutesToSnoozeFor());
- assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ assertEquals(2, mUnderTest.getDefaultOption().getMinutesToSnoozeFor());
}
@Test
- public void testGetOptionsWithValidDefault() throws Exception {
+ public void testGetOptionsWithValidDefault() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
"default=10,options_array=4:5:6:7");
- ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
- assertNotNull(mNotificationSnooze.getDefaultOption()); // pick one
+ ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions();
+ assertNotNull(mUnderTest.getDefaultOption()); // pick one
}
@Test
- public void testGetOptionsWithValidConfig() throws Exception {
+ public void testGetOptionsWithValidConfig() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
"default=6,options_array=4:5:6:7");
- ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions();
assertEquals(4, result.size());
assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order
assertEquals(5, result.get(1).getMinutesToSnoozeFor());
assertEquals(6, result.get(2).getMinutesToSnoozeFor());
assertEquals(7, result.get(3).getMinutesToSnoozeFor());
- assertEquals(6, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ assertEquals(6, mUnderTest.getDefaultOption().getMinutesToSnoozeFor());
}
@Test
- public void testGetOptionsWithLongConfig() throws Exception {
+ public void testGetOptionsWithLongConfig() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
"default=6,options_array=4:5:6:7:8:9:10:11:12:13:14:15:16:17");
- ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions();
assertTrue(result.size() > 3);
assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order
assertEquals(5, result.get(1).getMinutesToSnoozeFor());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
index 09be93de9f3e..ea91b7a9d6e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
@@ -19,6 +19,7 @@ package com.android.systemui.unfold
import android.content.Context
import android.content.res.Resources
import android.hardware.devicestate.DeviceStateManager
+import android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
@@ -27,16 +28,20 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImp
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl
import com.android.systemui.defaultDeviceState
import com.android.systemui.deviceStateManager
-import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.FOLDED
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.HALF_FOLDED
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.UNFOLDED
+import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.foldedDeviceStateList
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.power.shared.model.ScreenPowerState
-import com.android.systemui.power.shared.model.WakeSleepReason
-import com.android.systemui.power.shared.model.WakefulnessModel
-import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState
+import com.android.systemui.power.domain.interactor.PowerInteractorFactory
+import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_OFF
+import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_ON
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.unfold.DisplaySwitchLatencyTracker.Companion.FOLDABLE_DEVICE_STATE_CLOSED
@@ -45,7 +50,7 @@ import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLate
import com.android.systemui.unfold.data.repository.UnfoldTransitionRepositoryImpl
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import com.android.systemui.unfoldedDeviceState
-import com.android.systemui.util.animation.data.repository.AnimationStatusRepository
+import com.android.systemui.util.animation.data.repository.fakeAnimationStatusRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.time.FakeSystemClock
@@ -77,14 +82,15 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
private lateinit var displaySwitchLatencyTracker: DisplaySwitchLatencyTracker
@Captor private lateinit var loggerArgumentCaptor: ArgumentCaptor<DisplaySwitchLatencyEvent>
+ private val kosmos = Kosmos()
private val mockContext = mock<Context>()
private val resources = mock<Resources>()
- private val foldStateRepository = mock<DeviceStateRepository>()
- private val powerInteractor = mock<PowerInteractor>()
- private val animationStatusRepository = mock<AnimationStatusRepository>()
+ private val foldStateRepository = kosmos.fakeDeviceStateRepository
+ private val powerInteractor = PowerInteractorFactory.create().powerInteractor
+ private val animationStatusRepository = kosmos.fakeAnimationStatusRepository
private val keyguardInteractor = mock<KeyguardInteractor>()
private val displaySwitchLatencyLogger = mock<DisplaySwitchLatencyLogger>()
- private val kosmos = Kosmos()
+
private val deviceStateManager = kosmos.deviceStateManager
private val closedDeviceState = kosmos.foldedDeviceStateList.first()
private val openDeviceState = kosmos.unfoldedDeviceState
@@ -94,12 +100,7 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
private val testDispatcher: TestDispatcher = StandardTestDispatcher()
private val testScope: TestScope = TestScope(testDispatcher)
- private val isAsleep = MutableStateFlow(false)
private val isAodAvailable = MutableStateFlow(false)
- private val deviceState = MutableStateFlow(DeviceState.UNFOLDED)
- private val screenPowerState = MutableStateFlow(ScreenPowerState.SCREEN_ON)
- private val areAnimationEnabled = MutableStateFlow(true)
- private val lastWakefulnessEvent = MutableStateFlow(WakefulnessModel())
private val systemClock = FakeSystemClock()
private val configurationController = FakeConfigurationController()
private val configurationRepository =
@@ -126,13 +127,10 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
.thenReturn(listOf(closedDeviceState, openDeviceState))
whenever(resources.getIntArray(R.array.config_foldedDeviceStates))
.thenReturn(nonEmptyClosedDeviceStatesArray)
- whenever(foldStateRepository.state).thenReturn(deviceState)
- whenever(powerInteractor.isAsleep).thenReturn(isAsleep)
- whenever(animationStatusRepository.areAnimationsEnabled()).thenReturn(areAnimationEnabled)
- whenever(powerInteractor.screenPowerState).thenReturn(screenPowerState)
whenever(keyguardInteractor.isAodAvailable).thenReturn(isAodAvailable)
- whenever(powerInteractor.detailedWakefulness).thenReturn(lastWakefulnessEvent)
-
+ animationStatusRepository.onAnimationStatusChanged(true)
+ powerInteractor.setAwakeForTest()
+ powerInteractor.setScreenPowerState(SCREEN_ON)
displaySwitchLatencyTracker =
DisplaySwitchLatencyTracker(
mockContext,
@@ -152,21 +150,19 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun unfold_logsLatencyTillTransitionStarted() {
testScope.runTest {
- areAnimationEnabled.emit(true)
-
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.FOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
runCurrent()
systemClock.advanceTime(50)
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
systemClock.advanceTime(200)
unfoldTransitionProgressProvider.onTransitionStarted()
runCurrent()
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
val loggedEvent = loggerArgumentCaptor.value
@@ -202,23 +198,22 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
systemClock,
deviceStateManager,
)
- areAnimationEnabled.emit(true)
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.FOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
systemClock.advanceTime(50)
runCurrent()
systemClock.advanceTime(200)
unfoldTransitionProgressProvider.onTransitionStarted()
runCurrent()
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
val loggedEvent = loggerArgumentCaptor.value
@@ -235,23 +230,23 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun unfold_animationDisabled_logsLatencyTillScreenTurnedOn() {
testScope.runTest {
- areAnimationEnabled.emit(false)
+ animationStatusRepository.onAnimationStatusChanged(false)
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.FOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
systemClock.advanceTime(50)
runCurrent()
unfoldTransitionProgressProvider.onTransitionStarted()
systemClock.advanceTime(200)
runCurrent()
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
val loggedEvent = loggerArgumentCaptor.value
@@ -268,19 +263,18 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun foldWhileStayingAwake_logsLatency() {
testScope.runTest {
- areAnimationEnabled.emit(true)
- deviceState.emit(DeviceState.UNFOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ setDeviceState(UNFOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.FOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
runCurrent()
systemClock.advanceTime(200)
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
runCurrent()
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
@@ -298,25 +292,19 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun foldToAod_capturesToStateAsAod() {
testScope.runTest {
- areAnimationEnabled.emit(true)
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
isAodAvailable.emit(true)
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.FOLDED)
- lastWakefulnessEvent.emit(
- WakefulnessModel(
- internalWakefulnessState = WakefulnessState.ASLEEP,
- lastSleepReason = WakeSleepReason.FOLD,
- )
- )
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
runCurrent()
systemClock.advanceTime(200)
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
runCurrent()
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
@@ -335,22 +323,21 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun fold_notAFoldable_shouldNotLogLatency() {
testScope.runTest {
- areAnimationEnabled.emit(true)
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
whenever(resources.getIntArray(R.array.config_foldedDeviceStates))
.thenReturn(IntArray(0))
whenever(deviceStateManager.supportedDeviceStates)
.thenReturn(listOf(defaultDeviceState))
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.FOLDED)
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
runCurrent()
systemClock.advanceTime(200)
- screenPowerState.emit(ScreenPowerState.SCREEN_ON)
+ powerInteractor.setScreenPowerState(SCREEN_ON)
runCurrent()
verify(displaySwitchLatencyLogger, never()).log(any())
@@ -360,22 +347,16 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
@Test
fun foldToScreenOff_capturesToStateAsScreenOff() {
testScope.runTest {
- areAnimationEnabled.emit(true)
- deviceState.emit(DeviceState.UNFOLDED)
+ setDeviceState(UNFOLDED)
isAodAvailable.emit(false)
displaySwitchLatencyTracker.start()
- deviceState.emit(DeviceState.HALF_FOLDED)
+ setDeviceState(HALF_FOLDED)
systemClock.advanceTime(50)
runCurrent()
- deviceState.emit(DeviceState.FOLDED)
- lastWakefulnessEvent.emit(
- WakefulnessModel(
- internalWakefulnessState = WakefulnessState.ASLEEP,
- lastSleepReason = WakeSleepReason.FOLD,
- )
- )
- screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
+ setDeviceState(FOLDED)
+ powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD)
+ powerInteractor.setScreenPowerState(SCREEN_OFF)
runCurrent()
verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
@@ -390,4 +371,8 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
assertThat(loggedEvent).isEqualTo(expectedLoggedEvent)
}
}
+
+ private suspend fun setDeviceState(state: DeviceState) {
+ foldStateRepository.emit(state)
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index e76f38c8c75c..9507b0483a06 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -62,15 +62,14 @@ public abstract class ClockRegistryModule {
scope,
mainDispatcher,
bgDispatcher,
- com.android.systemui.Flags.lockscreenCustomClocks()
+ com.android.systemui.shared.Flags.lockscreenCustomClocks()
|| featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
/* handleAllUsers= */ true,
new DefaultClockProvider(
context,
layoutInflater,
resources,
-
- com.android.systemui.Flags.clockReactiveVariants()
+ com.android.systemui.shared.Flags.clockReactiveVariants()
),
context.getString(R.string.lockscreen_clock_id_fallback),
clockBuffers,
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 1c994731c393..126471234fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -32,6 +32,9 @@ import com.android.systemui.authentication.shared.model.AuthenticationWipeModel.
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -66,6 +69,7 @@ constructor(
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val repository: AuthenticationRepository,
private val selectedUserInteractor: SelectedUserInteractor,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) {
/**
* The currently-configured authentication method. This determines how the authentication
@@ -85,7 +89,11 @@ constructor(
* `true` even when the lockscreen is showing and still needs to be dismissed by the user to
* proceed.
*/
- val authenticationMethod: Flow<AuthenticationMethodModel> = repository.authenticationMethod
+ val authenticationMethod: Flow<AuthenticationMethodModel> =
+ repository.authenticationMethod.logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ initialValue = AuthenticationMethodModel.None,
+ )
/**
* Whether the auto confirm feature is enabled for the currently-selected user.
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
index 4e45fcc25fb8..744fd7e94ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
@@ -16,6 +16,9 @@
package com.android.systemui.authentication.shared.model
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
+
/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
/**
@@ -24,8 +27,8 @@ sealed class AuthenticationMethodModel(
* "Secure" authentication methods require authentication to unlock the device. Non-secure auth
* methods simply require user dismissal.
*/
- open val isSecure: Boolean,
-) {
+ open val isSecure: Boolean
+) : Diffable<AuthenticationMethodModel> {
/**
* Device doesn't use a secure authentication method. Either there is no lockscreen or the lock
* screen can be swiped away when displayed.
@@ -39,4 +42,8 @@ sealed class AuthenticationMethodModel(
data object Pattern : AuthenticationMethodModel(isSecure = true)
data object Sim : AuthenticationMethodModel(isSecure = true)
+
+ override fun logDiffs(prevVal: AuthenticationMethodModel, row: TableRowLogger) {
+ row.logChange(columnName = "authenticationMethod", value = toString())
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
index 19238804fb12..79e66a89cd6b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.common.data
+import com.android.systemui.common.data.repository.BatteryRepository
+import com.android.systemui.common.data.repository.BatteryRepositoryImpl
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.data.repository.PackageChangeRepositoryImpl
import dagger.Binds
@@ -27,4 +29,6 @@ abstract class CommonDataLayerModule {
abstract fun bindPackageChangeRepository(
impl: PackageChangeRepositoryImpl
): PackageChangeRepository
+
+ @Binds abstract fun bindBatteryRepository(impl: BatteryRepositoryImpl): BatteryRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt b/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt
new file mode 100644
index 000000000000..63b051339d4b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.common.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.util.kotlin.isDevicePluggedIn
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.stateIn
+
+interface BatteryRepository {
+ val isDevicePluggedIn: Flow<Boolean>
+}
+
+@SysUISingleton
+class BatteryRepositoryImpl
+@Inject
+constructor(@Background bgScope: CoroutineScope, batteryController: BatteryController) :
+ BatteryRepository {
+
+ /** Returns {@code true} if the device is currently plugged in or wireless charging. */
+ override val isDevicePluggedIn: Flow<Boolean> =
+ batteryController
+ .isDevicePluggedIn()
+ .stateIn(bgScope, SharingStarted.WhileSubscribed(), batteryController.isPluggedIn)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt
new file mode 100644
index 000000000000..987776d14b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.common.domain.interactor
+
+import com.android.systemui.common.data.repository.BatteryRepository
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+@SysUISingleton
+class BatteryInteractor @Inject constructor(batteryRepository: BatteryRepository) {
+ val isDevicePluggedIn = batteryRepository.isDevicePluggedIn
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
index 53122c56ed2c..abd101693b43 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
@@ -34,6 +34,7 @@ import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_I
import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_USER_SETTING
import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule.Companion.DEFAULT_BACKGROUND_TYPE
import com.android.systemui.communal.shared.model.CommunalBackgroundType
+import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -60,6 +61,12 @@ interface CommunalSettingsRepository {
fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean>
/**
+ * Returns a [WhenToDream] for the specified user, indicating what state the device should be in
+ * to trigger dreams.
+ */
+ fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream>
+
+ /**
* Returns true if any glanceable hub functionality should be enabled via configs and flags.
*
* This should be used for preventing basic glanceable hub functionality from running on devices
@@ -157,6 +164,49 @@ constructor(
}
.flowOn(bgDispatcher)
+ override fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> =
+ secureSettings
+ .observerFlow(
+ userId = user.id,
+ names =
+ arrayOf(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ ),
+ )
+ .emitOnStart()
+ .map {
+ if (
+ secureSettings.getIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 0,
+ user.id,
+ ) == 1
+ ) {
+ WhenToDream.WHILE_CHARGING
+ } else if (
+ secureSettings.getIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 0,
+ user.id,
+ ) == 1
+ ) {
+ WhenToDream.WHILE_DOCKED
+ } else if (
+ secureSettings.getIntForUser(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 0,
+ user.id,
+ ) == 1
+ ) {
+ WhenToDream.WHILE_POSTURED
+ } else {
+ WhenToDream.NEVER
+ }
+ }
+ .flowOn(bgDispatcher)
+
override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> =
broadcastDispatcher
.broadcastFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 465a8e3eccca..b4e6e9348b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -30,11 +30,13 @@ import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.Flags.communalResponsiveGrid
import com.android.systemui.Flags.glanceableHubBlurredBackground
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.domain.interactor.BatteryInteractor
import com.android.systemui.communal.data.repository.CommunalMediaRepository
import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent
+import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.FULL
@@ -43,11 +45,14 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.shared.model.EditModeState
+import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.retrieveIsDocked
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
@@ -67,6 +72,7 @@ import com.android.systemui.statusbar.phone.ManagedProfileController
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.emitOnStart
+import com.android.systemui.util.kotlin.isDevicePluggedIn
import javax.inject.Inject
import kotlin.time.Duration.Companion.minutes
import kotlinx.coroutines.CoroutineDispatcher
@@ -86,6 +92,7 @@ import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -117,6 +124,9 @@ constructor(
@CommunalLog logBuffer: LogBuffer,
@CommunalTableLog tableLogBuffer: TableLogBuffer,
private val managedProfileController: ManagedProfileController,
+ private val batteryInteractor: BatteryInteractor,
+ private val dockManager: DockManager,
+ private val posturingInteractor: PosturingInteractor,
) {
private val logger = Logger(logBuffer, "CommunalInteractor")
@@ -172,6 +182,33 @@ constructor(
replay = 1,
)
+ /**
+ * Whether communal hub should be shown automatically, depending on the user's [WhenToDream]
+ * state.
+ */
+ val shouldShowCommunal: Flow<Boolean> =
+ allOf(
+ isCommunalAvailable,
+ communalSettingsInteractor.whenToDream
+ .flatMapLatest { whenToDream ->
+ when (whenToDream) {
+ WhenToDream.NEVER -> flowOf(false)
+
+ WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn
+
+ WhenToDream.WHILE_DOCKED ->
+ allOf(
+ batteryInteractor.isDevicePluggedIn,
+ dockManager.retrieveIsDocked(),
+ )
+
+ WhenToDream.WHILE_POSTURED ->
+ allOf(batteryInteractor.isDevicePluggedIn, posturingInteractor.postured)
+ }
+ }
+ .flowOn(bgDispatcher),
+ )
+
private val _isDisclaimerDismissed = MutableStateFlow(false)
val isDisclaimerDismissed: Flow<Boolean> = _isDisclaimerDismissed.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
index 1738f37b7f0c..a0b1261df346 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
@@ -21,6 +21,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.communal.data.model.CommunalEnabledState
import com.android.systemui.communal.data.repository.CommunalSettingsRepository
import com.android.systemui.communal.shared.model.CommunalBackgroundType
+import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.dagger.CommunalTableLog
@@ -73,6 +74,12 @@ constructor(
repository.getScreensaverEnabledState(user)
}
+ /** When to dream for the currently selected user. */
+ val whenToDream: Flow<WhenToDream> =
+ userInteractor.selectedUserInfo.flatMapLatest { user ->
+ repository.getWhenToDreamState(user)
+ }
+
/**
* Returns true if any glanceable hub functionality should be enabled via configs and flags.
*
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt
new file mode 100644
index 000000000000..0d4eb60c5240
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.communal.shared.model
+
+enum class WhenToDream {
+ NEVER,
+ WHILE_CHARGING,
+ WHILE_DOCKED,
+ WHILE_POSTURED,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
index 1e7bec257432..69da67e055fe 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
@@ -68,4 +68,10 @@ constructor(
emptyFlow()
}
}
+
+ /** Triggered if a face failure occurs regardless of the mode. */
+ val faceFailure: Flow<FailedFaceAuthenticationStatus> =
+ deviceEntryFaceAuthInteractor.authenticationStatus.filterIsInstance<
+ FailedFaceAuthenticationStatus
+ >()
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
index cdd2b054711e..079d624e6fe0 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor
import com.android.systemui.CoreStartable
import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus
+import com.android.systemui.log.table.TableLogBuffer
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -81,6 +82,8 @@ interface DeviceEntryFaceAuthInteractor : CoreStartable {
/** Whether face auth is considered class 3 */
fun isFaceAuthStrong(): Boolean
+
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer)
}
/**
@@ -93,17 +96,17 @@ interface DeviceEntryFaceAuthInteractor : CoreStartable {
*/
interface FaceAuthenticationListener {
/** Receive face isAuthenticated updates */
- fun onAuthenticatedChanged(isAuthenticated: Boolean)
+ fun onAuthenticatedChanged(isAuthenticated: Boolean) = Unit
/** Receive face authentication status updates */
- fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus)
+ fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus) = Unit
/** Receive status updates whenever face detection runs */
- fun onDetectionStatusChanged(status: FaceDetectionStatus)
+ fun onDetectionStatusChanged(status: FaceDetectionStatus) = Unit
- fun onLockoutStateChanged(isLockedOut: Boolean)
+ fun onLockoutStateChanged(isLockedOut: Boolean) = Unit
- fun onRunningStateChanged(isRunning: Boolean)
+ fun onRunningStateChanged(isRunning: Boolean) = Unit
- fun onAuthEnrollmentStateChanged(enrolled: Boolean)
+ fun onAuthEnrollmentStateChanged(enrolled: Boolean) = Unit
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
index cd456a618c48..38e0503440f9 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
@@ -123,7 +123,7 @@ constructor(
private val playErrorHapticForBiometricFailure: Flow<Unit> =
merge(
deviceEntryFingerprintAuthInteractor.fingerprintFailure,
- deviceEntryBiometricAuthInteractor.faceOnlyFaceFailure,
+ deviceEntryBiometricAuthInteractor.faceFailure,
)
// map to Unit
.map {}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 4ddc98cd434f..5b6859761705 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -25,7 +25,10 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
@@ -33,9 +36,11 @@ import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -43,6 +48,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Hosts application business logic related to device entry.
@@ -62,6 +68,7 @@ constructor(
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val dismissCallbackRegistry: DismissCallbackRegistry,
sceneBackInteractor: SceneBackInteractor,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) {
/**
* Whether the device is unlocked.
@@ -147,6 +154,11 @@ constructor(
) { enteredDirectly, enteredOnBackStack ->
enteredOnBackStack || enteredDirectly
}
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isDeviceEntered",
+ initialValue = false,
+ )
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
@@ -184,6 +196,11 @@ constructor(
deviceUnlockStatus.deviceUnlockSource?.dismissesLockscreen == false)) &&
!isDeviceEntered
}
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "canSwipeToEnter",
+ initialValue = false,
+ )
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
@@ -271,4 +288,29 @@ constructor(
fun lockNow() {
deviceUnlockedInteractor.lockNow()
}
+
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ coroutineScope {
+ launch {
+ isDeviceEntered
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isDeviceEntered",
+ initialValue = isDeviceEntered.value,
+ )
+ .collect()
+ }
+
+ launch {
+ canSwipeToEnter
+ .map { it?.toString() ?: "" }
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "canSwipeToEnter",
+ initialValue = canSwipeToEnter.value?.toString() ?: "",
+ )
+ .collect()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
index 68aef521be7b..b1be9a209a0a 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
@@ -33,8 +33,11 @@ import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.TrustInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
@@ -48,6 +51,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -74,6 +78,7 @@ constructor(
private val systemPropertiesHelper: SystemPropertiesHelper,
private val userAwareSecureSettingsRepository: UserAwareSecureSettingsRepository,
private val keyguardInteractor: KeyguardInteractor,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) : ExclusiveActivatable() {
private val deviceUnlockSource =
@@ -179,17 +184,33 @@ constructor(
private val lockNowRequests = Channel<Unit>()
override suspend fun onActivated(): Nothing {
- authenticationInteractor.authenticationMethod.collectLatest { authMethod ->
- if (!authMethod.isSecure) {
- // Device remains unlocked as long as the authentication method is not secure.
- Log.d(TAG, "remaining unlocked because auth method not secure")
- repository.deviceUnlockStatus.value = DeviceUnlockStatus(true, null)
- } else if (authMethod == AuthenticationMethodModel.Sim) {
- // Device remains locked while SIM is locked.
- Log.d(TAG, "remaining locked because SIM locked")
- repository.deviceUnlockStatus.value = DeviceUnlockStatus(false, null)
- } else {
- handleLockAndUnlockEvents()
+ coroutineScope {
+ launch {
+ authenticationInteractor.authenticationMethod.collectLatest { authMethod ->
+ if (!authMethod.isSecure) {
+ // Device remains unlocked as long as the authentication method is not
+ // secure.
+ Log.d(TAG, "remaining unlocked because auth method not secure")
+ repository.deviceUnlockStatus.value = DeviceUnlockStatus(true, null)
+ } else if (authMethod == AuthenticationMethodModel.Sim) {
+ // Device remains locked while SIM is locked.
+ Log.d(TAG, "remaining locked because SIM locked")
+ repository.deviceUnlockStatus.value = DeviceUnlockStatus(false, null)
+ } else {
+ handleLockAndUnlockEvents()
+ }
+ }
+ }
+
+ launch {
+ deviceUnlockStatus
+ .map { it.isUnlocked }
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isUnlocked",
+ initialValue = deviceUnlockStatus.value.isUnlocked,
+ )
+ .collect()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
index 9b8c2b1acc33..ecc4dbc2326a 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus
+import com.android.systemui.log.table.TableLogBuffer
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -73,4 +74,6 @@ class NoopDeviceEntryFaceAuthInteractor @Inject constructor() : DeviceEntryFaceA
override fun onWalletLaunched() = Unit
override fun onDeviceUnfolded() {}
+
+ override suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index b19b2d9ece02..4b90e1d52ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -44,6 +44,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -53,13 +55,16 @@ import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
@@ -379,6 +384,27 @@ constructor(
.launchIn(applicationScope)
}
+ override suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ conflatedCallbackFlow {
+ val listener =
+ object : FaceAuthenticationListener {
+ override fun onAuthEnrollmentStateChanged(enrolled: Boolean) {
+ trySend(isFaceAuthEnabledAndEnrolled())
+ }
+ }
+
+ registerListener(listener)
+
+ awaitClose { unregisterListener(listener) }
+ }
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isFaceAuthEnabledAndEnrolled",
+ initialValue = isFaceAuthEnabledAndEnrolled(),
+ )
+ .collect()
+ }
+
companion object {
const val TAG = "DeviceEntryFaceAuthInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 8c6037107c5a..cf712f111034 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -19,8 +19,12 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import android.util.MathUtils
import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags.communalSceneKtfRefactor
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -39,6 +43,10 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
+import java.util.UUID
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -47,11 +55,6 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
-import kotlin.time.Duration.Companion.milliseconds
-import kotlin.time.Duration.Companion.seconds
-import java.util.UUID
-import javax.inject.Inject
-import com.android.app.tracing.coroutines.launchTraced as launch
@SysUISingleton
class FromLockscreenTransitionInteractor
@@ -68,6 +71,8 @@ constructor(
powerInteractor: PowerInteractor,
private val glanceableHubTransitions: GlanceableHubTransitions,
private val communalSettingsInteractor: CommunalSettingsInteractor,
+ private val communalInteractor: CommunalInteractor,
+ private val communalSceneInteractor: CommunalSceneInteractor,
private val swipeToDismissInteractor: SwipeToDismissInteractor,
keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
) :
@@ -94,6 +99,9 @@ constructor(
if (!communalSceneKtfRefactor()) {
listenForLockscreenToGlanceableHub()
}
+ if (communalSettingsInteractor.isV2FlagEnabled()) {
+ listenForLockscreenToGlanceableHubV2()
+ }
}
/**
@@ -268,9 +276,7 @@ constructor(
it.transitionState == TransitionState.CANCELED &&
it.to == KeyguardState.PRIMARY_BOUNCER
}
- .collect {
- transitionId = null
- }
+ .collect { transitionId = null }
}
}
@@ -370,6 +376,19 @@ constructor(
}
}
+ private fun listenForLockscreenToGlanceableHubV2() {
+ scope.launch {
+ communalInteractor.shouldShowCommunal
+ .filterRelevantKeyguardStateAnd { shouldShow -> shouldShow }
+ .collect {
+ communalSceneInteractor.changeScene(
+ newScene = CommunalScenes.Communal,
+ loggingReason = "lockscreen to communal",
+ )
+ }
+ }
+ }
+
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
interpolator = Interpolators.LINEAR
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 42cbd7d39248..a1f288edcdd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -24,6 +24,8 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.sample
@@ -32,6 +34,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -166,4 +169,14 @@ constructor(
isKeyguardEnabled.value && lockPatternUtils.isLockScreenDisabled(userId)
}
}
+
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ isKeyguardEnabled
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isKeyguardEnabled",
+ initialValue = isKeyguardEnabled.value,
+ )
+ .collect()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 75178f0ffef0..3739d17da6c4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -42,6 +42,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
@@ -60,6 +62,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.debounce
@@ -533,6 +536,16 @@ constructor(
repository.setNotificationStackAbsoluteBottom(bottom)
}
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ isDozing
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnName = "isDozing",
+ initialValue = isDozing.value,
+ )
+ .collect()
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index de5088c3521c..898b68d0f4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -475,7 +475,7 @@ constructor(
KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED,
value =
- com.android.systemui.Flags.lockscreenCustomClocks() ||
+ com.android.systemui.shared.Flags.lockscreenCustomClocks() ||
featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
),
KeyguardPickerFlag(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
index 454ba9af5745..d2808627163e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
@@ -19,6 +19,7 @@
package com.android.systemui.keyguard.ui.view
import android.graphics.Rect
+import android.os.DeadObjectException
import android.util.Log
import android.view.View
import com.android.systemui.dagger.SysUISingleton
@@ -192,7 +193,12 @@ constructor(
launcherAnimationController?.let {
manualUnlockAmount = amount
- it.setUnlockAmount(amount, forceIfAnimating)
+
+ try {
+ it.setUnlockAmount(amount, forceIfAnimating)
+ } catch (e: DeadObjectException) {
+ Log.e(TAG, "DeadObjectException in setUnlockAmount($amount, $forceIfAnimating)", e)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
index f15a7b30dce7..f8d442de0f55 100644
--- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -22,6 +22,8 @@ import com.android.systemui.camera.CameraGestureHelper
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorActual
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.PowerRepository
import com.android.systemui.power.shared.model.DozeScreenStateModel
@@ -35,6 +37,7 @@ import javax.inject.Provider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -228,6 +231,15 @@ constructor(
repository.updateWakefulness(powerButtonLaunchGestureTriggered = true)
}
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ detailedWakefulness
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ initialValue = detailedWakefulness.value,
+ )
+ .collect()
+ }
+
companion object {
private const val FSI_WAKE_WHY = "full_screen_intent"
diff --git a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt
index 0f49c94c3195..297c6af5a4a7 100644
--- a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt
@@ -1,6 +1,8 @@
package com.android.systemui.power.shared.model
import com.android.systemui.keyguard.KeyguardService
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
/**
* Models whether the device is awake or asleep, along with information about why we're in that
@@ -35,7 +37,7 @@ data class WakefulnessModel(
* to a subsequent power gesture.
*/
val powerButtonLaunchGestureTriggered: Boolean = false,
-) {
+) : Diffable<WakefulnessModel> {
fun isAwake() =
internalWakefulnessState == WakefulnessState.AWAKE ||
internalWakefulnessState == WakefulnessState.STARTING_TO_WAKE
@@ -58,4 +60,8 @@ data class WakefulnessModel(
return isAwake() &&
(lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE)
}
+
+ override fun logDiffs(prevVal: WakefulnessModel, row: TableRowLogger) {
+ row.logChange(columnName = "wakefulness", value = toString())
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 07de4662e82f..a3893bc3a54a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -32,11 +32,7 @@ import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
import androidx.annotation.VisibleForTesting
-import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.togetherWith
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
@@ -120,6 +116,7 @@ import com.android.systemui.qs.composefragment.ui.GridAnchor
import com.android.systemui.qs.composefragment.ui.NotificationScrimClipParams
import com.android.systemui.qs.composefragment.ui.notificationScrimClip
import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSettings
+import com.android.systemui.qs.composefragment.ui.toEditMode
import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel
import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.qs.footer.ui.compose.FooterActions
@@ -144,6 +141,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -273,36 +271,7 @@ constructor(
// by the composables.
.gesturesDisabled(viewModel.showingMirror)
) {
- val isEditing by
- viewModel.containerViewModel.editModeViewModel.isEditing
- .collectAsStateWithLifecycle()
- val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
- AnimatedContent(
- targetState = isEditing,
- transitionSpec = {
- fadeIn(animationSpecEditMode) togetherWith
- fadeOut(animationSpecEditMode)
- },
- label = "EditModeAnimatedContent",
- ) { editing ->
- if (editing) {
- val qqsPadding = viewModel.qqsHeaderHeight
- EditMode(
- viewModel = viewModel.containerViewModel.editModeViewModel,
- modifier =
- Modifier.fillMaxWidth()
- .padding(top = { qqsPadding })
- .padding(
- horizontal = {
- QuickSettingsShade.Dimensions.Padding
- .roundToPx()
- }
- ),
- )
- } else {
- CollapsableQuickSettingsSTL()
- }
- }
+ CollapsableQuickSettingsSTL()
}
}
}
@@ -324,12 +293,17 @@ constructor(
from(QuickQuickSettings, QuickSettings) {
quickQuickSettingsToQuickSettings(viewModel::animateTilesExpansion::get)
}
+ to(SceneKeys.EditMode) {
+ spec = tween(durationMillis = EDIT_MODE_TIME_MILLIS)
+ toEditMode()
+ }
},
)
LaunchedEffect(Unit) {
synchronizeQsState(
sceneState,
+ viewModel.containerViewModel.editModeViewModel.isEditing,
snapshotFlow { viewModel.expansionState }.map { it.progress },
)
}
@@ -342,7 +316,15 @@ constructor(
scene(QuickQuickSettings) {
LaunchedEffect(Unit) { viewModel.onQQSOpen() }
- QuickQuickSettingsElement()
+ // Cannot pass the element modifier in because the top element has a `testTag`
+ // and this would overwrite it.
+ Box(Modifier.element(QuickQuickSettings.rootElementKey)) {
+ QuickQuickSettingsElement()
+ }
+ }
+
+ scene(SceneKeys.EditMode) {
+ EditModeElement(Modifier.element(SceneKeys.EditMode.rootElementKey))
}
}
}
@@ -582,7 +564,7 @@ constructor(
}
@Composable
- private fun ContentScope.QuickQuickSettingsElement() {
+ private fun ContentScope.QuickQuickSettingsElement(modifier: Modifier = Modifier) {
val qqsPadding = viewModel.qqsHeaderHeight
val bottomPadding = viewModel.qqsBottomPadding
DisposableEffect(Unit) {
@@ -595,7 +577,7 @@ constructor(
.squishiness
.collectAsStateWithLifecycle()
- Column(modifier = Modifier.sysuiResTag(ResIdTags.quickQsPanel)) {
+ Column(modifier = modifier.sysuiResTag(ResIdTags.quickQsPanel)) {
Box(
modifier =
Modifier.fillMaxWidth()
@@ -666,12 +648,12 @@ constructor(
}
@Composable
- private fun ContentScope.QuickSettingsElement() {
+ private fun ContentScope.QuickSettingsElement(modifier: Modifier = Modifier) {
val qqsPadding = viewModel.qqsHeaderHeight
val qsExtraPadding = dimensionResource(R.dimen.qs_panel_padding_top)
Column(
modifier =
- Modifier.collapseExpandSemanticAction(
+ modifier.collapseExpandSemanticAction(
stringResource(id = R.string.accessibility_quick_settings_collapse)
)
) {
@@ -776,6 +758,18 @@ constructor(
}
}
+ @Composable
+ private fun EditModeElement(modifier: Modifier = Modifier) {
+ // No need for top padding, the Scaffold inside takes care of the correct insets
+ EditMode(
+ viewModel = viewModel.containerViewModel.editModeViewModel,
+ modifier =
+ modifier
+ .fillMaxWidth()
+ .padding(horizontal = { QuickSettingsShade.Dimensions.Padding.roundToPx() }),
+ )
+ }
+
private fun Modifier.collapseExpandSemanticAction(label: String): Modifier {
return viewModel.collapseExpandAccessibilityAction?.let {
semantics {
@@ -863,6 +857,7 @@ private val instanceProvider =
object SceneKeys {
val QuickQuickSettings = SceneKey("QuickQuickSettingsScene")
val QuickSettings = SceneKey("QuickSettingsScene")
+ val EditMode = SceneKey("EditModeScene")
fun QSFragmentComposeViewModel.QSExpansionState.toIdleSceneKey(): SceneKey {
return when {
@@ -880,7 +875,11 @@ object SceneKeys {
}
}
-suspend fun synchronizeQsState(state: MutableSceneTransitionLayoutState, expansion: Flow<Float>) {
+private suspend fun synchronizeQsState(
+ state: MutableSceneTransitionLayoutState,
+ editMode: Flow<Boolean>,
+ expansion: Flow<Float>,
+) {
coroutineScope {
val animationScope = this
@@ -891,23 +890,30 @@ suspend fun synchronizeQsState(state: MutableSceneTransitionLayoutState, expansi
currentTransition = null
}
- expansion.collectLatest { progress ->
- when (progress) {
- 0f -> snapTo(QuickQuickSettings)
- 1f -> snapTo(QuickSettings)
- else -> {
- val transition = currentTransition
- if (transition != null) {
- transition.progress = progress
- return@collectLatest
- }
+ editMode.combine(expansion, ::Pair).collectLatest { (editMode, progress) ->
+ if (editMode && state.currentScene != SceneKeys.EditMode) {
+ state.setTargetScene(SceneKeys.EditMode, animationScope)?.second?.join()
+ } else if (!editMode && state.currentScene == SceneKeys.EditMode) {
+ state.setTargetScene(SceneKeys.QuickSettings, animationScope)?.second?.join()
+ }
+ if (!editMode) {
+ when (progress) {
+ 0f -> snapTo(QuickQuickSettings)
+ 1f -> snapTo(QuickSettings)
+ else -> {
+ val transition = currentTransition
+ if (transition != null) {
+ transition.progress = progress
+ return@collectLatest
+ }
- val newTransition =
- ExpansionTransition(progress).also { currentTransition = it }
- state.startTransitionImmediately(
- animationScope = animationScope,
- transition = newTransition,
- )
+ val newTransition =
+ ExpansionTransition(progress).also { currentTransition = it }
+ state.startTransitionImmediately(
+ animationScope = animationScope,
+ transition = newTransition,
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt
new file mode 100644
index 000000000000..0c6f3ee88312
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.composefragment.ui
+
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.qs.composefragment.SceneKeys
+
+fun TransitionBuilder.toEditMode() {
+ fractionRange(start = 0.5f) { fade(SceneKeys.EditMode.rootElementKey) }
+ fractionRange(end = 0.5f) {
+ fade(SceneKeys.QuickQuickSettings.rootElementKey)
+ fade(SceneKeys.QuickSettings.rootElementKey)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
index be792df340c9..f2f237ac987e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
@@ -16,13 +16,27 @@
package com.android.systemui.scene.domain
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.scene.domain.resolver.SceneResolverModule
import dagger.Module
+import dagger.Provides
+import javax.inject.Qualifier
-@Module(
- includes =
- [
- SceneResolverModule::class,
- ]
-)
-object SceneDomainModule
+@Module(includes = [SceneResolverModule::class])
+object SceneDomainModule {
+
+ @JvmStatic
+ @Provides
+ @SysUISingleton
+ @SceneFrameworkTableLog
+ fun provideSceneFrameworkTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
+ return factory.create("SceneFrameworkTableLog", 100)
+ }
+}
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class SceneFrameworkTableLog
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
index bebd398ac972..c9d8e0244d20 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -18,11 +18,16 @@ package com.android.systemui.scene.domain.interactor
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.scene.data.model.SceneStack
+import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.data.model.peek
import com.android.systemui.scene.data.model.pop
import com.android.systemui.scene.data.model.push
import com.android.systemui.scene.data.model.sceneStackOf
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.SceneContainerConfig
import javax.inject.Inject
@@ -39,6 +44,7 @@ class SceneBackInteractor
constructor(
private val logger: SceneLogger,
private val sceneContainerConfig: SceneContainerConfig,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) {
private val _backStack = MutableStateFlow(sceneStackOf())
val backStack: StateFlow<SceneStack> = _backStack.asStateFlow()
@@ -58,6 +64,7 @@ constructor(
fun onSceneChange(from: SceneKey, to: SceneKey) {
check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" }
+ val prevVal = backStack.value
_backStack.update { stack ->
when (stackOperation(from, to, stack)) {
null -> stack
@@ -68,12 +75,21 @@ constructor(
}
}
logger.logSceneBackStack(backStack.value)
+ tableLogBuffer.logDiffs(
+ prevVal = DiffableSceneStack(prevVal),
+ newVal = DiffableSceneStack(backStack.value),
+ )
}
/** Applies the given [transform] to the back stack. */
fun updateBackStack(transform: (SceneStack) -> SceneStack) {
+ val prevVal = backStack.value
_backStack.update { stack -> transform(stack) }
logger.logSceneBackStack(backStack.value)
+ tableLogBuffer.logDiffs(
+ prevVal = DiffableSceneStack(prevVal),
+ newVal = DiffableSceneStack(backStack.value),
+ )
}
private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? {
@@ -106,4 +122,15 @@ constructor(
private data object Push : StackOperation
private data object Pop : StackOperation
+
+ private class DiffableSceneStack(private val sceneStack: SceneStack) :
+ Diffable<DiffableSceneStack> {
+
+ override fun logDiffs(prevVal: DiffableSceneStack, row: TableRowLogger) {
+ row.logChange(
+ columnName = "backStack",
+ value = sceneStack.asIterable().joinToString { it.debugName },
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 8bc9d96c064a..9c04323f2a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -27,14 +27,19 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.resolver.SceneResolver
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.pairwise
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -47,6 +52,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
/**
* Generic business logic and app state accessors for the scene framework.
@@ -562,6 +568,28 @@ constructor(
decrementActiveTransitionAnimationCount()
}
+ suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
+ coroutineScope {
+ launch {
+ currentScene
+ .map { sceneKey -> DiffableSceneKey(key = sceneKey) }
+ .pairwise()
+ .collect { (prev, current) ->
+ tableLogBuffer.logDiffs(prevVal = prev, newVal = current)
+ }
+ }
+
+ launch {
+ currentOverlays
+ .map { overlayKeys -> DiffableOverlayKeys(keys = overlayKeys) }
+ .pairwise()
+ .collect { (prev, current) ->
+ tableLogBuffer.logDiffs(prevVal = prev, newVal = current)
+ }
+ }
+ }
+ }
+
private fun decrementActiveTransitionAnimationCount() {
repository.activeTransitionAnimationCount.update { current ->
(current - 1).also {
@@ -573,4 +601,20 @@ constructor(
}
}
}
+
+ private class DiffableSceneKey(private val key: SceneKey) : Diffable<DiffableSceneKey> {
+ override fun logDiffs(prevVal: DiffableSceneKey, row: TableRowLogger) {
+ row.logChange(columnName = "currentScene", value = key.debugName)
+ }
+ }
+
+ private class DiffableOverlayKeys(private val keys: Set<OverlayKey>) :
+ Diffable<DiffableOverlayKeys> {
+ override fun logDiffs(prevVal: DiffableOverlayKeys, row: TableRowLogger) {
+ row.logChange(
+ columnName = "currentOverlays",
+ value = keys.joinToString { key -> key.debugName },
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 8602884ec4ee..2fd584176220 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,6 +45,7 @@ import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.keyguardScenes
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.model.SceneContainerPlugin
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
@@ -54,6 +55,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.data.model.sceneStackOf
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.scene.domain.interactor.DisabledContentInteractor
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
@@ -145,6 +147,7 @@ constructor(
private val disabledContentInteractor: DisabledContentInteractor,
private val activityTransitionAnimator: ActivityTransitionAnimator,
private val shadeModeInteractor: ShadeModeInteractor,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) : CoreStartable {
private val centralSurfaces: CentralSurfaces?
get() = centralSurfacesOptLazy.get().getOrNull()
@@ -154,6 +157,7 @@ constructor(
override fun start() {
if (SceneContainerFlag.isEnabled) {
sceneLogger.logFrameworkEnabled(isEnabled = true)
+ applicationScope.launch { hydrateTableLogBuffer() }
hydrateVisibility()
automaticallySwitchScenes()
hydrateSystemUiState()
@@ -224,6 +228,16 @@ constructor(
}
}
+ private suspend fun hydrateTableLogBuffer() {
+ coroutineScope {
+ launch { sceneInteractor.hydrateTableLogBuffer(tableLogBuffer) }
+ launch { keyguardEnabledInteractor.hydrateTableLogBuffer(tableLogBuffer) }
+ launch { faceUnlockInteractor.hydrateTableLogBuffer(tableLogBuffer) }
+ launch { powerInteractor.hydrateTableLogBuffer(tableLogBuffer) }
+ launch { keyguardInteractor.hydrateTableLogBuffer(tableLogBuffer) }
+ }
+ }
+
private fun resetShadeSessions() {
applicationScope.launch {
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
index 59d812403777..01451502b859 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
@@ -19,6 +19,9 @@ package com.android.systemui.shade.domain.interactor
import android.provider.Settings
import androidx.annotation.FloatRange
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.scene.domain.SceneFrameworkTableLog
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeMode
@@ -81,8 +84,9 @@ class ShadeModeInteractorImpl
@Inject
constructor(
@Application applicationScope: CoroutineScope,
- repository: ShadeRepository,
+ private val repository: ShadeRepository,
secureSettingsRepository: SecureSettingsRepository,
+ @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
) : ShadeModeInteractor {
private val isDualShadeEnabled: Flow<Boolean> =
@@ -93,17 +97,17 @@ constructor(
override val isShadeLayoutWide: StateFlow<Boolean> = repository.isShadeLayoutWide
+ private val shadeModeInitialValue: ShadeMode
+ get() =
+ determineShadeMode(
+ isDualShadeEnabled = DUAL_SHADE_ENABLED_DEFAULT,
+ isShadeLayoutWide = repository.isShadeLayoutWide.value,
+ )
+
override val shadeMode: StateFlow<ShadeMode> =
combine(isDualShadeEnabled, repository.isShadeLayoutWide, ::determineShadeMode)
- .stateIn(
- applicationScope,
- SharingStarted.Eagerly,
- initialValue =
- determineShadeMode(
- isDualShadeEnabled = DUAL_SHADE_ENABLED_DEFAULT,
- isShadeLayoutWide = repository.isShadeLayoutWide.value,
- ),
- )
+ .logDiffsForTable(tableLogBuffer = tableLogBuffer, initialValue = shadeModeInitialValue)
+ .stateIn(applicationScope, SharingStarted.Eagerly, initialValue = shadeModeInitialValue)
@FloatRange(from = 0.0, to = 1.0) override fun getTopEdgeSplitFraction(): Float = 0.5f
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
index a8199a402ef1..8b3ce0f69742 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
@@ -16,15 +16,18 @@
package com.android.systemui.shade.shared.model
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
+
/** Enumerates all known modes of operation of the shade. */
-sealed interface ShadeMode {
+sealed class ShadeMode : Diffable<ShadeMode> {
/**
* The single or "accordion" shade where the QS and notification parts are in two vertically
* stacked panels and the user can swipe up and down to expand or collapse between the two
* parts.
*/
- data object Single : ShadeMode
+ data object Single : ShadeMode()
/**
* The split shade where, on large screens and unfolded foldables, the QS and notification parts
@@ -32,14 +35,18 @@ sealed interface ShadeMode {
*
* Note: This isn't the only mode where the shade is wide.
*/
- data object Split : ShadeMode
+ data object Split : ShadeMode()
/**
* The dual shade where the QS and notification parts each have their own independently
* expandable/collapsible panel on either side of the large screen / unfolded device or sharing
* a space on a small screen or folded device.
*/
- data object Dual : ShadeMode
+ data object Dual : ShadeMode()
+
+ override fun logDiffs(prevVal: ShadeMode, row: TableRowLogger) {
+ row.logChange("shadeMode", toString())
+ }
companion object {
@JvmStatic fun dual(): Dual = Dual
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 2d1eccdf1abd..a0a86710b4ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -22,6 +22,7 @@ import com.android.internal.widget.MessagingGroup
import com.android.internal.widget.MessagingMessage
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.Flags
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
@@ -144,7 +145,12 @@ internal constructor(
)
log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
traceSection("updateNotifOnUiModeChanged") {
- mPipeline?.allNotifs?.forEach { entry -> entry.row?.onUiModeChanged() }
+ mPipeline?.allNotifs?.forEach { entry ->
+ entry.row?.onUiModeChanged()
+ if (Flags.notificationUndoGutsOnConfigChanged()) {
+ mGutsManager.closeAndUndoGuts()
+ }
+ }
}
}
@@ -152,9 +158,15 @@ internal constructor(
colorUpdateLogger.logEvent("VCC.updateNotificationsOnDensityOrFontScaleChanged()")
mPipeline?.allNotifs?.forEach { entry ->
entry.onDensityOrFontScaleChanged()
- val exposedGuts = entry.areGutsExposed()
- if (exposedGuts) {
- mGutsManager.onDensityOrFontScaleChanged(entry)
+ if (Flags.notificationUndoGutsOnConfigChanged()) {
+ mGutsManager.closeAndUndoGuts()
+ } else {
+ // This property actually gets reset when the guts are re-inflated, so we're never
+ // actually calling onDensityOrFontScaleChanged below.
+ val exposedGuts = entry.areGutsExposed()
+ if (exposedGuts) {
+ mGutsManager.onDensityOrFontScaleChanged(entry)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index b86d1d934269..75d1c7c3d51e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -287,7 +287,7 @@ public class NotificationGuts extends FrameLayout {
* @param save whether the state should be saved
* @param force whether the guts should be force-closed regardless of state.
*/
- private void closeControls(int x, int y, boolean save, boolean force) {
+ public void closeControls(int x, int y, boolean save, boolean force) {
// First try to dismiss any blocking helper.
if (getWindowToken() == null) {
if (mClosedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index b1e5b22f9b1a..445cd010cd86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -48,6 +48,7 @@ import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.statusbar.IStatusBarService;
import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.CoreStartable;
+import com.android.systemui.Flags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -223,6 +224,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
}
public void onDensityOrFontScaleChanged(NotificationEntry entry) {
+ if (!Flags.notificationUndoGutsOnConfigChanged()) {
+ Log.wtf(TAG, "onDensityOrFontScaleChanged should not be called if"
+ + " notificationUndoGutsOnConfigChanged is off");
+ }
setExposedGuts(entry.getGuts());
bindGuts(entry.getRow());
}
@@ -590,7 +595,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
}
/**
- * Closes guts or notification menus that might be visible and saves any changes.
+ * Closes guts or notification menus that might be visible and saves any changes if applicable
+ * (see {@link NotificationGuts.GutsContent#shouldBeSavedOnClose}).
*
* @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
* @param force true if guts should be closed regardless of state (used for snooze only).
@@ -611,6 +617,20 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
}
/**
+ * Closes all guts that might be visible without saving changes.
+ */
+ public void closeAndUndoGuts() {
+ if (mNotificationGutsExposed != null) {
+ mNotificationGutsExposed.removeCallbacks(mOpenRunnable);
+ mNotificationGutsExposed.closeControls(
+ /* x = */ -1,
+ /* y = */ -1,
+ /* save = */ false,
+ /* force = */ false);
+ }
+ }
+
+ /**
* Returns the exposed NotificationGuts or null if none are exposed.
*/
public NotificationGuts getExposedGuts() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 99a6f6a59bd0..83897f5bc3a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -51,6 +51,7 @@ import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Flags;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.res.R;
@@ -86,18 +87,26 @@ public class NotificationSnooze extends LinearLayout
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
- private View mSnoozeView;
- private TextView mSelectedOptionText;
+ @VisibleForTesting
+ public View mSnoozeView;
+ @VisibleForTesting
+ public TextView mSelectedOptionText;
private TextView mUndoButton;
- private ImageView mExpandButton;
- private View mDivider;
- private ViewGroup mSnoozeOptionContainer;
- private List<SnoozeOption> mSnoozeOptions;
+ @VisibleForTesting
+ public ImageView mExpandButton;
+ @VisibleForTesting
+ public View mDivider;
+ @VisibleForTesting
+ public ViewGroup mSnoozeOptionContainer;
+ @VisibleForTesting
+ public List<SnoozeOption> mSnoozeOptions;
private int mCollapsedHeight;
private SnoozeOption mDefaultOption;
- private SnoozeOption mSelectedOption;
+ @VisibleForTesting
+ public SnoozeOption mSelectedOption;
private boolean mSnoozing;
- private boolean mExpanded;
+ @VisibleForTesting
+ public boolean mExpanded;
private AnimatorSet mExpandAnimation;
private KeyValueListParser mParser;
@@ -334,7 +343,8 @@ public class NotificationSnooze extends LinearLayout
}
}
- private void showSnoozeOptions(boolean show) {
+ @VisibleForTesting
+ public void showSnoozeOptions(boolean show) {
int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification
: com.android.internal.R.drawable.ic_expand_notification;
mExpandButton.setImageResource(drawableId);
@@ -381,7 +391,8 @@ public class NotificationSnooze extends LinearLayout
mExpandAnimation.start();
}
- private void setSelected(SnoozeOption option, boolean userAction) {
+ @VisibleForTesting
+ public void setSelected(SnoozeOption option, boolean userAction) {
if (option != mSelectedOption) {
mSelectedOption = option;
mSelectedOptionText.setText(option.getConfirmation());
@@ -466,7 +477,12 @@ public class NotificationSnooze extends LinearLayout
@Override
public boolean handleCloseControls(boolean save, boolean force) {
- if (mExpanded && !force) {
+ if (Flags.notificationUndoGutsOnConfigChanged() && !save) {
+ // Undo changes and let the guts handle closing the view
+ mSelectedOption = null;
+ showSnoozeOptions(false);
+ return false;
+ } else if (mExpanded && !force) {
// Collapse expanded state on outside touch
showSnoozeOptions(false);
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 9795cda97f37..eecea9228ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
@@ -82,18 +83,29 @@ fun TutorialSelectionScreen(
}
),
) {
- val padding = if (hasCompactWindowSize()) 24.dp else 60.dp
+ val isCompactWindow = hasCompactWindowSize()
+ val padding = if (isCompactWindow) 24.dp else 60.dp
val configuration = LocalConfiguration.current
when (configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
- HorizontalSelectionButtons(
- onBackTutorialClicked = onBackTutorialClicked,
- onHomeTutorialClicked = onHomeTutorialClicked,
- onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
- onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
- modifier = Modifier.weight(1f).padding(padding),
- lastSelectedScreen,
- )
+ if (isCompactWindow)
+ HorizontalCompactSelectionButtons(
+ onBackTutorialClicked = onBackTutorialClicked,
+ onHomeTutorialClicked = onHomeTutorialClicked,
+ onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
+ lastSelectedScreen,
+ modifier = Modifier.weight(1f).padding(padding),
+ )
+ else
+ HorizontalSelectionButtons(
+ onBackTutorialClicked = onBackTutorialClicked,
+ onHomeTutorialClicked = onHomeTutorialClicked,
+ onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
+ lastSelectedScreen,
+ modifier = Modifier.weight(1f).padding(padding),
+ )
}
else -> {
VerticalSelectionButtons(
@@ -101,8 +113,8 @@ fun TutorialSelectionScreen(
onHomeTutorialClicked = onHomeTutorialClicked,
onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked,
- modifier = Modifier.weight(1f).padding(padding),
lastSelectedScreen,
+ modifier = Modifier.weight(1f).padding(padding),
)
}
}
@@ -120,11 +132,99 @@ private fun HorizontalSelectionButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
onSwitchAppsTutorialClicked: () -> Unit,
+ lastSelectedScreen: Screen,
modifier: Modifier = Modifier,
+) {
+ Column(modifier = modifier) {
+ TwoByTwoTutorialButtons(
+ onBackTutorialClicked,
+ onHomeTutorialClicked,
+ onRecentAppsTutorialClicked,
+ onSwitchAppsTutorialClicked,
+ lastSelectedScreen,
+ modifier = Modifier.weight(1f).fillMaxSize(),
+ )
+ }
+}
+
+@Composable
+private fun TwoByTwoTutorialButtons(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
lastSelectedScreen: Screen,
+ modifier: Modifier = Modifier,
+) {
+ val homeFocusRequester = remember { FocusRequester() }
+ val backFocusRequester = remember { FocusRequester() }
+ val recentAppsFocusRequester = remember { FocusRequester() }
+ val switchAppsFocusRequester = remember { FocusRequester() }
+ LaunchedEffect(Unit) {
+ when (lastSelectedScreen) {
+ Screen.HOME_GESTURE -> homeFocusRequester.requestFocus()
+ Screen.BACK_GESTURE -> backFocusRequester.requestFocus()
+ Screen.RECENT_APPS_GESTURE -> recentAppsFocusRequester.requestFocus()
+ Screen.SWITCH_APPS_GESTURE -> switchAppsFocusRequester.requestFocus()
+ else -> {} // No-Op.
+ }
+ }
+ Column {
+ Row(Modifier.weight(1f)) {
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
+ icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon),
+ iconColor = MaterialTheme.colorScheme.onPrimary,
+ onClick = onHomeTutorialClicked,
+ backgroundColor = MaterialTheme.colorScheme.primary,
+ modifier = modifier.focusRequester(homeFocusRequester).focusable().fillMaxSize(),
+ )
+ Spacer(modifier = Modifier.size(16.dp))
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
+ icon = Icons.AutoMirrored.Outlined.ArrowBack,
+ iconColor = MaterialTheme.colorScheme.onTertiary,
+ onClick = onBackTutorialClicked,
+ backgroundColor = MaterialTheme.colorScheme.tertiary,
+ modifier = modifier.focusRequester(backFocusRequester).focusable().fillMaxSize(),
+ )
+ }
+ Spacer(modifier = Modifier.size(16.dp))
+ Row(Modifier.weight(1f)) {
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
+ icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_recents_icon),
+ iconColor = MaterialTheme.colorScheme.onSecondary,
+ onClick = onRecentAppsTutorialClicked,
+ backgroundColor = MaterialTheme.colorScheme.secondary,
+ modifier =
+ modifier.focusRequester(recentAppsFocusRequester).focusable().fillMaxSize(),
+ )
+ Spacer(modifier = Modifier.size(16.dp))
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_switch_apps_gesture_button),
+ icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_apps_icon),
+ iconColor = MaterialTheme.colorScheme.primary,
+ onClick = onSwitchAppsTutorialClicked,
+ backgroundColor = MaterialTheme.colorScheme.onPrimary,
+ modifier =
+ modifier.focusRequester(switchAppsFocusRequester).focusable().fillMaxSize(),
+ )
+ }
+ }
+}
+
+@Composable
+private fun HorizontalCompactSelectionButtons(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onRecentAppsTutorialClicked: () -> Unit,
+ onSwitchAppsTutorialClicked: () -> Unit,
+ lastSelectedScreen: Screen,
+ modifier: Modifier = Modifier,
) {
Row(
- horizontalArrangement = Arrangement.spacedBy(20.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier,
) {
@@ -133,8 +233,8 @@ private fun HorizontalSelectionButtons(
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
onSwitchAppsTutorialClicked,
- modifier = Modifier.weight(1f).fillMaxSize(),
lastSelectedScreen,
+ modifier = Modifier.weight(1f).fillMaxSize(),
)
}
}
@@ -145,8 +245,8 @@ private fun VerticalSelectionButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
onSwitchAppsTutorialClicked: () -> Unit,
- modifier: Modifier = Modifier,
lastSelectedScreen: Screen,
+ modifier: Modifier = Modifier,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
@@ -158,8 +258,8 @@ private fun VerticalSelectionButtons(
onHomeTutorialClicked,
onRecentAppsTutorialClicked,
onSwitchAppsTutorialClicked,
- modifier = Modifier.weight(1f).fillMaxSize(),
lastSelectedScreen,
+ modifier = Modifier.weight(1f).fillMaxSize(),
)
}
}
@@ -170,8 +270,8 @@ private fun FourTutorialButtons(
onHomeTutorialClicked: () -> Unit,
onRecentAppsTutorialClicked: () -> Unit,
onSwitchAppsTutorialClicked: () -> Unit,
- modifier: Modifier = Modifier,
lastSelectedScreen: Screen,
+ modifier: Modifier = Modifier,
) {
val homeFocusRequester = remember { FocusRequester() }
val backFocusRequester = remember { FocusRequester() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
index 2bd104dd375d..48b801cb06be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.authentication.data.repository.authenticationReposit
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.user.domain.interactor.selectedUserInteractor
val Kosmos.authenticationInteractor by
@@ -29,5 +30,6 @@ val Kosmos.authenticationInteractor by
backgroundDispatcher = testDispatcher,
repository = authenticationRepository,
selectedUserInteractor = selectedUserInteractor,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt
new file mode 100644
index 000000000000..edfe8ecd0775
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.common.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.batteryRepository: BatteryRepository by Kosmos.Fixture { FakeBatteryRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt
new file mode 100644
index 000000000000..ac94335b42c3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.common.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBatteryRepository : BatteryRepository {
+ private val _isDevicePluggedIn = MutableStateFlow(false)
+
+ override val isDevicePluggedIn: Flow<Boolean> = _isDevicePluggedIn.asStateFlow()
+
+ fun setDevicePluggedIn(isPluggedIn: Boolean) {
+ _isDevicePluggedIn.value = isPluggedIn
+ }
+}
+
+val BatteryRepository.fake
+ get() = this as FakeBatteryRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt
new file mode 100644
index 000000000000..2153955f3cc1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.common.domain.interactor
+
+import com.android.systemui.common.data.repository.batteryRepository
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.batteryInteractor by Kosmos.Fixture { BatteryInteractor(batteryRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 89aad4be7cc0..b0a6de1f931a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -19,10 +19,13 @@ package com.android.systemui.communal.domain.interactor
import android.content.testableContext
import android.os.userManager
import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.common.domain.interactor.batteryInteractor
import com.android.systemui.communal.data.repository.communalMediaRepository
import com.android.systemui.communal.data.repository.communalSmartspaceRepository
import com.android.systemui.communal.data.repository.communalWidgetRepository
+import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
+import com.android.systemui.dock.dockManager
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -64,6 +67,9 @@ val Kosmos.communalInteractor by Fixture {
logBuffer = logcatLogBuffer("CommunalInteractor"),
tableLogBuffer = mock(),
managedProfileController = fakeManagedProfileController,
+ batteryInteractor = batteryInteractor,
+ dockManager = dockManager,
+ posturingInteractor = posturingInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
index 1d3fd300da06..c927b5563bba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
@@ -22,6 +22,7 @@ import com.android.systemui.deviceentry.data.repository.deviceEntryRepository
import com.android.systemui.keyguard.dismissCallbackRegistry
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -36,5 +37,6 @@ val Kosmos.deviceEntryInteractor by
alternateBouncerInteractor = alternateBouncerInteractor,
dismissCallbackRegistry = dismissCallbackRegistry,
sceneBackInteractor = sceneBackInteractor,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt
index e4c7df64fdc6..9e36428d119d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt
@@ -25,6 +25,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
@@ -40,6 +41,7 @@ val Kosmos.deviceUnlockedInteractor by Fixture {
systemPropertiesHelper = fakeSystemPropertiesHelper,
userAwareSecureSettingsRepository = userAwareSecureSettingsRepository,
keyguardInteractor = keyguardInteractor,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
.apply { activateIn(testScope) }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
index b07de16be567..ff7a06c5087e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
@@ -16,6 +16,8 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
@@ -41,5 +43,7 @@ var Kosmos.fromLockscreenTransitionInteractor by
communalSettingsInteractor = communalSettingsInteractor,
swipeToDismissInteractor = swipeToDismissInteractor,
keyguardOcclusionInteractor = keyguardOcclusionInteractor,
+ communalInteractor = communalInteractor,
+ communalSceneInteractor = communalSceneInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt
index e46ede65bfb6..e9ba42547883 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.interactor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.shared.logger.sceneLogger
@@ -25,5 +26,6 @@ val Kosmos.sceneBackInteractor by Fixture {
SceneBackInteractor(
logger = sceneLogger,
sceneContainerConfig = sceneContainerConfig,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index d105326ec3d0..65bfafbfa9b0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -36,6 +36,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.model.sysUiState
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.disabledContentInteractor
@@ -89,5 +90,6 @@ val Kosmos.sceneContainerStartable by Fixture {
disabledContentInteractor = disabledContentInteractor,
activityTransitionAnimator = activityTransitionAnimator,
shadeModeInteractor = shadeModeInteractor,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt
index a4631f17cb37..2ba9c8094aac 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt
@@ -21,6 +21,7 @@ import android.provider.Settings
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.shade.data.repository.shadeRepository
@@ -31,6 +32,7 @@ val Kosmos.shadeModeInteractor by Fixture {
applicationScope = applicationCoroutineScope,
repository = shadeRepository,
secureSettingsRepository = fakeSecureSettingsRepository,
+ tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
)
}
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index 3de84f17b583..d2db8f74cd05 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -27,7 +27,6 @@ import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
-import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UEventObserver;
@@ -37,6 +36,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -57,8 +57,6 @@ import java.util.Map;
final class DockObserver extends SystemService {
private static final String TAG = "DockObserver";
- private static final int MSG_DOCK_STATE_CHANGED = 0;
-
private final PowerManager mPowerManager;
private final PowerManager.WakeLock mWakeLock;
@@ -66,11 +64,16 @@ final class DockObserver extends SystemService {
private boolean mSystemReady;
+ @GuardedBy("mLock")
private int mActualDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ @GuardedBy("mLock")
private int mReportedDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+ @GuardedBy("mLock")
private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ @GuardedBy("mLock")
private boolean mUpdatesStopped;
private final boolean mKeepDreamingWhenUnplugging;
@@ -182,18 +185,24 @@ final class DockObserver extends SystemService {
ExtconInfo.EXTCON_DOCK
});
- if (!infos.isEmpty()) {
- ExtconInfo info = infos.get(0);
- Slog.i(TAG, "Found extcon info devPath: " + info.getDevicePath()
- + ", statePath: " + info.getStatePath());
-
- // set initial status
- setDockStateFromProviderLocked(ExtconStateProvider.fromFile(info.getStatePath()));
- mPreviousDockState = mActualDockState;
-
- mExtconUEventObserver.startObserving(info);
- } else {
- Slog.i(TAG, "No extcon dock device found in this kernel.");
+ synchronized (mLock) {
+ if (!infos.isEmpty()) {
+ ExtconInfo info = infos.get(0);
+ Slog.i(
+ TAG,
+ "Found extcon info devPath: "
+ + info.getDevicePath()
+ + ", statePath: "
+ + info.getStatePath());
+
+ // set initial status
+ setDockStateFromProviderLocked(ExtconStateProvider.fromFile(info.getStatePath()));
+ mPreviousDockState = mActualDockState;
+
+ mExtconUEventObserver.startObserving(info);
+ } else {
+ Slog.i(TAG, "No extcon dock device found in this kernel.");
+ }
}
mDockObserverLocalService = new DockObserverLocalService();
@@ -223,13 +232,15 @@ final class DockObserver extends SystemService {
}
}
+ @GuardedBy("mLock")
private void updateIfDockedLocked() {
// don't bother broadcasting undocked here
if (mReportedDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- updateLocked();
+ postWakefulDockStateChange();
}
}
+ @GuardedBy("mLock")
private void setActualDockStateLocked(int newState) {
mActualDockState = newState;
if (!mUpdatesStopped) {
@@ -237,6 +248,7 @@ final class DockObserver extends SystemService {
}
}
+ @GuardedBy("mLock")
private void setDockStateLocked(int newState) {
if (newState != mReportedDockState) {
mReportedDockState = newState;
@@ -246,10 +258,12 @@ final class DockObserver extends SystemService {
if (mSystemReady) {
// Wake up immediately when docked or undocked unless prohibited from doing so.
if (allowWakeFromDock()) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ mPowerManager.wakeUp(
+ SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_DOCK,
"android.server:DOCK");
}
- updateLocked();
+ postWakefulDockStateChange();
}
}
}
@@ -263,9 +277,8 @@ final class DockObserver extends SystemService {
Settings.Global.THEATER_MODE_ON, 0) == 0);
}
- private void updateLocked() {
- mWakeLock.acquire();
- mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
+ private void postWakefulDockStateChange() {
+ mHandler.post(mWakeLock.wrap(this::handleDockStateChange));
}
private void handleDockStateChange() {
@@ -348,17 +361,7 @@ final class DockObserver extends SystemService {
}
}
- private final Handler mHandler = new Handler(true /*async*/) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_DOCK_STATE_CHANGED:
- handleDockStateChange();
- mWakeLock.release();
- break;
- }
- }
- };
+ private final Handler mHandler = new Handler(true /*async*/);
private int getDockedStateExtraValue(ExtconStateProvider state) {
for (ExtconStateConfig config : mExtconStateConfigs) {
@@ -386,6 +389,7 @@ final class DockObserver extends SystemService {
}
}
+ @GuardedBy("mLock")
private void setDockStateFromProviderLocked(ExtconStateProvider provider) {
int state = Intent.EXTRA_DOCK_STATE_UNDOCKED;
if ("1".equals(provider.getValue("DOCK"))) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index d335529a006a..ce526e510053 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -572,6 +572,7 @@ public class CachedAppOptimizer {
public long mTotalAnonMemFreedKBs;
public long mSumOrigAnonRss;
public double mMaxCompactEfficiency;
+ public double mMaxSwapEfficiency;
// Cpu time
public long mTotalCpuTimeMillis;
@@ -586,6 +587,10 @@ public class CachedAppOptimizer {
if (compactEfficiency > mMaxCompactEfficiency) {
mMaxCompactEfficiency = compactEfficiency;
}
+ final double swapEfficiency = anonRssSaved / (double) origAnonRss;
+ if (swapEfficiency > mMaxSwapEfficiency) {
+ mMaxSwapEfficiency = swapEfficiency;
+ }
mTotalDeltaAnonRssKBs += anonRssSaved;
mTotalZramConsumedKBs += zramConsumed;
mTotalAnonMemFreedKBs += memFreed;
@@ -628,7 +633,11 @@ public class CachedAppOptimizer {
pw.println(" -----Memory Stats----");
pw.println(" Total Delta Anon RSS (KB) : " + mTotalDeltaAnonRssKBs);
pw.println(" Total Physical ZRAM Consumed (KB): " + mTotalZramConsumedKBs);
+ // Anon Mem Freed = Delta Anon RSS - ZRAM Consumed
pw.println(" Total Anon Memory Freed (KB): " + mTotalAnonMemFreedKBs);
+ pw.println(" Avg Swap Efficiency (KB) (Delta Anon RSS/Orig Anon RSS): "
+ + (mTotalDeltaAnonRssKBs / (double) mSumOrigAnonRss));
+ pw.println(" Max Swap Efficiency: " + mMaxSwapEfficiency);
// This tells us how much anon memory we were able to free thanks to running
// compaction
pw.println(" Avg Compaction Efficiency (Anon Freed/Anon RSS): "
@@ -808,8 +817,9 @@ public class CachedAppOptimizer {
pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size()
+ " processes.");
pw.println("Last Compaction per process stats:");
- pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs,"
- + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)");
+ pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs"
+ + ",SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
+ + "oomAdjReason)");
for (Map.Entry<Integer, SingleCompactionStats> entry :
mLastCompactionStats.entrySet()) {
SingleCompactionStats stats = entry.getValue();
@@ -818,7 +828,8 @@ public class CachedAppOptimizer {
pw.println();
pw.println("Last 20 Compactions Stats:");
pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs,"
- + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)");
+ + "SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
+ + "oomAdjReason)");
for (SingleCompactionStats stats : mCompactionStatsHistory) {
stats.dump(pw);
}
@@ -1779,6 +1790,8 @@ public class CachedAppOptimizer {
double getCompactEfficiency() { return mAnonMemFreedKBs / (double) mOrigAnonRss; }
+ double getSwapEfficiency() { return mDeltaAnonRssKBs / (double) mOrigAnonRss; }
+
double getCompactCost() {
// mCpuTimeMillis / (anonMemFreedKBs/1024) and metric is in (ms/MB)
return mCpuTimeMillis / (double) mAnonMemFreedKBs * 1024;
@@ -1791,7 +1804,8 @@ public class CachedAppOptimizer {
@NeverCompile
void dump(PrintWriter pw) {
pw.println(" (" + mProcessName + "," + mSourceType.name() + "," + mDeltaAnonRssKBs
- + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + "," + getCompactEfficiency()
+ + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + ","
+ + getSwapEfficiency() + "," + getCompactEfficiency()
+ "," + getCompactCost() + "," + mProcState + "," + mOomAdj + ","
+ OomAdjuster.oomAdjReasonToString(mOomAdjReason) + ")");
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index e753f273eb9b..4301c93cbed1 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -87,7 +87,6 @@ import android.service.quicksettings.TileService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
-import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -125,7 +124,6 @@ import com.android.server.policy.GlobalActionsProvider;
import com.android.server.power.ShutdownCheckPoints;
import com.android.server.power.ShutdownThread;
import com.android.server.wm.ActivityTaskManagerInternal;
-import com.android.systemui.shared.Flags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -343,19 +341,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onDisplayAdded(int displayId) {
- if (Flags.statusBarConnectedDisplays()) {
- synchronized (mLock) {
- mDisplayUiState.put(displayId, new UiState());
- }
+ synchronized (mLock) {
+ mDisplayUiState.put(displayId, new UiState());
}
}
@Override
public void onDisplayRemoved(int displayId) {
- if (Flags.statusBarConnectedDisplays()) {
- synchronized (mLock) {
- mDisplayUiState.remove(displayId);
- }
+ synchronized (mLock) {
+ mDisplayUiState.remove(displayId);
}
}
@@ -1366,66 +1360,53 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
return mTracingEnabled;
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
@Override
public void disable(int what, IBinder token, String pkg) {
disableForUser(what, token, pkg, mCurrentUserId);
}
- /**
- * Disable additional status bar features for user for all displays. Pass the bitwise-or of the
- * {@code #DISABLE_*} flags. To re-enable everything, pass {@code #DISABLE_NONE}.
- *
- * Warning: Only pass {@code #DISABLE_*} flags into this function, do not use
- * {@code #DISABLE2_*} flags.
- */
+ // TODO(b/117478341): make it aware of multi-display if needed.
@Override
public void disableForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
enforceValidCallingUser();
synchronized (mLock) {
- IntArray displayIds = new IntArray();
- for (int i = 0; i < mDisplayUiState.size(); i++) {
- displayIds.add(mDisplayUiState.keyAt(i));
- }
- disableLocked(displayIds, userId, what, token, pkg, 1);
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1);
}
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
/**
- * Disable additional status bar features. Pass the bitwise-or of the {@code #DISABLE2_*} flags.
- * To re-enable everything, pass {@code #DISABLE2_NONE}.
+ * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
+ * To re-enable everything, pass {@link #DISABLE2_NONE}.
*
- * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use
- * {@code #DISABLE_*} flags.
+ * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
*/
@Override
public void disable2(int what, IBinder token, String pkg) {
disable2ForUser(what, token, pkg, mCurrentUserId);
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
/**
- * Disable additional status bar features for a given user for all displays. Pass the bitwise-or
- * of the {@code #DISABLE2_*} flags. To re-enable everything, pass {@code #DISABLE2_NONE}.
+ * Disable additional status bar features for a given user. Pass the bitwise-or of the
+ * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
*
- * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use
- * {@code #DISABLE_*} flags.
+ * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
*/
@Override
public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
synchronized (mLock) {
- IntArray displayIds = new IntArray();
- for (int i = 0; i < mDisplayUiState.size(); i++) {
- displayIds.add(mDisplayUiState.keyAt(i));
- }
- disableLocked(displayIds, userId, what, token, pkg, 2);
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2);
}
}
- private void disableLocked(IntArray displayIds, int userId, int what, IBinder token,
- String pkg, int whichFlag) {
+ private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg,
+ int whichFlag) {
// It's important that the the callback and the call to mBar get done
// in the same order when multiple threads are calling this function
// so they are paired correctly. The messages on the handler will be
@@ -1435,27 +1416,18 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
// Ensure state for the current user is applied, even if passed a non-current user.
final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1);
final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2);
- boolean shouldCallNotificationOnSetDisabled = false;
- IStatusBar bar = mBar;
- for (int displayId : displayIds.toArray()) {
- final UiState state = getUiState(displayId);
- if (!state.disableEquals(net1, net2)) {
- shouldCallNotificationOnSetDisabled = true;
- state.setDisabled(net1, net2);
- if (bar != null) {
- try {
- // TODO(b/388244660): Create IStatusBar#disableForAllDisplays to avoid
- // multiple IPC calls.
- bar.disable(displayId, net1, net2);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Unable to disable Status bar.", ex);
- }
+ final UiState state = getUiState(displayId);
+ if (!state.disableEquals(net1, net2)) {
+ state.setDisabled(net1, net2);
+ mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
+ IStatusBar bar = mBar;
+ if (bar != null) {
+ try {
+ bar.disable(displayId, net1, net2);
+ } catch (RemoteException ex) {
}
}
}
- if (shouldCallNotificationOnSetDisabled) {
- mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
- }
}
/**
@@ -1610,8 +1582,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")");
synchronized (mLock) {
- disableLocked(IntArray.wrap(new int[]{displayId}), mCurrentUserId, flags,
- mSysUiVisToken, cause, 1);
+ disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cf111cdbcc6a..ddb9f178cb8b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2988,38 +2988,45 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.DEVICE_POWER);
}
-
- synchronized (mGlobalLock) {
- final long ident = Binder.clearCallingIdentity();
- if (mKeyguardShown != keyguardShowing) {
- mKeyguardShown = keyguardShowing;
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::reportCurKeyguardUsageEvent, mAmInternal,
- keyguardShowing);
- mH.sendMessage(msg);
- }
- // Always reset the state regardless of keyguard-showing change, because that means the
- // unlock is either completed or canceled.
- if ((mDemoteTopAppReasons & DEMOTE_TOP_REASON_DURING_UNLOCKING) != 0) {
- mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING;
- // The scheduling group of top process was demoted by unlocking, so recompute
- // to restore its real top priority if possible.
- if (mTopApp != null) {
- mTopApp.scheduleUpdateOomAdj();
- }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ setLockScreenShownLocked(keyguardShowing, aodShowing);
}
- try {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown");
- mRootWindowContainer.forAllDisplays(displayContent -> {
- mKeyguardController.setKeyguardShown(displayContent.getDisplayId(),
- keyguardShowing, aodShowing);
- });
- maybeHideLockedProfileActivityLocked();
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- Binder.restoreCallingIdentity(ident);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @GuardedBy("mGlobalLock")
+ void setLockScreenShownLocked(boolean keyguardShowing, boolean aodShowing) {
+ if (mKeyguardShown != keyguardShowing) {
+ mKeyguardShown = keyguardShowing;
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::reportCurKeyguardUsageEvent, mAmInternal,
+ keyguardShowing);
+ mH.sendMessage(msg);
+ }
+ // Always reset the state regardless of keyguard-showing change, because that means the
+ // unlock is either completed or canceled.
+ if ((mDemoteTopAppReasons & DEMOTE_TOP_REASON_DURING_UNLOCKING) != 0) {
+ mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING;
+ // The scheduling group of top process was demoted by unlocking, so recompute
+ // to restore its real top priority if possible.
+ if (mTopApp != null) {
+ mTopApp.scheduleUpdateOomAdj();
}
}
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown");
+ mRootWindowContainer.forAllDisplays(displayContent -> {
+ mKeyguardController.setKeyguardShown(displayContent.getDisplayId(),
+ keyguardShowing, aodShowing);
+ });
+ maybeHideLockedProfileActivityLocked();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
mH.post(() -> {
for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 060f2e803ec9..b4c2c0173767 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1865,7 +1865,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (keyguardState != null) {
boolean keyguardShowing = keyguardState.getKeyguardShowing();
boolean aodShowing = keyguardState.getAodShowing();
- mService.setLockScreenShown(keyguardShowing, aodShowing);
+ mService.setLockScreenShownLocked(keyguardShowing, aodShowing);
}
return effects;
}
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index 263ada8b36f6..148c96850d34 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -69,7 +69,6 @@ import android.os.Binder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.platform.test.annotations.EnableFlags;
import android.service.quicksettings.TileService;
import android.testing.TestableContext;
@@ -80,7 +79,6 @@ import com.android.internal.statusbar.IStatusBar;
import com.android.server.LocalServices;
import com.android.server.policy.GlobalActionsProvider;
import com.android.server.wm.ActivityTaskManagerInternal;
-import com.android.systemui.shared.Flags;
import libcore.junit.util.compat.CoreCompatChangeRule;
@@ -107,7 +105,6 @@ public class StatusBarManagerServiceTest {
TEST_SERVICE);
private static final CharSequence APP_NAME = "AppName";
private static final CharSequence TILE_LABEL = "Tile label";
- private static final int SECONDARY_DISPLAY_ID = 2;
@Rule
public final TestableContext mContext =
@@ -752,29 +749,6 @@ public class StatusBarManagerServiceTest {
}
@Test
- @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
- public void testDisableForAllDisplays() throws Exception {
- int user1Id = 0;
- mockUidCheck();
- mockCurrentUserCheck(user1Id);
-
- mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID);
-
- int expectedFlags = DISABLE_MASK & DISABLE_BACK;
- String pkg = mContext.getPackageName();
-
- // before disabling
- assertEquals(DISABLE_NONE,
- mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]);
-
- // disable
- mStatusBarManagerService.disable(expectedFlags, mMockStatusBar, pkg);
-
- verify(mMockStatusBar).disable(0, expectedFlags, 0);
- verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, expectedFlags, 0);
- }
-
- @Test
public void testSetHomeDisabled() throws Exception {
int expectedFlags = DISABLE_MASK & DISABLE_HOME;
String pkg = mContext.getPackageName();
@@ -877,29 +851,6 @@ public class StatusBarManagerServiceTest {
}
@Test
- @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
- public void testDisable2ForAllDisplays() throws Exception {
- int user1Id = 0;
- mockUidCheck();
- mockCurrentUserCheck(user1Id);
-
- mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID);
-
- int expectedFlags = DISABLE2_MASK & DISABLE2_NOTIFICATION_SHADE;
- String pkg = mContext.getPackageName();
-
- // before disabling
- assertEquals(DISABLE_NONE,
- mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]);
-
- // disable
- mStatusBarManagerService.disable2(expectedFlags, mMockStatusBar, pkg);
-
- verify(mMockStatusBar).disable(0, 0, expectedFlags);
- verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, 0, expectedFlags);
- }
-
- @Test
public void testSetQuickSettingsDisabled2() throws Exception {
int expectedFlags = DISABLE2_MASK & DISABLE2_QUICK_SETTINGS;
String pkg = mContext.getPackageName();
@@ -1141,7 +1092,6 @@ public class StatusBarManagerServiceTest {
// disable
mStatusBarManagerService.disableForUser(expectedUser1Flags, mMockStatusBar, pkg, user1Id);
mStatusBarManagerService.disableForUser(expectedUser2Flags, mMockStatusBar, pkg, user2Id);
-
// check that right flag is disabled
assertEquals(expectedUser1Flags,
mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]);
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
index a0e047759dab..1fb18a6bb391 100644
--- a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
+++ b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
@@ -39,13 +39,4 @@ python_test_host {
device_common_data: [
":cdm_snippet_legacy",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: true,
- },
- },
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index 03d6ce88ac0c..18f44ddff086 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -51,8 +51,8 @@ constructor(
instrumentation.targetContext.contentResolver,
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
0,
- UserHandle.USER_CURRENT
- );
+ UserHandle.USER_CURRENT_OR_SELF
+ )
}
private val logTag = this::class.java.simpleName