1 /* <lambda>null2 * Copyright 2021 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 androidx.camera.camera2.pipe.integration.testing 18 19 import android.hardware.camera2.params.MeteringRectangle 20 import androidx.camera.camera2.pipe.AeMode 21 import androidx.camera.camera2.pipe.AfMode 22 import androidx.camera.camera2.pipe.AwbMode 23 import androidx.camera.camera2.pipe.CameraGraph 24 import androidx.camera.camera2.pipe.Frame 25 import androidx.camera.camera2.pipe.FrameCapture 26 import androidx.camera.camera2.pipe.FrameMetadata 27 import androidx.camera.camera2.pipe.FrameNumber 28 import androidx.camera.camera2.pipe.Lock3ABehavior 29 import androidx.camera.camera2.pipe.OutputStatus 30 import androidx.camera.camera2.pipe.Request 31 import androidx.camera.camera2.pipe.Result3A 32 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession.RequestStatus.ABORTED 33 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession.RequestStatus.FAILED 34 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession.RequestStatus.TOTAL_CAPTURE_DONE 35 import androidx.camera.camera2.pipe.testing.FakeFrameInfo 36 import androidx.camera.camera2.pipe.testing.FakeRequestFailure 37 import androidx.camera.camera2.pipe.testing.FakeRequestMetadata 38 import java.util.concurrent.Semaphore 39 import kotlinx.atomicfu.atomic 40 import kotlinx.coroutines.CompletableDeferred 41 import kotlinx.coroutines.Deferred 42 import kotlinx.coroutines.ExperimentalCoroutinesApi 43 import kotlinx.coroutines.runBlocking 44 45 open class FakeCameraGraphSession : CameraGraph.Session { 46 47 val repeatingRequests = mutableListOf<Request>() 48 var repeatingRequestSemaphore = Semaphore(0) 49 var stopRepeatingSemaphore = Semaphore(0) 50 51 enum class RequestStatus { 52 TOTAL_CAPTURE_DONE, 53 FAILED, 54 ABORTED 55 } 56 57 var startRepeatingSignal = CompletableDeferred(TOTAL_CAPTURE_DONE) // already completed 58 59 val submittedRequests = mutableListOf<Request>() 60 61 override fun abort() { 62 // No-op 63 } 64 65 override fun close() { 66 // No-op 67 } 68 69 override suspend fun lock3A( 70 aeMode: AeMode?, 71 afMode: AfMode?, 72 awbMode: AwbMode?, 73 aeRegions: List<MeteringRectangle>?, 74 afRegions: List<MeteringRectangle>?, 75 awbRegions: List<MeteringRectangle>?, 76 aeLockBehavior: Lock3ABehavior?, 77 afLockBehavior: Lock3ABehavior?, 78 awbLockBehavior: Lock3ABehavior?, 79 afTriggerStartAeMode: AeMode?, 80 convergedCondition: ((FrameMetadata) -> Boolean)?, 81 lockedCondition: ((FrameMetadata) -> Boolean)?, 82 frameLimit: Int, 83 convergedTimeLimitNs: Long, 84 lockedTimeLimitNs: Long 85 ): Deferred<Result3A> { 86 throw NotImplementedError("Not used in testing") 87 } 88 89 override suspend fun lock3AForCapture( 90 lockedCondition: ((FrameMetadata) -> Boolean)?, 91 frameLimit: Int, 92 timeLimitNs: Long 93 ): Deferred<Result3A> { 94 throw NotImplementedError("Not used in testing") 95 } 96 97 override suspend fun lock3AForCapture( 98 triggerAf: Boolean, 99 waitForAwb: Boolean, 100 frameLimit: Int, 101 timeLimitNs: Long 102 ): Deferred<Result3A> { 103 throw NotImplementedError("Not used in testing") 104 } 105 106 override fun setTorchOn(): Deferred<Result3A> { 107 throw NotImplementedError("Not used in testing") 108 } 109 110 override fun setTorchOff(aeMode: AeMode?): Deferred<Result3A> { 111 throw NotImplementedError("Not used in testing") 112 } 113 114 override fun startRepeating(request: Request) { 115 repeatingRequests.add(request) 116 repeatingRequestSemaphore.release() 117 118 startRepeatingSignal.invokeOnCompletion { 119 // completes immediately if startRepeatingListenerInvoker is the initial one 120 runBlocking { 121 // the real GraphSession processes only the last successful repeating request 122 repeatingRequests.notifyLastRequestListeners(request, startRepeatingSignal.await()) 123 } 124 } 125 } 126 127 override fun stopRepeating() { 128 stopRepeatingSemaphore.release() 129 } 130 131 override fun submit(request: Request) { 132 submittedRequests.add(request) 133 } 134 135 override fun submit(requests: List<Request>) { 136 submittedRequests.addAll(requests) 137 } 138 139 override fun capture(request: Request): FrameCapture { 140 val capture = FakeFrameCapture(request) 141 submit(request) 142 return capture 143 } 144 145 override fun capture(requests: List<Request>): List<FrameCapture> { 146 val captures = requests.map { FakeFrameCapture(it) } 147 submit(requests) 148 return captures 149 } 150 151 override suspend fun submit3A( 152 aeMode: AeMode?, 153 afMode: AfMode?, 154 awbMode: AwbMode?, 155 aeRegions: List<MeteringRectangle>?, 156 afRegions: List<MeteringRectangle>?, 157 awbRegions: List<MeteringRectangle>? 158 ): Deferred<Result3A> { 159 throw NotImplementedError("Not used in testing") 160 } 161 162 override suspend fun unlock3A( 163 ae: Boolean?, 164 af: Boolean?, 165 awb: Boolean?, 166 unlockedCondition: ((FrameMetadata) -> Boolean)?, 167 frameLimit: Int, 168 timeLimitNs: Long 169 ): Deferred<Result3A> { 170 throw NotImplementedError("Not used in testing") 171 } 172 173 override suspend fun unlock3APostCapture(cancelAf: Boolean): Deferred<Result3A> { 174 throw NotImplementedError("Not used in testing") 175 } 176 177 override fun update3A( 178 aeMode: AeMode?, 179 afMode: AfMode?, 180 awbMode: AwbMode?, 181 aeRegions: List<MeteringRectangle>?, 182 afRegions: List<MeteringRectangle>?, 183 awbRegions: List<MeteringRectangle>? 184 ): Deferred<Result3A> { 185 return CompletableDeferred(Result3A(Result3A.Status.OK)) 186 } 187 188 private fun MutableList<Request>.notifyLastRequestListeners( 189 request: Request, 190 status: RequestStatus 191 ) { 192 val requestMetadata = FakeRequestMetadata(request = request) 193 last().listeners.forEach { listener -> 194 when (status) { 195 TOTAL_CAPTURE_DONE -> 196 listener.onTotalCaptureResult(requestMetadata, FrameNumber(0), FakeFrameInfo()) 197 FAILED -> 198 listener.onFailed( 199 requestMetadata, 200 FrameNumber(0), 201 FakeRequestFailure(requestMetadata, FrameNumber(0)) 202 ) 203 ABORTED -> listener.onRequestSequenceAborted(requestMetadata) 204 } 205 } 206 } 207 208 @OptIn(ExperimentalCoroutinesApi::class) 209 private class FakeFrameCapture(override val request: Request) : FrameCapture { 210 private val result = CompletableDeferred<Frame?>() 211 private val closed = atomic(false) 212 private val listeners = mutableListOf<Frame.Listener>() 213 override val status: OutputStatus 214 get() { 215 if (closed.value || result.isCancelled) return OutputStatus.UNAVAILABLE 216 if (!result.isCompleted) return OutputStatus.PENDING 217 return OutputStatus.AVAILABLE 218 } 219 220 override suspend fun awaitFrame(): Frame? = result.await() 221 222 override fun getFrame(): Frame? { 223 if (result.isCompleted && !result.isCancelled) { 224 return result.getCompleted() 225 } 226 return null 227 } 228 229 override fun addListener(listener: Frame.Listener) { 230 listeners.add(listener) 231 } 232 233 override fun close() { 234 if (closed.compareAndSet(expect = false, update = true)) { 235 result.cancel() 236 } 237 } 238 } 239 } 240