1 /*
2  * Copyright 2024 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.internal
18 
19 import android.os.Build
20 import android.util.Log
21 import androidx.annotation.GuardedBy
22 import androidx.camera.core.impl.Quirks
23 import androidx.camera.core.impl.utils.executor.CameraXExecutors
24 import androidx.camera.core.impl.utils.futures.Futures
25 import com.google.common.util.concurrent.ListenableFuture
26 import com.google.common.util.concurrent.MoreExecutors
27 import java.util.concurrent.CountDownLatch
28 import java.util.concurrent.TimeUnit
29 
30 private const val TAG = "FakeFocusMeteringControl"
31 
32 /** A fake implementations of {@link ScreenFlash} for testing purpose. */
33 internal class FakeFocusMeteringControl(
34     fakeCamera2CameraControlImpl: ScreenFlashTaskTest.FakeCamera2CameraControlImpl,
35     quirks: Quirks
36 ) :
37     FocusMeteringControl(
38         fakeCamera2CameraControlImpl,
39         CameraXExecutors.myLooperExecutor(),
40         MoreExecutors.directExecutor(),
41         quirks,
42     ) {
43     // This class needs to be in androidx.camera.camera2.internal path since FocusMeteringControl
44     // constructor is package-private
45 
46     // TODO: Fake out all the methods so real implementation is not called in test
47 
48     private val lock = Any()
49 
50     @GuardedBy("mLock") var externalFlashAeModeEnabled = false
51     private var enableExternalFlashAeModeLatch: CountDownLatch? = null
52 
53     @GuardedBy("mLock") var triggerAePrecaptureCount = 0
54     @GuardedBy("mLock") private var triggerAePrecaptureLatch: CountDownLatch? = null
55 
56     @GuardedBy("mLock") var cancelAfAeTriggerCount = 0
57     @GuardedBy("mLock") private var cancelAfAeTriggerLatch: CountDownLatch? = null
58 
triggerAePrecapturenull59     override fun triggerAePrecapture(): ListenableFuture<Void> {
60         synchronized(lock) {
61             triggerAePrecaptureCount++
62             triggerAePrecaptureLatch?.countDown()
63         }
64 
65         Log.d(TAG, "triggerAePrecaptureCount = $triggerAePrecaptureCount")
66 
67         return Futures.immediateFuture(null)
68     }
69 
70     /** Waits for a new [triggerAePrecapture] API invocation. */
awaitTriggerAePrecapturenull71     fun awaitTriggerAePrecapture(timeoutMillis: Long = 3000) {
72         synchronized(lock) { triggerAePrecaptureLatch = CountDownLatch(1) }
73         triggerAePrecaptureLatch?.await(timeoutMillis, TimeUnit.MILLISECONDS)
74     }
75 
cancelAfAeTriggernull76     override fun cancelAfAeTrigger(cancelAfTrigger: Boolean, cancelAePrecaptureTrigger: Boolean) {
77         synchronized(lock) {
78             cancelAfAeTriggerCount++
79             cancelAfAeTriggerLatch?.countDown()
80         }
81     }
82 
83     /** Waits for a new [cancelAfAeTrigger] API invocation. */
awaitCancelAfAeTriggernull84     fun awaitCancelAfAeTrigger(timeoutMillis: Long = 3000) {
85         synchronized(lock) { cancelAfAeTriggerLatch = CountDownLatch(1) }
86         cancelAfAeTriggerLatch?.await(timeoutMillis, TimeUnit.MILLISECONDS)
87     }
88 
enableExternalFlashAeModenull89     override fun enableExternalFlashAeMode(enable: Boolean): ListenableFuture<Void> {
90         synchronized(lock) {
91             if (Build.VERSION.SDK_INT >= 28) {
92                 externalFlashAeModeEnabled = enable
93             }
94             enableExternalFlashAeModeLatch?.countDown()
95         }
96 
97         Log.d(TAG, "externalFlashAeModeEnabled = $externalFlashAeModeEnabled")
98 
99         return Futures.immediateFuture(null)
100     }
101 
102     /** Waits for a new [enableExternalFlashAeMode] API invocation. */
awaitEnableExternalFlashAeModenull103     fun awaitEnableExternalFlashAeMode(timeoutMillis: Long = 3000) {
104         synchronized(lock) { enableExternalFlashAeModeLatch = CountDownLatch(1) }
105         enableExternalFlashAeModeLatch?.await(timeoutMillis, TimeUnit.MILLISECONDS)
106     }
107 }
108