1 /* 2 * Copyright 2023 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.core.impl; 18 19 import android.util.Range; 20 21 import androidx.camera.core.FocusMeteringAction; 22 import androidx.camera.core.FocusMeteringResult; 23 import androidx.camera.core.impl.utils.SessionProcessorUtil; 24 import androidx.camera.core.impl.utils.futures.Futures; 25 26 import com.google.common.util.concurrent.ListenableFuture; 27 28 import org.jspecify.annotations.NonNull; 29 import org.jspecify.annotations.Nullable; 30 31 /** 32 * A {@link CameraControlInternal} whose capabilities can be restricted by the associated 33 * {@link SessionProcessor}. Only the camera operations that can be retrieved from 34 * {@link SessionProcessor#getSupportedCameraOperations()} can be supported by the 35 * AdapterCameraControl. 36 */ 37 public class AdapterCameraControl extends ForwardingCameraControl { 38 private final CameraControlInternal mCameraControl; 39 private final @Nullable SessionProcessor mSessionProcessor; 40 41 /** 42 * Creates the restricted version of the given {@link CameraControlInternal}. 43 */ AdapterCameraControl(@onNull CameraControlInternal cameraControl, @Nullable SessionProcessor sessionProcessor)44 public AdapterCameraControl(@NonNull CameraControlInternal cameraControl, 45 @Nullable SessionProcessor sessionProcessor) { 46 super(cameraControl); 47 mCameraControl = cameraControl; 48 mSessionProcessor = sessionProcessor; 49 } 50 51 /** 52 * Returns implementation instance. 53 */ 54 @Override getImplementation()55 public @NonNull CameraControlInternal getImplementation() { 56 return mCameraControl; 57 } 58 59 /** 60 * Returns the {@link SessionProcessor} associated with the AdapterCameraControl. 61 */ getSessionProcessor()62 public @Nullable SessionProcessor getSessionProcessor() { 63 return mSessionProcessor; 64 } 65 66 @Override enableTorch(boolean torch)67 public @NonNull ListenableFuture<Void> enableTorch(boolean torch) { 68 if (!SessionProcessorUtil.isOperationSupported(mSessionProcessor, 69 AdapterCameraInfo.CAMERA_OPERATION_TORCH)) { 70 return Futures.immediateFailedFuture( 71 new IllegalStateException("Torch is not supported")); 72 } 73 return mCameraControl.enableTorch(torch); 74 } 75 76 @Override startFocusAndMetering( @onNull FocusMeteringAction action)77 public @NonNull ListenableFuture<FocusMeteringResult> startFocusAndMetering( 78 @NonNull FocusMeteringAction action) { 79 FocusMeteringAction modifiedAction = 80 SessionProcessorUtil.getModifiedFocusMeteringAction(mSessionProcessor, action); 81 if (modifiedAction == null) { 82 return Futures.immediateFailedFuture( 83 new IllegalStateException("FocusMetering is not supported")); 84 } 85 86 return mCameraControl.startFocusAndMetering(modifiedAction); 87 } 88 89 @Override cancelFocusAndMetering()90 public @NonNull ListenableFuture<Void> cancelFocusAndMetering() { 91 return mCameraControl.cancelFocusAndMetering(); 92 } 93 94 @Override setZoomRatio(float ratio)95 public @NonNull ListenableFuture<Void> setZoomRatio(float ratio) { 96 if (!SessionProcessorUtil.isOperationSupported(mSessionProcessor, 97 AdapterCameraInfo.CAMERA_OPERATION_ZOOM)) { 98 return Futures.immediateFailedFuture( 99 new IllegalStateException("Zoom is not supported")); 100 } 101 102 if (mSessionProcessor != null) { 103 Range<Float> extensionZoomRange = mSessionProcessor.getExtensionZoomRange(); 104 if (extensionZoomRange != null 105 && (ratio < extensionZoomRange.getLower() 106 || ratio > extensionZoomRange.getUpper())) { 107 String outOfRangeDesc = "Requested zoomRatio " + ratio + " is not within valid " 108 + "range [" + extensionZoomRange.getLower() + " , " 109 + extensionZoomRange.getUpper() + "]"; 110 return Futures.immediateFailedFuture(new IllegalArgumentException(outOfRangeDesc)); 111 } 112 } 113 return mCameraControl.setZoomRatio(ratio); 114 } 115 116 @Override setLinearZoom(float linearZoom)117 public @NonNull ListenableFuture<Void> setLinearZoom(float linearZoom) { 118 if (!SessionProcessorUtil.isOperationSupported(mSessionProcessor, 119 AdapterCameraInfo.CAMERA_OPERATION_ZOOM)) { 120 return Futures.immediateFailedFuture( 121 new IllegalStateException("Zoom is not supported")); 122 } 123 124 if (mSessionProcessor != null) { 125 Range<Float> extensionZoomRange = mSessionProcessor.getExtensionZoomRange(); 126 if (extensionZoomRange == null) { 127 return mCameraControl.setLinearZoom(linearZoom); 128 } 129 130 if (linearZoom > 1.0f || linearZoom < 0f) { 131 String outOfRangeDesc = "Requested linearZoom " + linearZoom + " is not within" 132 + " valid range [0..1]"; 133 return Futures.immediateFailedFuture(new IllegalArgumentException(outOfRangeDesc)); 134 } 135 float zoomRatio = AdapterCameraInfo.getZoomRatioByPercentage(linearZoom, 136 extensionZoomRange.getLower(), extensionZoomRange.getUpper()); 137 return mCameraControl.setZoomRatio(zoomRatio); 138 } 139 140 return mCameraControl.setLinearZoom(linearZoom); 141 } 142 143 @Override setExposureCompensationIndex(int value)144 public @NonNull ListenableFuture<Integer> setExposureCompensationIndex(int value) { 145 if (!SessionProcessorUtil.isOperationSupported(mSessionProcessor, 146 AdapterCameraInfo.CAMERA_OPERATION_EXPOSURE_COMPENSATION)) { 147 return Futures.immediateFailedFuture( 148 new IllegalStateException("ExposureCompensation is not supported")); 149 } 150 return mCameraControl.setExposureCompensationIndex(value); 151 } 152 } 153