1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.policy
18 
19 import android.content.pm.PackageManager
20 import android.hardware.camera2.CameraCharacteristics
21 import android.hardware.camera2.CameraManager
22 import android.hardware.camera2.impl.CameraMetadataNative
23 import android.test.suitebuilder.annotation.SmallTest
24 import android.testing.AndroidTestingRunner
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.broadcast.BroadcastSender
27 import com.android.systemui.dump.DumpManager
28 import com.android.systemui.util.concurrency.FakeExecutor
29 import com.android.systemui.util.settings.FakeSettings
30 import com.android.systemui.util.time.FakeSystemClock
31 import java.util.concurrent.Executor
32 import org.junit.Before
33 import org.junit.Test
34 import org.junit.runner.RunWith
35 import org.mockito.Mock
36 import org.mockito.Mockito.any
37 import org.mockito.Mockito.clearInvocations
38 import org.mockito.Mockito.eq
39 import org.mockito.Mockito.never
40 import org.mockito.Mockito.verify
41 import org.mockito.Mockito.verifyNoMoreInteractions
42 import org.mockito.Mockito.verifyZeroInteractions
43 import org.mockito.Mockito.`when`
44 import org.mockito.MockitoAnnotations
45 
46 @SmallTest
47 @RunWith(AndroidTestingRunner::class)
48 class FlashlightControllerImplTest : SysuiTestCase() {
49 
50     @Mock
51     private lateinit var dumpManager: DumpManager
52 
53     @Mock
54     private lateinit var cameraManager: CameraManager
55 
56     @Mock
57     private lateinit var broadcastSender: BroadcastSender
58 
59     @Mock
60     private lateinit var packageManager: PackageManager
61 
62     private lateinit var fakeSettings: FakeSettings
63     private lateinit var fakeSystemClock: FakeSystemClock
64     private lateinit var backgroundExecutor: FakeExecutor
65     private lateinit var controller: FlashlightControllerImpl
66 
67     @Before
68     fun setup() {
69         MockitoAnnotations.initMocks(this)
70 
71         fakeSystemClock = FakeSystemClock()
72         backgroundExecutor = FakeExecutor(fakeSystemClock)
73         fakeSettings = FakeSettings()
74 
75         `when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH))
76                 .thenReturn(true)
77 
78         controller = FlashlightControllerImpl(
79                 dumpManager,
80                 cameraManager,
81                 backgroundExecutor,
82                 fakeSettings,
83                 broadcastSender,
84                 packageManager
85         )
86     }
87 
88     @Test
89     fun testNoCameraManagerInteractionDirectlyOnConstructor() {
90         verifyZeroInteractions(cameraManager)
91     }
92 
93     @Test
94     fun testCameraManagerInitAfterConstructionOnExecutor() {
95         injectCamera()
96         backgroundExecutor.runAllReady()
97 
98         verify(cameraManager).registerTorchCallback(eq(backgroundExecutor), any())
99     }
100 
101     @Test
102     fun testNoCallbackIfNoFlashCamera() {
103         injectCamera(flash = false)
104         backgroundExecutor.runAllReady()
105 
106         verify(cameraManager, never()).registerTorchCallback(any<Executor>(), any())
107     }
108 
109     @Test
110     fun testNoCallbackIfNoBackCamera() {
111         injectCamera(facing = CameraCharacteristics.LENS_FACING_FRONT)
112         backgroundExecutor.runAllReady()
113 
114         verify(cameraManager, never()).registerTorchCallback(any<Executor>(), any())
115     }
116 
117     @Test
118     fun testSetFlashlightInBackgroundExecutor() {
119         val id = injectCamera()
120         backgroundExecutor.runAllReady()
121 
122         clearInvocations(cameraManager)
123         val enable = !controller.isEnabled
124         controller.setFlashlight(enable)
125         verifyNoMoreInteractions(cameraManager)
126 
127         backgroundExecutor.runAllReady()
128         verify(cameraManager).setTorchMode(id, enable)
129     }
130 
131     private fun injectCamera(
132         flash: Boolean = true,
133         facing: Int = CameraCharacteristics.LENS_FACING_BACK
134     ): String {
135         val cameraID = "ID"
136         val camera = CameraCharacteristics(CameraMetadataNative().apply {
137             set(CameraCharacteristics.FLASH_INFO_AVAILABLE, flash)
138             set(CameraCharacteristics.LENS_FACING, facing)
139         })
140         `when`(cameraManager.cameraIdList).thenReturn(arrayOf(cameraID))
141         `when`(cameraManager.getCameraCharacteristics(cameraID)).thenReturn(camera)
142         return cameraID
143     }
144 }
145