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.CaptureRequest
20 import android.hardware.camera2.params.MeteringRectangle
21 import androidx.camera.camera2.pipe.AeMode
22 import androidx.camera.camera2.pipe.CameraGraph
23 import androidx.camera.camera2.pipe.CameraStream
24 import androidx.camera.camera2.pipe.Lock3ABehavior
25 import androidx.camera.camera2.pipe.Request
26 import androidx.camera.camera2.pipe.RequestTemplate
27 import androidx.camera.camera2.pipe.Result3A
28 import androidx.camera.camera2.pipe.StreamId
29 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
30 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
31 import androidx.camera.camera2.pipe.integration.config.UseCaseCameraComponent
32 import androidx.camera.camera2.pipe.integration.config.UseCaseCameraConfig
33 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
34 import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
35 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
36 import androidx.camera.core.ImageCapture
37 import androidx.camera.core.imagecapture.CameraCapturePipeline
38 import androidx.camera.core.impl.CaptureConfig
39 import androidx.camera.core.impl.Config
40 import androidx.camera.core.impl.DeferrableSurface
41 import androidx.camera.core.impl.SessionConfig
42 import androidx.camera.testing.impl.FakeCameraCapturePipeline
43 import java.util.concurrent.TimeUnit.MILLISECONDS
44 import java.util.concurrent.TimeUnit.NANOSECONDS
45 import kotlinx.coroutines.CompletableDeferred
46 import kotlinx.coroutines.CoroutineScope
47 import kotlinx.coroutines.Deferred
48 import kotlinx.coroutines.Job
49 import kotlinx.coroutines.SupervisorJob
50 import kotlinx.coroutines.launch
51 import kotlinx.coroutines.withTimeoutOrNull
52 
53 class FakeUseCaseCameraComponentBuilder : UseCaseCameraComponent.Builder {
54     var buildInvocationCount = 0
55     private var sessionConfigAdapter = SessionConfigAdapter(emptyList())
56     private var cameraGraph = FakeCameraGraph()
57     private var streamConfigMap = mutableMapOf<CameraStream.Config, DeferrableSurface>()
58 
59     private var config: UseCaseCameraConfig =
60         UseCaseCameraConfig(
61             emptyList(),
62             sessionConfigAdapter,
63             CameraStateAdapter(),
64             cameraGraph,
65             streamConfigMap,
66             sessionProcessorManager = null
67         )
68 
69     override fun config(config: UseCaseCameraConfig): UseCaseCameraComponent.Builder {
70         this.config = config
71         return this
72     }
73 
74     override fun build(): UseCaseCameraComponent {
75         buildInvocationCount++
76         return FakeUseCaseCameraComponent()
77     }
78 }
79 
80 class FakeUseCaseCameraComponent() : UseCaseCameraComponent {
81     private val fakeUseCaseCamera = FakeUseCaseCamera()
82     private val cameraGraph = FakeCameraGraph()
83     private val cameraStateAdapter = CameraStateAdapter()
84 
getUseCaseCameranull85     override fun getUseCaseCamera(): UseCaseCamera {
86         return fakeUseCaseCamera
87     }
88 
getUseCaseGraphConfignull89     override fun getUseCaseGraphConfig(): UseCaseGraphConfig {
90         // TODO: Implement this properly once we need to use it with SessionProcessor enabled.
91         return UseCaseGraphConfig(cameraGraph, emptyMap(), cameraStateAdapter)
92     }
93 }
94 
95 // TODO: Further implement the methods in this class as needed
96 open class FakeUseCaseCameraRequestControl(
97     private val scope: CoroutineScope = CoroutineScope(SupervisorJob()),
98 ) : UseCaseCameraRequestControl {
99     val addParameterCalls = mutableListOf<Map<CaptureRequest.Key<*>, Any>>()
100     var addParameterResult = CompletableDeferred(Unit)
101     var setConfigCalls = mutableListOf<RequestParameters>()
102     var setConfigResult = CompletableDeferred(Unit)
103     var setTorchResult = CompletableDeferred(Result3A(status = Result3A.Status.OK))
104 
105     // TODO - Implement thread-safety in the functions annotated with @AnyThread in
106     //  UseCaseCameraRequestControl
107 
setParametersAsyncnull108     override fun setParametersAsync(
109         type: UseCaseCameraRequestControl.Type,
110         values: Map<CaptureRequest.Key<*>, Any>,
111         optionPriority: Config.OptionPriority,
112     ): Deferred<Unit> {
113         addParameterCalls.add(values)
114         return addParameterResult
115     }
116 
setConfigAsyncnull117     override fun setConfigAsync(
118         type: UseCaseCameraRequestControl.Type,
119         config: Config?,
120         tags: Map<String, Any>,
121         streams: Set<StreamId>?,
122         template: RequestTemplate?,
123         listeners: Set<Request.Listener>,
124         sessionConfig: SessionConfig?,
125     ): Deferred<Unit> {
126         setConfigCalls.add(RequestParameters(type, config, tags))
127         return CompletableDeferred(Unit)
128     }
129 
setTorchOnAsyncnull130     override fun setTorchOnAsync(): Deferred<Result3A> {
131         return setTorchResult
132     }
133 
setTorchOffAsyncnull134     override fun setTorchOffAsync(aeMode: AeMode): Deferred<Result3A> {
135         return setTorchResult
136     }
137 
138     var aeRegions: List<MeteringRectangle>? = null
139     var afRegions: List<MeteringRectangle>? = null
140     var awbRegions: List<MeteringRectangle>? = null
141 
142     val focusMeteringCalls = mutableListOf<FocusMeteringParams>()
143     var focusMeteringResult = CompletableDeferred(Result3A(status = Result3A.Status.OK))
144     var cancelFocusMeteringCallCount = 0
145     var cancelFocusMeteringResult = CompletableDeferred(Result3A(status = Result3A.Status.OK))
146 
147     var focusAutoCompletesAfterTimeout = true
148 
startFocusAndMeteringAsyncnull149     override fun startFocusAndMeteringAsync(
150         aeRegions: List<MeteringRectangle>?,
151         afRegions: List<MeteringRectangle>?,
152         awbRegions: List<MeteringRectangle>?,
153         aeLockBehavior: Lock3ABehavior?,
154         afLockBehavior: Lock3ABehavior?,
155         awbLockBehavior: Lock3ABehavior?,
156         afTriggerStartAeMode: AeMode?,
157         timeLimitNs: Long,
158     ): Deferred<Result3A> {
159         this.aeRegions = aeRegions
160         this.afRegions = afRegions
161         this.awbRegions = awbRegions
162 
163         focusMeteringCalls.add(
164             FocusMeteringParams(
165                 aeRegions,
166                 afRegions,
167                 awbRegions,
168                 aeLockBehavior,
169                 afLockBehavior,
170                 awbLockBehavior,
171                 afTriggerStartAeMode,
172                 timeLimitNs
173             )
174         )
175 
176         if (focusAutoCompletesAfterTimeout) {
177             scope.launch {
178                 withTimeoutOrNull(MILLISECONDS.convert(timeLimitNs, NANOSECONDS)) {
179                         focusMeteringResult.await()
180                     }
181                     .let { result3A ->
182                         if (result3A == null) {
183                             focusMeteringResult.complete(
184                                 Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
185                             )
186                         }
187                     }
188             }
189         }
190 
191         return focusMeteringResult
192     }
193 
cancelFocusAndMeteringAsyncnull194     override fun cancelFocusAndMeteringAsync(): Deferred<Result3A> {
195         cancelFocusMeteringCallCount++
196         return cancelFocusMeteringResult
197     }
198 
issueSingleCaptureAsyncnull199     override fun issueSingleCaptureAsync(
200         captureSequence: List<CaptureConfig>,
201         @ImageCapture.CaptureMode captureMode: Int,
202         @ImageCapture.FlashType flashType: Int,
203         @ImageCapture.FlashMode flashMode: Int,
204     ): List<Deferred<Void?>> {
205         return captureSequence.map { CompletableDeferred<Void?>(null).apply { complete(null) } }
206     }
207 
update3aRegionsnull208     override fun update3aRegions(
209         aeRegions: List<MeteringRectangle>?,
210         afRegions: List<MeteringRectangle>?,
211         awbRegions: List<MeteringRectangle>?
212     ): Deferred<Result3A> {
213         this.aeRegions = aeRegions
214         this.afRegions = afRegions
215         this.awbRegions = awbRegions
216         return CompletableDeferred(Result3A(status = Result3A.Status.OK))
217     }
218 
awaitSurfaceSetupnull219     override suspend fun awaitSurfaceSetup(): Boolean {
220         return true
221     }
222 
closenull223     override fun close() {}
224 
225     data class FocusMeteringParams(
226         val aeRegions: List<MeteringRectangle>? = null,
227         val afRegions: List<MeteringRectangle>? = null,
228         val awbRegions: List<MeteringRectangle>? = null,
229         val aeLockBehavior: Lock3ABehavior? = null,
230         val afLockBehavior: Lock3ABehavior? = null,
231         val awbLockBehavior: Lock3ABehavior? = null,
232         val afTriggerStartAeMode: AeMode? = null,
233         val timeLimitNs: Long = CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS,
234     )
235 
236     data class RequestParameters(
237         val type: UseCaseCameraRequestControl.Type,
238         val config: Config?,
239         val tags: Map<String, Any> = emptyMap(),
240     )
241 }
242 
243 // TODO: Further implement the methods in this class as needed
244 class FakeUseCaseCamera(
245     override var requestControl: UseCaseCameraRequestControl = FakeUseCaseCameraRequestControl(),
246 ) : UseCaseCamera {
getCameraCapturePipelinenull247     override suspend fun getCameraCapturePipeline(
248         captureMode: Int,
249         flashMode: Int,
250         flashType: Int
251     ): CameraCapturePipeline = FakeCameraCapturePipeline()
252 
253     override fun close(): Job {
254         return CompletableDeferred(Unit)
255     }
256 }
257