1 /*
2  * Copyright 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 androidx.camera.camera2.internal.compat.workaround;
18 
19 import android.hardware.camera2.CaptureRequest;
20 
21 import androidx.annotation.OptIn;
22 import androidx.camera.camera2.impl.Camera2ImplConfig;
23 import androidx.camera.camera2.internal.compat.quirk.DeviceQuirks;
24 import androidx.camera.camera2.internal.compat.quirk.TorchIsClosedAfterImageCapturingQuirk;
25 import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
26 import androidx.camera.core.impl.CaptureConfig;
27 import androidx.camera.core.impl.DeferrableSurface;
28 
29 import org.jspecify.annotations.NonNull;
30 
31 import java.util.List;
32 
33 /**
34  * This is a workaround for b/228272227 where the Torch is unexpectedly closed after a single
35  * capturing.
36  */
37 public class TorchStateReset {
38     private final boolean mIsImageCaptureTorchIsClosedQuirkEnabled;
39 
TorchStateReset()40     public TorchStateReset() {
41         mIsImageCaptureTorchIsClosedQuirkEnabled =
42                 DeviceQuirks.get(TorchIsClosedAfterImageCapturingQuirk.class) != null;
43     }
44 
45     /**
46      * The method indicates if the Torch would be unexpectedly closed after the capture. Return
47      * true means the Torch will be unexpectedly closed, and it requires turning on the Torch
48      * again after the capturing.
49      */
isTorchResetRequired(@onNull List<CaptureRequest> captureRequestList, boolean isSingleCapture)50     public boolean isTorchResetRequired(@NonNull List<CaptureRequest> captureRequestList,
51             boolean isSingleCapture) {
52         if (mIsImageCaptureTorchIsClosedQuirkEnabled && isSingleCapture) {
53             for (CaptureRequest captureRequest: captureRequestList) {
54                 Integer flashMode = captureRequest.get(CaptureRequest.FLASH_MODE);
55                 if (flashMode != null && flashMode == CaptureRequest.FLASH_MODE_TORCH) {
56                     return true;
57                 }
58             }
59         }
60 
61         return false;
62     }
63 
64     /**
65      * Create a single request from the {@link CaptureConfig}. And turns off the Torch by
66      * overriding the FLASH_MODE to FLASH_MODE_OFF.
67      *
68      * @param repeatingConfig the CaptureConfig that is used for the repeating request of the
69      *                        current session.
70      * @return a CaptureConfig that can be used in a single request to reset the FLASH_MODE to
71      * FLASH_MODE_OFF. The returned CaptureConfig will not set the CameraCaptureCallbacks and
72      * Tags since it is only used for Torch reset.
73      */
74     @OptIn(markerClass = ExperimentalCamera2Interop.class)
createTorchResetRequest(@onNull CaptureConfig repeatingConfig)75     public @NonNull CaptureConfig createTorchResetRequest(@NonNull CaptureConfig repeatingConfig) {
76         CaptureConfig.Builder captureConfigBuilder = new CaptureConfig.Builder();
77         captureConfigBuilder.setTemplateType(repeatingConfig.getTemplateType());
78 
79         // The single request only applies to the repeating surfaces.
80         for (DeferrableSurface deferrableSurface : repeatingConfig.getSurfaces()) {
81             captureConfigBuilder.addSurface(deferrableSurface);
82         }
83 
84         captureConfigBuilder.addImplementationOptions(repeatingConfig.getImplementationOptions());
85         Camera2ImplConfig.Builder builder = new Camera2ImplConfig.Builder();
86         builder.setCaptureRequestOption(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
87 
88         captureConfigBuilder.addImplementationOptions(builder.build());
89 
90         return captureConfigBuilder.build();
91     }
92 }
93