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