1 /*
2  * Copyright 2019 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.impl;
18 
19 import android.hardware.camera2.CameraCaptureSession;
20 import android.hardware.camera2.CameraDevice;
21 import android.hardware.camera2.CaptureRequest;
22 
23 import androidx.annotation.OptIn;
24 import androidx.annotation.RestrictTo;
25 import androidx.annotation.RestrictTo.Scope;
26 import androidx.camera.camera2.interop.CaptureRequestOptions;
27 import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
28 import androidx.camera.core.ExtendableBuilder;
29 import androidx.camera.core.impl.Config;
30 import androidx.camera.core.impl.MutableConfig;
31 import androidx.camera.core.impl.MutableOptionsBundle;
32 import androidx.camera.core.impl.OptionsBundle;
33 
34 import org.jspecify.annotations.NonNull;
35 import org.jspecify.annotations.Nullable;
36 
37 /**
38  * Internal shared implementation details for camera 2 interop.
39  */
40 @OptIn(markerClass = ExperimentalCamera2Interop.class)
41 public final class Camera2ImplConfig extends CaptureRequestOptions {
42 
43     @RestrictTo(Scope.LIBRARY)
44     public static final String CAPTURE_REQUEST_ID_STEM = "camera2.captureRequest.option.";
45 
46     // Option Declarations:
47     // *********************************************************************************************
48 
49     @RestrictTo(Scope.LIBRARY)
50     public static final Config.Option<Integer> TEMPLATE_TYPE_OPTION =
51             Option.create("camera2.captureRequest.templateType", int.class);
52     @RestrictTo(Scope.LIBRARY)
53     public static final Config.Option<Long> STREAM_USE_CASE_OPTION =
54             Option.create("camera2.cameraCaptureSession.streamUseCase", long.class);
55     @RestrictTo(Scope.LIBRARY)
56     public static final Option<CameraDevice.StateCallback> DEVICE_STATE_CALLBACK_OPTION =
57             Option.create("camera2.cameraDevice.stateCallback", CameraDevice.StateCallback.class);
58     @RestrictTo(Scope.LIBRARY)
59     public static final Option<CameraCaptureSession.StateCallback> SESSION_STATE_CALLBACK_OPTION =
60             Option.create(
61                     "camera2.cameraCaptureSession.stateCallback",
62                     CameraCaptureSession.StateCallback.class);
63     @RestrictTo(Scope.LIBRARY)
64     public static final Option<CameraCaptureSession.CaptureCallback>
65             SESSION_CAPTURE_CALLBACK_OPTION =
66             Option.create("camera2.cameraCaptureSession.captureCallback",
67                     CameraCaptureSession.CaptureCallback.class);
68     @RestrictTo(Scope.LIBRARY)
69     public static final Option<Object> CAPTURE_REQUEST_TAG_OPTION = Option.create(
70             "camera2.captureRequest.tag", Object.class);
71 
72     @RestrictTo(Scope.LIBRARY)
73     public static final Option<String> SESSION_PHYSICAL_CAMERA_ID_OPTION = Option.create(
74             "camera2.cameraCaptureSession.physicalCameraId", String.class);
75 
76     // *********************************************************************************************
77 
78     /**
79      * Creates a Camera2ImplConfig for reading Camera2 options from the given config.
80      *
81      * @param config The config that potentially contains Camera2 options.
82      */
Camera2ImplConfig(@onNull Config config)83     public Camera2ImplConfig(@NonNull Config config) {
84         super(config);
85     }
86 
87     // Unfortunately, we can't get the Class<T> from the CaptureRequest.Key, so we're forced to
88     // erase the type. This shouldn't be a problem as long as we are only using these options
89     // within the Camera2ImplConfig and Camera2ImplConfig.Builder classes.
90 
91     @RestrictTo(Scope.LIBRARY)
createCaptureRequestOption( CaptureRequest.@onNull Key<?> key)92     public static @NonNull Option<Object> createCaptureRequestOption(
93             CaptureRequest.@NonNull Key<?> key) {
94         return Option.create(CAPTURE_REQUEST_ID_STEM + key.getName(), Object.class, key);
95     }
96 
97     /**
98      * Returns all capture request options contained in this configuration.
99      *
100      */
101     @RestrictTo(Scope.LIBRARY)
getCaptureRequestOptions()102     public @NonNull CaptureRequestOptions getCaptureRequestOptions() {
103         return CaptureRequestOptions.Builder.from(getConfig()).build();
104     }
105 
106     /**
107      * Returns a CameraDevice template on the given configuration. Requires API 33 or above.
108      *
109      * <p>See {@link android.hardware.camera2.CameraMetadata} for valid stream use cases.
110      * See {@link android.hardware.camera2.params.OutputConfiguration} to see how
111      * camera2 framework uses this.
112      *
113      * @param valueIfMissing The value to return if this configuration option has not been set.
114      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
115      * configuration.
116      */
getStreamUseCase(long valueIfMissing)117     public long getStreamUseCase(long valueIfMissing) {
118         return getConfig().retrieveOption(STREAM_USE_CASE_OPTION, valueIfMissing);
119     }
120 
121     /**
122      * Returns the CameraDevice template from the given configuration.
123      *
124      * <p>See {@link CameraDevice} for valid template types. For example, {@link
125      * CameraDevice#TEMPLATE_PREVIEW}.
126      *
127      * @param valueIfMissing The value to return if this configuration option has not been set.
128      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
129      * configuration.
130      */
getCaptureRequestTemplate(int valueIfMissing)131     public int getCaptureRequestTemplate(int valueIfMissing) {
132         return getConfig().retrieveOption(TEMPLATE_TYPE_OPTION, valueIfMissing);
133     }
134 
135     /**
136      * Returns the stored {@link CameraDevice.StateCallback}.
137      *
138      * @param valueIfMissing The value to return if this configuration option has not been set.
139      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
140      * configuration.
141      */
getDeviceStateCallback( CameraDevice.@ullable StateCallback valueIfMissing)142     public CameraDevice.@Nullable StateCallback getDeviceStateCallback(
143             CameraDevice.@Nullable StateCallback valueIfMissing) {
144         return getConfig().retrieveOption(DEVICE_STATE_CALLBACK_OPTION, valueIfMissing);
145     }
146 
147 
148     /**
149      * Returns the stored {@link CameraCaptureSession.StateCallback}.
150      *
151      * @param valueIfMissing The value to return if this configuration option has not been set.
152      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
153      * configuration.
154      */
getSessionStateCallback( CameraCaptureSession.@ullable StateCallback valueIfMissing)155     public CameraCaptureSession.@Nullable StateCallback getSessionStateCallback(
156             CameraCaptureSession.@Nullable StateCallback valueIfMissing) {
157         return getConfig().retrieveOption(SESSION_STATE_CALLBACK_OPTION, valueIfMissing);
158     }
159 
160     /**
161      * Returns the stored {@link CameraCaptureSession.CaptureCallback}.
162      *
163      * @param valueIfMissing The value to return if this configuration option has not been set.
164      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
165      * configuration.
166      */
getSessionCaptureCallback( CameraCaptureSession.@ullable CaptureCallback valueIfMissing)167     public CameraCaptureSession.@Nullable CaptureCallback getSessionCaptureCallback(
168             CameraCaptureSession.@Nullable CaptureCallback valueIfMissing) {
169         return getConfig().retrieveOption(SESSION_CAPTURE_CALLBACK_OPTION, valueIfMissing);
170     }
171 
172     /**
173      * Returns the capture request tag.
174      *
175      * @param valueIfMissing The value to return if this configuration option has not been set.
176      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
177      * configuration.
178      */
getCaptureRequestTag(@ullable Object valueIfMissing)179     public @Nullable Object getCaptureRequestTag(@Nullable Object valueIfMissing) {
180         return getConfig().retrieveOption(CAPTURE_REQUEST_TAG_OPTION, valueIfMissing);
181     }
182 
183     /**
184      * Returns the physical camera ID.
185      *
186      * @param valueIfMissing The value to return if this configuration option has not been set.
187      * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
188      * configuration.
189      */
getPhysicalCameraId(@ullable String valueIfMissing)190     public @Nullable String getPhysicalCameraId(@Nullable String valueIfMissing) {
191         return getConfig().retrieveOption(SESSION_PHYSICAL_CAMERA_ID_OPTION, valueIfMissing);
192     }
193 
194     /**
195      * Builder for creating {@link Camera2ImplConfig} instance.
196      *
197      * <p>Use {@link Camera2ImplConfig.Builder} for creating {@link Config} which contains
198      * camera2 options only. And use
199      * {@link androidx.camera.camera2.interop.Camera2Interop.Extender} to add Camera2 options on
200      * existing other {@link
201      * ExtendableBuilder}.
202      */
203     public static final class Builder implements ExtendableBuilder<Camera2ImplConfig> {
204 
205         private final MutableOptionsBundle mMutableOptionsBundle = MutableOptionsBundle.create();
206 
207         @Override
getMutableConfig()208         public @NonNull MutableConfig getMutableConfig() {
209             return mMutableOptionsBundle;
210         }
211 
212         /**
213          * Inserts new capture request option with specific {@link CaptureRequest.Key} setting.
214          */
setCaptureRequestOption( CaptureRequest.@onNull Key<ValueT> key, @NonNull ValueT value)215         public <ValueT> Camera2ImplConfig.@NonNull Builder setCaptureRequestOption(
216                 CaptureRequest.@NonNull Key<ValueT> key, @NonNull ValueT value) {
217             Option<Object> opt = Camera2ImplConfig.createCaptureRequestOption(key);
218             mMutableOptionsBundle.insertOption(opt, value);
219             return this;
220         }
221 
222         /**
223          * Inserts new capture request option with specific {@link CaptureRequest.Key} setting and
224          * {@link OptionPriority}.
225          */
setCaptureRequestOptionWithPriority( CaptureRequest.@onNull Key<ValueT> key, @NonNull ValueT value, @NonNull OptionPriority priority)226         public <ValueT> @NonNull Builder setCaptureRequestOptionWithPriority(
227                 CaptureRequest.@NonNull Key<ValueT> key, @NonNull ValueT value,
228                 @NonNull OptionPriority priority) {
229             Option<Object> opt = Camera2ImplConfig.createCaptureRequestOption(key);
230             mMutableOptionsBundle.insertOption(opt, priority, value);
231             return this;
232         }
233 
234         /** Inserts options from other {@link Config} object. */
insertAllOptions(@onNull Config config)235         public Camera2ImplConfig.@NonNull Builder insertAllOptions(@NonNull Config config) {
236             insertAllOptions(config, OptionPriority.OPTIONAL);
237             return this;
238         }
239 
240         /** Inserts options from other {@link Config} object with the given option priority. */
insertAllOptions(@onNull Config config, @NonNull OptionPriority optionPriority)241         public Camera2ImplConfig.@NonNull Builder insertAllOptions(@NonNull Config config,
242                 @NonNull OptionPriority optionPriority) {
243             for (Option<?> option : config.listOptions()) {
244                 @SuppressWarnings("unchecked") // Options/values are being copied directly
245                 Option<Object> objectOpt = (Option<Object>) option;
246                 mMutableOptionsBundle.insertOption(objectOpt, optionPriority,
247                         config.retrieveOption(objectOpt));
248             }
249             return this;
250         }
251 
252         /**
253          * Builds an immutable {@link Camera2ImplConfig} from the current state.
254          *
255          * @return A {@link Camera2ImplConfig} populated with the current state.
256          */
257         @Override
build()258         public @NonNull Camera2ImplConfig build() {
259             return new Camera2ImplConfig(OptionsBundle.from(mMutableOptionsBundle));
260         }
261     }
262 }
263