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

Commit 861009b0 authored by Darrell Shi's avatar Darrell Shi Committed by Android Build Coastguard Worker
Browse files

Subscribe to activity recognition on charging only

This change makes the subscription of CHRE activity recognition depend
on device charging, which improves battery performance.

Test: atest DreamSuppressionStartableTest
Test: verified subscription only while charging
Fix: 445522597
Flag: com.android.systemui.dream_suppression
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:f219544ca37800e73c521cc6afae8ef635038679
Merged-In: Ib57802a4bb096ea199621fc95feaa046db6289e1
Change-Id: Ib57802a4bb096ea199621fc95feaa046db6289e1
parent 7ff7089e
Loading
Loading
Loading
Loading
+55 −2
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.statusbar.pipeline.battery.domain.interactor.batteryInteractor
import com.android.systemui.statusbar.policy.batteryController
import com.android.systemui.statusbar.policy.fake
import com.android.systemui.testKosmos
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,17 +51,21 @@ class DreamSuppressionStartableTest : SysuiTestCase() {
        DreamSuppressionStartable(
            bgScope = kosmos.applicationCoroutineScope,
            activityRecognitionRepository = kosmos.fakeActivityRecognitionRepository,
            batteryInteractor = kosmos.batteryInteractor,
            powerManager = kosmos.powerManager,
            logBuffer = logcatLogBuffer("DreamSuppressionStartableTest"),
        )
    }

    @Test
    fun suppressDreamWhenInVehicle() =
    fun suppressDreamWhenInVehicleAndCharging() =
        kosmos.runTest {
            underTest.start()

            setIsCharging(true)
            verify(powerManager, never()).suppressAmbientDisplay(any<String>(), any<Int>())

            // When in a vehicle, the dream should be suppressed
            fakeActivityRecognitionRepository.setInVehicle(true)
            verify(powerManager)
                .suppressAmbientDisplay(
@@ -66,8 +73,54 @@ class DreamSuppressionStartableTest : SysuiTestCase() {
                    PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM,
                )

            // When no longer in a vehicle, the dream should be unsuppressed
            fakeActivityRecognitionRepository.setInVehicle(false)
            verify(powerManager).suppressAmbientDisplay(DreamSuppression.InVehicle.token, false)
        }

    @Test
    fun noSuppressionWhenNotInVehicleAndCharging() =
        kosmos.runTest {
            underTest.start()
            setIsCharging(true)
            verify(powerManager, never()).suppressAmbientDisplay(any<String>(), any<Int>())

            // When not in a vehicle, the dream should not be suppressed
            fakeActivityRecognitionRepository.setInVehicle(false)
            verify(powerManager, never()).suppressAmbientDisplay(any<String>(), any<Int>())
        }

    @Test
    fun noSuppressionWhenInVehicleAndNotCharging() =
        kosmos.runTest {
            underTest.start()
            setIsCharging(false)
            verify(powerManager, never()).suppressAmbientDisplay(any<String>(), any<Int>())

            // When in a vehicle but not charging, the dream should not be suppressed
            fakeActivityRecognitionRepository.setInVehicle(true)
            verify(powerManager, never()).suppressAmbientDisplay(any<String>(), any<Int>())
        }

    @Test
    fun unsuppressWhenNoLongerCharging() =
        kosmos.runTest {
            underTest.start()
            setIsCharging(true)
            fakeActivityRecognitionRepository.setInVehicle(true)
            verify(powerManager)
                .suppressAmbientDisplay(DreamSuppression.None.token, /* suppress= */ false)
                .suppressAmbientDisplay(
                    DreamSuppression.InVehicle.token,
                    PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM,
                )

            // When no longer charging, the dream should be unsuppressed
            setIsCharging(false)
            verify(powerManager).suppressAmbientDisplay(DreamSuppression.InVehicle.token, false)
        }

    private fun Kosmos.setIsCharging(isCharging: Boolean) {
        batteryController.fake._isPluggedIn = isCharging
        batteryController.fake._isIncompatibleCharging = !isCharging
    }
}
+63 −25
Original line number Diff line number Diff line
@@ -28,13 +28,16 @@ import com.android.systemui.dreams.suppression.shared.model.DreamSuppression
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.DreamLog
import com.android.systemui.statusbar.pipeline.battery.domain.interactor.BatteryInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch

/** Manages the suppression of dreams. */
@SysUISingleton
@@ -43,11 +46,13 @@ class DreamSuppressionStartable
constructor(
    @Background private val bgScope: CoroutineScope,
    private val activityRecognitionRepository: ActivityRecognitionRepository,
    private val batteryInteractor: BatteryInteractor,
    private val powerManager: PowerManager,
    @DreamLog private val logBuffer: LogBuffer,
) : CoreStartable {

    private val logger = Logger(logBuffer, TAG)
    private var inVehicleJob: Job? = null

    @RequiresPermission(WRITE_DREAM_STATE)
    override fun start() {
@@ -55,6 +60,26 @@ constructor(
            return
        }

        batteryInteractor.isCharging
            .onEach { isCharging ->
                if (isCharging) {
                    startInVehicleDetection()
                } else {
                    stopInVehicleDetection()
                }
            }
            .launchIn(bgScope)
    }

    @RequiresPermission(WRITE_DREAM_STATE)
    private fun startInVehicleDetection() {
        if (inVehicleJob != null) {
            return
        }

        logger.i("Starting in-vehicle detection")
        inVehicleJob =
            bgScope.launch {
                activityRecognitionRepository.inVehicle
                    .map { inVehicle ->
                        if (inVehicle) {
@@ -79,12 +104,25 @@ constructor(
                            )
                        } else {
                            powerManager.suppressAmbientDisplay(
                        dreamSuppression.token,
                                DreamSuppression.InVehicle.token,
                                /*suppress=*/ false,
                            )
                        }
                    }
            .launchIn(bgScope)
                    .launchIn(this)
            }
    }

    @RequiresPermission(WRITE_DREAM_STATE)
    private fun stopInVehicleDetection() {
        if (inVehicleJob == null) {
            return
        }

        logger.i("Stopping in-vehicle detection")
        inVehicleJob?.cancel()
        inVehicleJob = null
        powerManager.suppressAmbientDisplay(DreamSuppression.InVehicle.token, /* suppress= */ false)
    }

    private companion object {