Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31a8a537 authored by Lucas Silva's avatar Lucas Silva
Browse files

Move direct boot logic out of condition monitor framework

Deletes the legacy DirectBootCondition and instead just monitors for
whether the current user is unlocked inside LowLightMonitor

Bug: 407633926
Test: atest LowLightMonitorTest
Flag: EXEMPT bugfix
Change-Id: Icf248616c143478c646f956aef72a8466a20d038
parent 3d55c2e5
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ import com.android.systemui.shared.condition.Condition
import com.android.systemui.shared.condition.Monitor
import com.android.systemui.statusbar.commandline.commandRegistry
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.user.domain.interactor.selectedUserInteractor
import com.android.systemui.user.domain.interactor.userLockedInteractor
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
@@ -85,6 +87,7 @@ class LowLightMonitorTest : SysuiTestCase() {
                packageManager = packageManager,
                scope = backgroundScope,
                commandRegistry = commandRegistry,
                userLockedInteractor = userLockedInteractor,
            )
        }

@@ -115,9 +118,14 @@ class LowLightMonitorTest : SysuiTestCase() {
        commandRegistry.onShellCommand(printWriter, arrayOf(LowLightMonitor.COMMAND_ROOT, value))
    }

    private fun Kosmos.setUserUnlocked(unlocked: Boolean) {
        fakeUserRepository.setUserUnlocked(selectedUserInteractor.getSelectedUserId(), unlocked)
    }

    @Before
    fun setUp() {
        kosmos.setDisplayOn(false)
        kosmos.setUserUnlocked(true)

        // Activate dreams on charge by default
        mContext.orCreateTestableResources.addOverride(
@@ -267,6 +275,30 @@ class LowLightMonitorTest : SysuiTestCase() {
                .setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
        }

    @Test
    fun testLowlightForcedToTrueWhenUserLocked() =
        kosmos.runTest {
            setDisplayOn(true)
            // low-light condition is false
            condition.setValue(false)

            underTest.start()
            verify(lowLightDreamManager)
                .setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR)
            clearInvocations(lowLightDreamManager)

            // locked user forces lowlight
            setUserUnlocked(false)
            verify(lowLightDreamManager)
                .setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
            clearInvocations(lowLightDreamManager)

            // clear forced state and ensure we go back to regular mode
            setUserUnlocked(true)
            verify(lowLightDreamManager)
                .setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR)
        }

    private class FakeCondition(
        scope: CoroutineScope,
        initialValue: Boolean?,
+4 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.communal.domain.suppression.dagger

import android.os.UserHandle
import com.android.systemui.Flags.glanceableHubV2
import com.android.systemui.communal.data.model.SuppressionReason
import com.android.systemui.communal.domain.interactor.CarProjectionInteractor
@@ -77,9 +78,9 @@ interface CommunalSuppressionModule {
        @Provides
        @IntoSet
        fun bindUserLockedSuppressor(interactor: UserLockedInteractor): Flow<SuppressionReason?> {
            return interactor.currentUserUnlocked.mapToReasonIfNotAllowed(
                SuppressionReason.ReasonUserLocked
            )
            return interactor
                .isUserUnlocked(UserHandle.CURRENT)
                .mapToReasonIfNotAllowed(SuppressionReason.ReasonUserLocked)
        }

        @Provides
+0 −59
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.lowlightclock

import android.content.Intent
import android.content.IntentFilter
import android.os.UserManager
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.shared.condition.Condition
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

class DirectBootCondition
@Inject
constructor(
    broadcastDispatcher: BroadcastDispatcher,
    private val userManager: UserManager,
    @Background private val coroutineScope: CoroutineScope,
) : Condition(coroutineScope) {
    private var job: Job? = null
    private val directBootFlow =
        broadcastDispatcher
            .broadcastFlow(IntentFilter(Intent.ACTION_USER_UNLOCKED))
            .map { !userManager.isUserUnlocked }
            .cancellable()
            .distinctUntilChanged()

    override suspend fun start() {
        job = coroutineScope.launch { directBootFlow.collect { updateCondition(it) } }
        updateCondition(!userManager.isUserUnlocked)
    }

    override fun stop() {
        job?.cancel()
    }

    override val startStrategy: Int
        get() = START_EAGERLY
}
+20 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.systemui.lowlightclock

import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.UserHandle
import com.android.dream.lowlight.LowLightDreamManager
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.dagger.qualifiers.Background
@@ -29,10 +30,12 @@ import com.android.systemui.shared.condition.Condition
import com.android.systemui.shared.condition.Monitor
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.user.domain.interactor.UserLockedInteractor
import com.android.systemui.util.condition.ConditionalCoreStartable
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import dagger.Lazy
import java.io.PrintWriter
import javax.inject.Inject
@@ -45,7 +48,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -70,6 +72,7 @@ constructor(
    private val packageManager: PackageManager,
    @Background private val scope: CoroutineScope,
    private val commandRegistry: CommandRegistry,
    userLockedInteractor: UserLockedInteractor,
) : ConditionalCoreStartable(conditionsMonitor) {

    /** Whether the screen is currently on. */
@@ -100,8 +103,19 @@ constructor(
    }

    private val isLowLight: Flow<Boolean> =
        combine(isLowLightForced, isLowLightFromSensor) { forcedValue, sensorValue ->
            forcedValue ?: sensorValue
        combine(
            not(userLockedInteractor.isUserUnlocked(UserHandle.CURRENT)),
            isLowLightForced,
            isLowLightFromSensor,
        ) { directBoot, forcedValue, sensorValue ->
            if (forcedValue != null) {
                forcedValue
            } else if (directBoot) {
                // If user is locked, normal dreams cannot start so we force lowlight dream.
                true
            } else {
                sensorValue
            }
        }

    @OptIn(ExperimentalCoroutinesApi::class)
@@ -123,8 +137,8 @@ constructor(
            }

            allOf(isScreenOn, dreamEnabled)
                .flatMapLatest {
                    if (it) {
                .flatMapLatestConflated { conditionsMet ->
                    if (conditionsMet) {
                        isLowLight
                    } else {
                        flowOf(false)
@@ -163,7 +177,7 @@ constructor(
        }

        override fun help(pw: PrintWriter) {
            pw.println("Usage: adb shell cmd statusbar low-light <cmd>")
            pw.println("Usage: adb shell cmd statusbar $COMMAND_ROOT <cmd>")
            pw.println("Supported commands:")
            pw.println("  - enable")
            pw.println("    forces device into low-light")
+5 −14
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.lowlightclock.AmbientLightModeMonitor.DebounceAlgorithm
import com.android.systemui.lowlightclock.DirectBootCondition
import com.android.systemui.lowlightclock.LowLightCondition
import com.android.systemui.lowlightclock.LowLightDisplayController
import com.android.systemui.lowlightclock.LowLightMonitor
@@ -47,6 +46,11 @@ abstract class LowLightModule {
    @Named(LOW_LIGHT_PRECONDITIONS)
    abstract fun bindDeviceInactiveCondition(condition: DeviceInactiveCondition): Condition

    @Binds
    @IntoSet
    @Named(LOW_LIGHT_PRECONDITIONS)
    abstract fun bindLowLightCondition(condition: LowLightCondition): Condition

    @BindsOptionalOf abstract fun bindsLowLightDisplayController(): LowLightDisplayController

    @BindsOptionalOf @Named(LIGHT_SENSOR) abstract fun bindsLightSensor(): Sensor
@@ -78,19 +82,6 @@ abstract class LowLightModule {
            return factory.create("LowLightLog", 250)
        }

        @Provides
        @IntoSet
        @Named(LOW_LIGHT_PRECONDITIONS)
        fun provideLowLightCondition(
            lowLightCondition: LowLightCondition,
            directBootCondition: DirectBootCondition,
        ): Condition {
            // Start lowlight if we are either in lowlight or in direct boot. The ordering of the
            // conditions matters here since we don't want to start the lowlight condition if
            // we are in direct boot mode.
            return directBootCondition.or(lowLightCondition)
        }

        /**  */
        @JvmStatic
        @Provides
Loading