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

Commit f6762fcb authored by brycelee's avatar brycelee Committed by Bryce Lee
Browse files

Support additional low-light behaviors.

This changelist introduces support for no dream and screen off
low-light behaviors.

Test: atest AmbientSuppressionLowLightActionTest
Fixes: 408229468
Flag:  android.os.low_light_dream_behavior
Change-Id: I2f535daaa7f52c5b8c0666af74222f9da0b9f7c9
parent a340e055
Loading
Loading
Loading
Loading
+67 −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.ambient.lowlight

import android.os.PowerManager
import android.os.powerManager
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import kotlin.test.Test
import kotlinx.coroutines.launch
import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWithLooper
@EnableFlags(android.os.Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
class AmbientSuppressionLowLightActionTest : SysuiTestCase() {
    val kosmos = testKosmos().useUnconfinedTestDispatcher()

    @Test
    fun testSuppressionInvokesPowerManager() =
        kosmos.runTest {
            val flags =
                PowerManager.FLAG_AMBIENT_SUPPRESSION_AOD or
                    PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM
            val suppression = AmbientSuppressionLowLightAction(powerManager = powerManager, flags)
            val job = testScope.backgroundScope.launch { suppression.activate() }

            val tagCaptor = argumentCaptor<String>()

            verify(powerManager).suppressAmbientDisplay(tagCaptor.capture(), eq(flags))

            clearInvocations(powerManager)
            job.cancel()

            verify(powerManager)
                .suppressAmbientDisplay(
                    eq(tagCaptor.lastValue),
                    eq(PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE),
                )
        }
}
+3 −1
Original line number Diff line number Diff line
@@ -16,18 +16,20 @@

package com.android.systemui.ambient.dagger

import com.android.systemui.ambient.lowlight.dagger.AmbientLowLightModule
import com.android.systemui.ambient.statusbar.dagger.AmbientStatusBarComponent
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
import com.android.systemui.ambient.touch.dagger.InputSessionComponent
import dagger.Module

@Module(
    includes = [AmbientLowLightModule::class],
    subcomponents =
        [
            AmbientStatusBarComponent::class,
            AmbientTouchComponent::class,
            InputSessionComponent::class,
        ]
        ],
)
interface AmbientModule {
    companion object {
+49 −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.ambient.lowlight

import android.os.PowerManager
import com.android.systemui.ambient.lowlight.dagger.AmbientSuppressionModule
import com.android.systemui.lifecycle.ExclusiveActivatable
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.awaitCancellation

/**
 * {@link AmbientSuppressionLowLightAction} is a {@link LowLightAction} implementation configurable
 * via dagger to suppress the ambient display via {@link PowerManager} during low-light.
 */
class AmbientSuppressionLowLightAction
@Inject
constructor(
    private val powerManager: PowerManager,
    @Named(AmbientSuppressionModule.AMBIENT_SUPPRESSION_SUPPRESSION_FLAGS) private val flags: Int,
) : ExclusiveActivatable() {
    private val suppressionToken: String = "AmbientSuppressionLowLightAction:" + flags

    override suspend fun onActivated(): Nothing {
        try {
            powerManager.suppressAmbientDisplay(suppressionToken, flags)
            awaitCancellation()
        } finally {
            powerManager.suppressAmbientDisplay(
                suppressionToken,
                PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE,
            )
        }
    }
}
+48 −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.ambient.lowlight.dagger

import android.os.PowerManager
import com.android.systemui.lowlight.shared.model.LowLightActionEntry
import com.android.systemui.lowlight.shared.model.LowLightDisplayBehavior
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet

@Module(subcomponents = [AmbientSuppressionComponent::class])
object AmbientLowLightModule {

    @Provides
    @IntoSet
    fun providesScreenOffLowLightActionEntry(
        factory: AmbientSuppressionComponent.Factory
    ): LowLightActionEntry {
        return LowLightActionEntry(LowLightDisplayBehavior.SCREEN_OFF) {
            factory.create(PowerManager.FLAG_AMBIENT_SUPPRESSION_ALL).getLowLightAction()
        }
    }

    @Provides
    @IntoSet
    fun providesDreamOffLowLightActionEntry(
        factory: AmbientSuppressionComponent.Factory
    ): LowLightActionEntry {
        return LowLightActionEntry(LowLightDisplayBehavior.NO_DREAM) {
            factory.create(PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM).getLowLightAction()
        }
    }
}
+36 −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.ambient.lowlight.dagger

import com.android.systemui.ambient.lowlight.AmbientSuppressionLowLightAction
import dagger.BindsInstance
import dagger.Subcomponent
import javax.inject.Named

@Subcomponent(modules = [AmbientSuppressionModule::class])
interface AmbientSuppressionComponent {
    @Subcomponent.Factory
    interface Factory {
        fun create(
            @Named(AmbientSuppressionModule.AMBIENT_SUPPRESSION_SUPPRESSION_FLAGS)
            @BindsInstance
            suppressionFlags: Int
        ): AmbientSuppressionComponent
    }

    fun getLowLightAction(): AmbientSuppressionLowLightAction
}
Loading