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

Commit e73031e5 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Introduce dream suppression" into main

parents 990fdf54 d9dffaa1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -2138,3 +2138,12 @@ flag {
    }
}

flag {
    name: "dream_suppression"
    namespace: "systemui"
    description: "Suppress dream when device is in a vehicle."
    bug: "433984504"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}
+73 −0
Original line number Diff line number Diff line
/*
 * 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.dreams.suppression

import android.os.PowerManager
import android.os.powerManager
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_DREAM_SUPPRESSION
import com.android.systemui.SysuiTestCase
import com.android.systemui.dreams.suppression.data.repository.fakeActivityRecognitionRepository
import com.android.systemui.dreams.suppression.shared.model.DreamSuppression
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
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.testKosmos
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.kotlin.any

@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableFlags(FLAG_DREAM_SUPPRESSION)
class DreamSuppressionStartableTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

    private val Kosmos.underTest by Fixture {
        DreamSuppressionStartable(
            bgScope = kosmos.applicationCoroutineScope,
            activityRecognitionRepository = kosmos.fakeActivityRecognitionRepository,
            powerManager = kosmos.powerManager,
            logBuffer = logcatLogBuffer("DreamSuppressionStartableTest"),
        )
    }

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

            fakeActivityRecognitionRepository.setInVehicle(true)
            verify(powerManager)
                .suppressAmbientDisplay(
                    DreamSuppression.InVehicle.token,
                    PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM,
                )

            fakeActivityRecognitionRepository.setInVehicle(false)
            verify(powerManager)
                .suppressAmbientDisplay(DreamSuppression.None.token, /* suppress= */ false)
        }
}
+5 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.hardware.SensorPrivacyManager;

import com.android.keyguard.KeyguardViewController;
import com.android.systemui.CoreStartable;
import com.android.systemui.Flags;
import com.android.systemui.ScreenDecorationsModule;
import com.android.systemui.accessibility.AccessibilityModule;
import com.android.systemui.accessibility.SystemActionsModule;
@@ -39,10 +40,8 @@ import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.dreams.suppression.dagger.NoOpActivityRecognitionModule;
import com.android.systemui.education.dagger.ContextualEducationModule;
import com.android.systemui.Flags;
import com.android.systemui.minmode.MinModeManager;
import com.android.systemui.minmode.MinModeManagerImpl;
import com.android.systemui.emergency.EmergencyGestureModule;
import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialModule;
import com.android.systemui.keyboard.shortcut.ShortcutHelperModule;
@@ -53,6 +52,8 @@ import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsMod
import com.android.systemui.media.dagger.MediaModule;
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.minmode.MinModeManager;
import com.android.systemui.minmode.MinModeManagerImpl;
import com.android.systemui.navigationbar.NavigationBarControllerModule;
import com.android.systemui.navigationbar.gestural.GestureModule;
import com.android.systemui.plugins.qs.QSFactory;
@@ -157,6 +158,7 @@ import javax.inject.Provider;
        MultiUserUtilsModule.class,
        NavigationBarControllerModule.class,
        NearbyMediaDevicesManager.StartableModule.class,
        NoOpActivityRecognitionModule.class,
        PowerModule.class,
        QSFragmentStartableModule.class,
        QSModule.class,
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.dreams.homecontrols.HomeControlsDreamService;
import com.android.systemui.dreams.homecontrols.dagger.HomeControlsDataSourceModule;
import com.android.systemui.dreams.homecontrols.dagger.HomeControlsRemoteServiceComponent;
import com.android.systemui.dreams.homecontrols.system.HomeControlsRemoteService;
import com.android.systemui.dreams.suppression.dagger.DreamSuppressionStartableModule;
import com.android.systemui.lowlightclock.LowLightClockDreamService;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.pipeline.shared.TileSpec;
@@ -72,6 +73,7 @@ import javax.inject.Named;
        ScrimModule.class,
        HomeControlsDataSourceModule.class,
        DreamSettingsRepositoryModule.class,
        DreamSuppressionStartableModule.class,
},
        subcomponents = {
                DreamComplicationComponent.class,
+93 −0
Original line number Diff line number Diff line
/*
 * 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.dreams.suppression

import android.Manifest.permission.WRITE_DREAM_STATE
import android.os.PowerManager
import androidx.annotation.RequiresPermission
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.dreamSuppression
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dreams.suppression.data.repository.ActivityRecognitionRepository
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 javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
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

/** Manages the suppression of dreams. */
@SysUISingleton
class DreamSuppressionStartable
@Inject
constructor(
    @Background private val bgScope: CoroutineScope,
    private val activityRecognitionRepository: ActivityRecognitionRepository,
    private val powerManager: PowerManager,
    @DreamLog private val logBuffer: LogBuffer,
) : CoreStartable {

    private val logger = Logger(logBuffer, TAG)

    @RequiresPermission(WRITE_DREAM_STATE)
    override fun start() {
        if (!dreamSuppression()) {
            return
        }

        activityRecognitionRepository.inVehicle
            .map { inVehicle ->
                if (inVehicle) {
                    DreamSuppression.InVehicle
                } else {
                    DreamSuppression.None
                }
            }
            .distinctUntilChanged()
            // No-op until dream suppression becomes true
            .dropWhile { !it.isSuppressed() }
            .onEach { dreamSuppression ->
                logger.i({ "Dream suppression updated: suppressed=$bool1 reason=$str1" }) {
                    bool1 = dreamSuppression.isSuppressed()
                    str1 = dreamSuppression.token
                }

                if (dreamSuppression.isSuppressed()) {
                    powerManager.suppressAmbientDisplay(
                        dreamSuppression.token,
                        PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM,
                    )
                } else {
                    powerManager.suppressAmbientDisplay(
                        dreamSuppression.token,
                        /*suppress=*/ false,
                    )
                }
            }
            .launchIn(bgScope)
    }

    private companion object {
        const val TAG = "DreamSuppressionStartable"
    }
}
Loading