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