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

Commit 95e6035f authored by Behnam Heydarshahi's avatar Behnam Heydarshahi
Browse files

Modernize flashlight data & domain layer

Using flows instead of callbacks.
Add support for flashlight levels.

Bug: 399472912
Flag: com.android.systemui.flashlight_strength
Test: atest FlashlightRepositoryTest FlashlightInteractorTest
Change-Id: Ib541f012f910ea9709d79cf59f0b7136a5c2f70d
parent 65812195
Loading
Loading
Loading
Loading
+538 −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.flashlight.data.repository

import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager.TorchCallback
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.cameraManager
import com.android.systemui.camera.injectCameraCharacteristics
import com.android.systemui.flashlight.shared.model.FlashlightModel
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import kotlin.time.Duration.Companion.seconds
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify

@MediumTest
@EnableFlags(com.android.systemui.Flags.FLAG_FLASHLIGHT_STRENGTH)
@RunWith(AndroidJUnit4::class)
class FlashlightRepositoryTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val underTest = kosmos.flashlightRepository

    @Test
    fun deviceDoesNotSupportCameraFlashlight_statePermanentlyUnavailable() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            startFlashlightRepository(false)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Permanently.NotSupported)
            verify(cameraManager, never()).registerTorchCallback(any<Executor>(), any())
        }

    @Test
    fun flashSupportedButNotAvailable_stateTemporarilyFlashlightNotFound() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)
            injectCameraCharacteristics(false)
            startFlashlightRepository(true)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)
            verify(cameraManager, never()).registerTorchCallback(any<Executor>(), any())
        }

    @Test
    fun onlyFrontFlashlight_stateTemporarilyFlashlightNotFound() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_FRONT)
            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)
            verify(cameraManager, never())
                .registerTorchCallback(Mockito.any<Executor>(), Mockito.any())
        }

    @Test
    fun supportsFeatureAndHasBackFlashlightAndDoesNotSupportLevel_stateAvailableBinaryOff() =
        kosmos.runTest {
            injectCameraCharacteristics(
                true,
                CameraCharacteristics.LENS_FACING_BACK,
                maxLevel = BASE_TORCH_LEVEL,
            )

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))
        }

    @Test
    fun maxLevelMissing_stateIsBinary() =
        kosmos.runTest {
            injectCameraCharacteristics(
                true,
                CameraCharacteristics.LENS_FACING_BACK,
                maxLevel = null,
            )

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))

            underTest.setEnabled(true)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(true))
        }

    @Test
    fun defaultLevelMissing_stateIsLevel() =
        kosmos.runTest {
            injectCameraCharacteristics(
                true,
                CameraCharacteristics.LENS_FACING_BACK,
                defaultLevel = null,
            )

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))

            underTest.setEnabled(true)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(true))
        }

    @Test
    fun bothMaxAndDefaultLevelsMissing_stateIsBinary() =
        kosmos.runTest {
            injectCameraCharacteristics(
                true,
                CameraCharacteristics.LENS_FACING_BACK,
                defaultLevel = null,
                maxLevel = null,
            )

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))

            underTest.setEnabled(true)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(true))
        }

    @Test
    fun setLevelOnBinary_stateRemainsBinary() =
        kosmos.runTest {
            injectCameraCharacteristics(
                true,
                CameraCharacteristics.LENS_FACING_BACK,
                maxLevel = BASE_TORCH_LEVEL,
            )

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))

            underTest.setLevel(DEFAULT_DEFAULT_LEVEL)

            assertThat(state).isEqualTo(FlashlightModel.Available.Binary(false))
        }

    @Test
    fun supportsFeatureAndHasBackFlashlightAndSupportsLevels_stateAvailableDisabledLevelDefault() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun changeLevel_stateUpdates() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setLevel(DEFAULT_MAX_LEVEL)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_MAX_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun enable_stateUpdates() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(true)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun setCallbackUnavailable_stateBecomesCameraInUse() =
        kosmos.runTest {
            val torchCallbackCaptor = ArgumentCaptor.forClass(TorchCallback::class.java)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            verify(cameraManager).registerTorchCallback(any(), torchCallbackCaptor.capture())

            torchCallbackCaptor.value.onTorchModeUnavailable(DEFAULT_ID)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.CameraInUse)
        }

    @Test(expected = IllegalArgumentException::class)
    fun setLevel0_throwsException() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            val disabledAtDefaultLevel =
                FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)

            assertThat(state).isEqualTo(disabledAtDefaultLevel)

            underTest.setLevel(0)

            assertThat(state).isEqualTo(disabledAtDefaultLevel)
        }

    @Test(expected = IllegalArgumentException::class)
    fun setLevelNegative_throwsException() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            val disabledAtDefaultLevel =
                FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)

            assertThat(state).isEqualTo(disabledAtDefaultLevel)

            underTest.setLevel(-1) // exception thrown

            assertThat(state).isEqualTo(disabledAtDefaultLevel)
        }

    @Test(expected = IllegalArgumentException::class)
    fun setLevelAboveMax_throwsException() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            val disabledAtDefaultLevel =
                FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
            assertThat(state).isEqualTo(disabledAtDefaultLevel)

            underTest.setLevel(DEFAULT_MAX_LEVEL + 1)

            assertThat(state).isEqualTo(disabledAtDefaultLevel)
        }

    @Test
    fun enableThenDisable_stateUpdates() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(true)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(false)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun enableSetLevelDisable_stateUpdatesReturnsToDisabledAndDefaultLevel() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            startFlashlightRepository(true)

            val state by collectLastValue(underTest.state)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(true)
            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setLevel(DEFAULT_MAX_LEVEL)
            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_MAX_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(false)
            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun start_registersTorchCallback() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            startFlashlightRepository(true)
            runCurrent()
            verify(cameraManager).registerTorchCallback(any(), any<TorchCallback>())
        }

    @Test
    fun initOnlyNotStart_torchCallbackNotRegistered() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            runCurrent()
            verify(cameraManager, never()).registerTorchCallback(any(), any<TorchCallback>())
        }

    @Test
    fun startButNotSubscribe_torchCallbackNotRegistered() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            startFlashlightRepository(true)

            verify(cameraManager, never()).registerTorchCallback(any(), any<TorchCallback>())
        }

    @Test
    fun enabledTwice_onlyOneBackendCall() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            startFlashlightRepository(true)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setEnabled(true)
            runCurrent()
            underTest.setEnabled(true)

            verify(cameraManager, times(1)).setTorchMode(anyString(), anyBoolean())
        }

    @Test
    fun setLevelTheSameTwice_onlyOneBackendCall() =
        kosmos.runTest {
            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)

            val state by collectLastValue(underTest.state)

            startFlashlightRepository(true)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setLevel(BASE_TORCH_LEVEL)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, BASE_TORCH_LEVEL, DEFAULT_MAX_LEVEL)
                )

            underTest.setLevel(BASE_TORCH_LEVEL)

            verify(cameraManager, times(1)).turnOnTorchWithStrengthLevel(anyString(), anyInt())
        }

    @Test
    fun initiallyFailLoadingThenFlashlightBecomesAvailable_afterCooldown_userEnables_connectsAndEnables() =
        kosmos.runTest {
            injectCameraCharacteristics(false, CameraCharacteristics.LENS_FACING_BACK)

            val state by collectLastValue(underTest.state)

            startFlashlightRepository(true)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            fakeSystemClock.advanceTime(RECONNECT_COOLDOWN.inWholeMilliseconds + 1000)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)

            underTest.setEnabled(true)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun initiallyFailLoadingThenFlashlightBecomesAvailable_afterCooldown_userSetsLevel_connectsAndSetLevel() =
        kosmos.runTest {
            injectCameraCharacteristics(false, CameraCharacteristics.LENS_FACING_BACK)

            val state by collectLastValue(underTest.state)

            startFlashlightRepository(true)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            fakeSystemClock.advanceTime(RECONNECT_COOLDOWN.inWholeMilliseconds + 1000)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)

            underTest.setLevel(BASE_TORCH_LEVEL)

            assertThat(state)
                .isEqualTo(
                    FlashlightModel.Available.Level(true, BASE_TORCH_LEVEL, DEFAULT_MAX_LEVEL)
                )
        }

    @Test
    fun initiallyFailLoadingThenFlashlightBecomesAvailable_beforeCooldown_userSetsLevel_doesNotConnect() =
        kosmos.runTest {
            injectCameraCharacteristics(false, CameraCharacteristics.LENS_FACING_BACK)

            val state by collectLastValue(underTest.state)

            startFlashlightRepository(true)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)

            injectCameraCharacteristics(true, CameraCharacteristics.LENS_FACING_BACK)
            fakeSystemClock.advanceTime(RECONNECT_COOLDOWN.inWholeMilliseconds - 1000)

            underTest.setLevel(BASE_TORCH_LEVEL)

            assertThat(state).isEqualTo(FlashlightModel.Unavailable.Temporarily.NotFound)
        }

    companion object {
        private const val BASE_TORCH_LEVEL = 1
        private const val DEFAULT_DEFAULT_LEVEL = 21
        private const val DEFAULT_MAX_LEVEL = 45
        private const val DEFAULT_ID = "ID"
        private val RECONNECT_COOLDOWN = 30.seconds
    }
}
+92 −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.flashlight.domain.interactor

import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flashlight.data.repository.flashlightRepository
import com.android.systemui.flashlight.data.repository.startFlashlightRepository
import com.android.systemui.flashlight.shared.model.FlashlightModel
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@EnableFlags(com.android.systemui.Flags.FLAG_FLASHLIGHT_STRENGTH)
@RunWith(AndroidJUnit4::class)
class FlashlightInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val underTest = kosmos.flashlightInteractor

    @Before
    fun setUp() {
        kosmos.startFlashlightRepository(true)
    }

    @Test
    fun enableDisable_StateMatches() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)
            val expectedStateDisabled =
                FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
            assertThat(state).isEqualTo(expectedStateDisabled)

            underTest.setEnabled(true)

            val expectedStateEnabled =
                FlashlightModel.Available.Level(true, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
            assertThat(state).isEqualTo(expectedStateEnabled)

            underTest.setEnabled(false)
            assertThat(state).isEqualTo(expectedStateDisabled)
        }

    @Test
    fun setLevel_interactorStateMatches() =
        kosmos.runTest {
            val state by collectLastValue(underTest.state)
            val expectedStateDefault =
                FlashlightModel.Available.Level(false, DEFAULT_DEFAULT_LEVEL, DEFAULT_MAX_LEVEL)
            assertThat(state).isEqualTo(expectedStateDefault)

            underTest.setLevel(BASE_TORCH_LEVEL)

            val expectedState =
                FlashlightModel.Available.Level(true, BASE_TORCH_LEVEL, DEFAULT_MAX_LEVEL)
            assertThat(state).isEqualTo(expectedState)
        }

    @Test
    fun deviceSupportsFlashlight_matchesRepository() =
        kosmos.runTest {
            val hasFlashlightFeature = flashlightRepository.deviceSupportsFlashlight

            assertThat(underTest.deviceSupportsFlashlight).isEqualTo(hasFlashlightFeature)
        }

    companion object {
        private const val BASE_TORCH_LEVEL = 1
        private const val DEFAULT_DEFAULT_LEVEL = 21
        private const val DEFAULT_MAX_LEVEL = 45
    }
}
+59 −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.flashlight

import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flashlight.data.repository.FlashlightRepository
import com.android.systemui.flashlight.data.repository.FlashlightRepositoryImpl
import com.android.systemui.flashlight.flags.FlashlightStrength
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.dagger.FlashlightLog
import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap

/** Module for repositories that provide data regarding flashlight state. */
@Module
interface FlashlightModule {
    @Binds fun bindsFlashlightRepoImpl(impl: FlashlightRepositoryImpl): FlashlightRepository

    companion object {
        @Provides
        @IntoMap
        @ClassKey(FlashlightRepositoryImpl::class)
        fun binds(flashlightRepositoryImpl: Lazy<FlashlightRepositoryImpl>): CoreStartable {
            return if (FlashlightStrength.isEnabled) {
                flashlightRepositoryImpl.get()
            } else {
                CoreStartable.NOP
            }
        }

        /** Provides a logging buffer for logs related to Flashlight. */
        @Provides
        @SysUISingleton
        @FlashlightLog
        fun provideFlashlightLogBuffer(factory: LogBufferFactory): LogBuffer {
            return factory.create("FlashlightLog", 100, true)
        }
    }
}
+387 −0

File added.

Preview size limit exceeded, changes collapsed.

+38 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading