1 /*
2  * Copyright 2021 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.extensions.internal.sessionprocessor;
18 
19 import static android.hardware.camera2.CameraExtensionCharacteristics.EXTENSION_AUTOMATIC;
20 import static android.hardware.camera2.CameraExtensionCharacteristics.EXTENSION_BOKEH;
21 import static android.hardware.camera2.CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH;
22 import static android.hardware.camera2.CameraExtensionCharacteristics.EXTENSION_HDR;
23 import static android.hardware.camera2.CameraExtensionCharacteristics.EXTENSION_NIGHT;
24 
25 import android.annotation.SuppressLint;
26 import android.content.Context;
27 import android.hardware.camera2.CameraCharacteristics;
28 import android.hardware.camera2.CaptureFailure;
29 import android.hardware.camera2.CaptureRequest;
30 import android.hardware.camera2.CaptureResult;
31 import android.hardware.camera2.TotalCaptureResult;
32 import android.hardware.camera2.params.SessionConfiguration;
33 import android.media.Image;
34 import android.os.Build;
35 import android.util.Pair;
36 import android.util.Size;
37 import android.view.Surface;
38 
39 import androidx.annotation.GuardedBy;
40 import androidx.annotation.IntRange;
41 import androidx.camera.core.Logger;
42 import androidx.camera.core.impl.CameraCaptureFailure;
43 import androidx.camera.core.impl.CameraCaptureResult;
44 import androidx.camera.core.impl.Config;
45 import androidx.camera.core.impl.OutputSurface;
46 import androidx.camera.core.impl.OutputSurfaceConfiguration;
47 import androidx.camera.core.impl.RequestProcessor;
48 import androidx.camera.core.impl.SessionProcessor;
49 import androidx.camera.core.impl.TagBundle;
50 import androidx.camera.extensions.ExtensionMode;
51 import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl;
52 import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
53 import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
54 import androidx.camera.extensions.impl.advanced.ImageReferenceImpl;
55 import androidx.camera.extensions.impl.advanced.OutputSurfaceConfigurationImpl;
56 import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
57 import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
58 import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
59 import androidx.camera.extensions.internal.ClientVersion;
60 import androidx.camera.extensions.internal.ExtensionVersion;
61 import androidx.camera.extensions.internal.RequestOptionConfig;
62 import androidx.camera.extensions.internal.VendorExtender;
63 import androidx.camera.extensions.internal.Version;
64 import androidx.core.util.Preconditions;
65 import androidx.lifecycle.LiveData;
66 import androidx.lifecycle.MutableLiveData;
67 
68 import org.jspecify.annotations.NonNull;
69 import org.jspecify.annotations.Nullable;
70 
71 import java.util.ArrayList;
72 import java.util.Collections;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Objects;
77 
78 /**
79  * A {@link SessionProcessor} based on OEMs' {@link SessionProcessorImpl}.
80  */
81 public class AdvancedSessionProcessor extends SessionProcessorBase {
82     private static final String TAG = "AdvancedSessionProcessor";
83     private final @NonNull SessionProcessorImpl mImpl;
84     private final @NonNull VendorExtender mVendorExtender;
85     private final @NonNull Context mContext;
86     @ExtensionMode.Mode
87     private final int mMode;
88     private final @Nullable MutableLiveData<Integer> mCurrentExtensionTypeLiveData;
89     private boolean mIsPostviewConfigured = false;
90     // Caches the working capture config so that the new extension strength can be applied on top
91     // of the existing config.
92     @GuardedBy("mLock")
93     private HashMap<CaptureRequest.Key<?>, Object> mWorkingCaptureConfigMap = new HashMap<>();
94     // Caches the capture callback adapter so that repeating can be started again to apply the
95     // new extension strength setting.
96     @GuardedBy("mLock")
97     private SessionProcessorImplCaptureCallbackAdapter mRepeatingCaptureCallbackAdapter = null;
98     private final @Nullable MutableLiveData<Integer> mExtensionStrengthLiveData;
99     private final @Nullable ExtensionMetadataMonitor mExtensionMetadataMonitor;
100     private final boolean mWillReceiveOnCaptureCompleted;
101 
AdvancedSessionProcessor(@onNull SessionProcessorImpl impl, @NonNull List<CaptureRequest.Key<?>> supportedKeys, @NonNull VendorExtender vendorExtender, @NonNull Context context)102     public AdvancedSessionProcessor(@NonNull SessionProcessorImpl impl,
103             @NonNull List<CaptureRequest.Key<?>> supportedKeys,
104             @NonNull VendorExtender vendorExtender,
105             @NonNull Context context) {
106         this(impl, supportedKeys, vendorExtender, context, ExtensionMode.NONE);
107     }
108 
AdvancedSessionProcessor(@onNull SessionProcessorImpl impl, @NonNull List<CaptureRequest.Key<?>> supportedKeys, @NonNull VendorExtender vendorExtender, @NonNull Context context, @ExtensionMode.Mode int mode)109     public AdvancedSessionProcessor(@NonNull SessionProcessorImpl impl,
110             @NonNull List<CaptureRequest.Key<?>> supportedKeys,
111             @NonNull VendorExtender vendorExtender,
112             @NonNull Context context,
113             @ExtensionMode.Mode int mode) {
114         super(supportedKeys, mode);
115         mImpl = impl;
116         mVendorExtender = vendorExtender;
117         mContext = context;
118         mWillReceiveOnCaptureCompleted = vendorExtender.willReceiveOnCaptureCompleted();
119         mMode = mode;
120         mCurrentExtensionTypeLiveData = isCurrentExtensionModeAvailable() ? new MutableLiveData<>(
121                 mMode) : null;
122         mExtensionStrengthLiveData = isExtensionStrengthAvailable() ? new MutableLiveData<>(100)
123                 : null;
124         if (mCurrentExtensionTypeLiveData != null || mExtensionStrengthLiveData != null) {
125             mExtensionMetadataMonitor = new ExtensionMetadataMonitor(mCurrentExtensionTypeLiveData,
126                     mExtensionStrengthLiveData);
127         } else {
128             mExtensionMetadataMonitor = null;
129         }
130     }
131 
132     @Override
initSessionInternal( @onNull String cameraId, @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, @NonNull OutputSurfaceConfiguration outputSurfaceConfig)133     protected @NonNull Camera2SessionConfig initSessionInternal(
134             @NonNull String cameraId,
135             @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
136             @NonNull OutputSurfaceConfiguration outputSurfaceConfig) {
137         Camera2SessionConfigImpl sessionConfigImpl = null;
138         if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)
139                 && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)) {
140             sessionConfigImpl =
141                     mImpl.initSession(
142                             cameraId,
143                             cameraCharacteristicsMap,
144                             mContext,
145                             new OutputSurfaceConfigurationImplAdapter(outputSurfaceConfig));
146 
147         }
148 
149         // In case of OEM doesn't implement the v1.4 version of initSession, we fallback to invoke
150         // prior version.
151         if (sessionConfigImpl == null) {
152             sessionConfigImpl =
153                     mImpl.initSession(
154                             cameraId,
155                             cameraCharacteristicsMap,
156                             mContext,
157                             new OutputSurfaceImplAdapter(
158                                     outputSurfaceConfig.getPreviewOutputSurface()),
159                             new OutputSurfaceImplAdapter(
160                                     outputSurfaceConfig.getImageCaptureOutputSurface()),
161                             outputSurfaceConfig.getImageAnalysisOutputSurface() == null
162                                     ? null : new OutputSurfaceImplAdapter(
163                                     outputSurfaceConfig.getImageAnalysisOutputSurface()));
164         }
165 
166         mIsPostviewConfigured = outputSurfaceConfig.getPostviewOutputSurface() != null;
167         // Resets the extension type and strength result when initializing the session
168         if (mCurrentExtensionTypeLiveData != null) {
169             mCurrentExtensionTypeLiveData.postValue(mMode);
170         }
171         if (mExtensionStrengthLiveData != null) {
172             mExtensionStrengthLiveData.postValue(100);
173         }
174         // Convert Camera2SessionConfigImpl(implemented in OEM) into Camera2SessionConfig
175         return convertToCamera2SessionConfig(sessionConfigImpl);
176     }
177 
convertToCamera2SessionConfig( @onNull Camera2SessionConfigImpl sessionConfigImpl)178     private Camera2SessionConfig convertToCamera2SessionConfig(
179             @NonNull Camera2SessionConfigImpl sessionConfigImpl) {
180         Camera2SessionConfigBuilder camera2SessionConfigBuilder = new Camera2SessionConfigBuilder();
181         for (Camera2OutputConfigImpl outputConfigImpl : sessionConfigImpl.getOutputConfigs()) {
182             Camera2OutputConfig outputConfig =
183                     Camera2OutputConfigConverter.fromImpl(outputConfigImpl);
184             camera2SessionConfigBuilder.addOutputConfig(outputConfig);
185         }
186 
187         for (CaptureRequest.Key<?> key : sessionConfigImpl.getSessionParameters().keySet()) {
188             @SuppressWarnings("unchecked")
189             CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
190             camera2SessionConfigBuilder.addSessionParameter(objKey,
191                     sessionConfigImpl.getSessionParameters().get(objKey));
192         }
193         camera2SessionConfigBuilder
194                 .setSessionTemplateId(sessionConfigImpl.getSessionTemplateId());
195         if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)
196                 && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)) {
197             try {
198                 int sessionType = sessionConfigImpl.getSessionType();
199                 if (sessionType == -1) { // -1 means using default value
200                     sessionType = SessionConfiguration.SESSION_REGULAR;
201                 }
202                 camera2SessionConfigBuilder.setSessionType(sessionType);
203             } catch (NoSuchMethodError e) {
204                 camera2SessionConfigBuilder.setSessionType(SessionConfiguration.SESSION_REGULAR);
205             }
206         }
207         return camera2SessionConfigBuilder.build();
208     }
209 
210     @Override
deInitSessionInternal()211     protected void deInitSessionInternal() {
212         synchronized (mLock) {
213             // Clears the working config map
214             mWorkingCaptureConfigMap = new HashMap<>();
215             mRepeatingCaptureCallbackAdapter = null;
216         }
217         mImpl.deInitSession();
218     }
219 
220     @Override
isCurrentExtensionModeAvailable()221     public boolean isCurrentExtensionModeAvailable() {
222         return mVendorExtender.isCurrentExtensionModeAvailable();
223     }
224 
225     @Override
getCurrentExtensionMode()226     public @NonNull LiveData<Integer> getCurrentExtensionMode() {
227         return mCurrentExtensionTypeLiveData;
228     }
229 
230     @Override
isExtensionStrengthAvailable()231     public boolean isExtensionStrengthAvailable() {
232         return mVendorExtender.isExtensionStrengthAvailable();
233     }
234 
235     @Override
236     @SuppressWarnings("unchecked")
setExtensionStrength(@ntRangefrom = 0, to = 100) int strength)237     public void setExtensionStrength(@IntRange(from = 0, to = 100) int strength) {
238         if (!isExtensionStrengthAvailable()
239                 || Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
240             return;
241         }
242 
243         SessionProcessorImplCaptureCallbackAdapter captureCallbackAdapter;
244         HashMap<CaptureRequest.Key<?>, Object> captureConfigMap;
245 
246         synchronized (mLock) {
247             mExtensionStrength = strength;
248             mWorkingCaptureConfigMap.put(CaptureRequest.EXTENSION_STRENGTH, mExtensionStrength);
249             captureCallbackAdapter = mRepeatingCaptureCallbackAdapter;
250             captureConfigMap =
251                     (HashMap<CaptureRequest.Key<?>, Object>) mWorkingCaptureConfigMap.clone();
252         }
253 
254         mImpl.setParameters(captureConfigMap);
255 
256         // Starts the repeating again to apply the new strength setting if it has been started.
257         // Otherwise, the new strength setting will be applied when the capture session is
258         // configured and repeating is started.
259         if (captureCallbackAdapter != null) {
260             mImpl.startRepeating(captureCallbackAdapter);
261         }
262     }
263 
264     @SuppressLint("KotlinPropertyAccess")
265     @Override
getExtensionStrength()266     public @NonNull LiveData<Integer> getExtensionStrength() {
267         return mExtensionStrengthLiveData;
268     }
269 
270     @Override
setParameters( @onNull Config parameters)271     public void setParameters(
272             @NonNull Config parameters) {
273         HashMap<CaptureRequest.Key<?>, Object> captureConfigMap;
274 
275         synchronized (mLock) {
276             captureConfigMap = convertConfigToMap(parameters);
277             // Applies extension strength setting if it is set via
278             // CameraExtensionsControl#setExtensionStrength() API.
279             if (mExtensionStrength != EXTENSION_STRENGTH_UNKNOWN
280                     && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
281                 captureConfigMap.put(CaptureRequest.EXTENSION_STRENGTH, mExtensionStrength);
282             }
283             mWorkingCaptureConfigMap = captureConfigMap;
284         }
285 
286         mImpl.setParameters(captureConfigMap);
287     }
288 
convertConfigToMap( @onNull Config parameters)289     private static @NonNull HashMap<CaptureRequest.Key<?>, Object> convertConfigToMap(
290             @NonNull Config parameters) {
291         HashMap<CaptureRequest.Key<?>, Object> map = new HashMap<>();
292 
293         RequestOptionConfig options =
294                 RequestOptionConfig.Builder.from(parameters).build();
295 
296         for (Config.Option<?> option : options.listOptions()) {
297             @SuppressWarnings("unchecked")
298             CaptureRequest.Key<Object> key = (CaptureRequest.Key<Object>) option.getToken();
299             map.put(key, options.retrieveOption(option));
300         }
301         return map;
302     }
303 
304     @Override
onCaptureSessionStart( @onNull RequestProcessor requestProcessor)305     public void onCaptureSessionStart(
306             @NonNull RequestProcessor requestProcessor) {
307         mImpl.onCaptureSessionStart(new RequestProcessorImplAdapter(requestProcessor));
308     }
309 
310     @Override
onCaptureSessionEnd()311     public void onCaptureSessionEnd() {
312         mImpl.onCaptureSessionEnd();
313     }
314 
315     @Override
startCapture( boolean postviewEnabled, @NonNull TagBundle tagBundle, SessionProcessor.@NonNull CaptureCallback callback)316     public int startCapture(
317             boolean postviewEnabled,
318             @NonNull TagBundle tagBundle,
319             SessionProcessor.@NonNull CaptureCallback callback) {
320         Logger.d(TAG, "startCapture postviewEnabled = " + postviewEnabled
321                 + " mWillReceiveOnCaptureCompleted = " + mWillReceiveOnCaptureCompleted);
322         SessionProcessorImplCaptureCallbackAdapter stillCaptureCallback =
323                 new SessionProcessorImplCaptureCallbackAdapter(
324                         callback, tagBundle, mWillReceiveOnCaptureCompleted);
325 
326         if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)
327                 && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)
328                 && mIsPostviewConfigured && postviewEnabled
329                 && mVendorExtender.isPostviewAvailable()) {
330             return mImpl.startCaptureWithPostview(stillCaptureCallback);
331         } else {
332             return mImpl.startCapture(stillCaptureCallback);
333         }
334     }
335 
336     @Override
startRepeating(@onNull TagBundle tagBundle, SessionProcessor.@NonNull CaptureCallback callback)337     public int startRepeating(@NonNull TagBundle tagBundle,
338             SessionProcessor.@NonNull CaptureCallback callback) {
339         SessionProcessorImplCaptureCallbackAdapter captureCallbackAdapter;
340         synchronized (mLock) {
341             captureCallbackAdapter = new SessionProcessorImplCaptureCallbackAdapter(callback,
342                     tagBundle, mExtensionMetadataMonitor, mWillReceiveOnCaptureCompleted);
343             mRepeatingCaptureCallbackAdapter = captureCallbackAdapter;
344         }
345         return mImpl.startRepeating(captureCallbackAdapter);
346     }
347 
348     @Override
startTrigger(@onNull Config config, @NonNull TagBundle tagBundle, @NonNull CaptureCallback callback)349     public int startTrigger(@NonNull Config config, @NonNull TagBundle tagBundle,
350             @NonNull CaptureCallback callback) {
351         HashMap<CaptureRequest.Key<?>, Object> map = convertConfigToMap(config);
352         if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
353                 && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)) {
354             return mImpl.startTrigger(map,
355                     new SessionProcessorImplCaptureCallbackAdapter(
356                             callback, tagBundle, mWillReceiveOnCaptureCompleted));
357         }
358         return -1;
359     }
360 
361     @Override
stopRepeating()362     public void stopRepeating() {
363         mImpl.stopRepeating();
364         synchronized (mLock) {
365             mRepeatingCaptureCallbackAdapter = null;
366         }
367     }
368 
369     @Override
abortCapture(int captureSequenceId)370     public void abortCapture(int captureSequenceId) {
371         mImpl.abortCapture(captureSequenceId);
372     }
373 
374     @Override
getRealtimeCaptureLatency()375     public @Nullable Pair<Long, Long> getRealtimeCaptureLatency() {
376         if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)
377                 && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)) {
378             return mImpl.getRealtimeCaptureLatency();
379         }
380         return null;
381     }
382 
383     @Override
getSupportedPostviewSize(@onNull Size captureSize)384     public @NonNull Map<Integer, List<Size>> getSupportedPostviewSize(@NonNull Size captureSize) {
385         return mVendorExtender.getSupportedPostviewResolutions(captureSize);
386     }
387 
388     @Override
389     public @NonNull List<Pair<CameraCharacteristics.Key, Object>>
getAvailableCharacteristicsKeyValues()390         getAvailableCharacteristicsKeyValues() {
391         return mVendorExtender.getAvailableCharacteristicsKeyValues();
392     }
393 
394     /**
395      * Adapter to transform a {@link OutputSurface} to a {@link OutputSurfaceImpl}.
396      */
397     private static class OutputSurfaceImplAdapter implements OutputSurfaceImpl {
398         private final OutputSurface mOutputSurface;
399 
400         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
OutputSurfaceImplAdapter(OutputSurface outputSurface)401         OutputSurfaceImplAdapter(OutputSurface outputSurface) {
402             mOutputSurface = outputSurface;
403         }
404 
405         @Override
getSurface()406         public @NonNull Surface getSurface() {
407             return mOutputSurface.getSurface();
408         }
409 
410         @Override
getSize()411         public @NonNull Size getSize() {
412             return mOutputSurface.getSize();
413         }
414 
415         @Override
getImageFormat()416         public int getImageFormat() {
417             return mOutputSurface.getImageFormat();
418         }
419     }
420 
421     private static class OutputSurfaceConfigurationImplAdapter implements
422             OutputSurfaceConfigurationImpl {
423         private final OutputSurfaceImpl mPreviewOutputSurface;
424         private final OutputSurfaceImpl mCaptureOutputSurface;
425         private final OutputSurfaceImpl mAnalysisOutputSurface;
426         private final OutputSurfaceImpl mPostviewOutputSurface;
427 
OutputSurfaceConfigurationImplAdapter( @onNull OutputSurfaceConfiguration outputSurfaceConfig)428         OutputSurfaceConfigurationImplAdapter(
429                 @NonNull OutputSurfaceConfiguration outputSurfaceConfig) {
430             mPreviewOutputSurface = new OutputSurfaceImplAdapter(
431                     outputSurfaceConfig.getPreviewOutputSurface());
432             mCaptureOutputSurface = new OutputSurfaceImplAdapter(
433                     outputSurfaceConfig.getImageCaptureOutputSurface());
434             mAnalysisOutputSurface =
435                     outputSurfaceConfig.getImageAnalysisOutputSurface() != null
436                             ? new OutputSurfaceImplAdapter(
437                             outputSurfaceConfig.getImageAnalysisOutputSurface()) : null;
438             mPostviewOutputSurface =
439                     outputSurfaceConfig.getPostviewOutputSurface() != null
440                             ? new OutputSurfaceImplAdapter(
441                             outputSurfaceConfig.getPostviewOutputSurface()) : null;
442         }
443 
444         @Override
getPreviewOutputSurface()445         public @NonNull OutputSurfaceImpl getPreviewOutputSurface() {
446             return mPreviewOutputSurface;
447         }
448 
449         @Override
getImageCaptureOutputSurface()450         public @NonNull OutputSurfaceImpl getImageCaptureOutputSurface() {
451             return mCaptureOutputSurface;
452         }
453 
454         @Override
getImageAnalysisOutputSurface()455         public @Nullable OutputSurfaceImpl getImageAnalysisOutputSurface() {
456             return mAnalysisOutputSurface;
457         }
458 
459         @Override
getPostviewOutputSurface()460         public @Nullable OutputSurfaceImpl getPostviewOutputSurface() {
461             return mPostviewOutputSurface;
462         }
463     }
464 
465     /**
466      * Adapter to transform a {@link RequestProcessor} to {@link RequestProcessorImpl}.
467      */
468     private class RequestProcessorImplAdapter implements RequestProcessorImpl {
469         private final RequestProcessor mRequestProcessor;
470 
471         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
RequestProcessorImplAdapter(@onNull RequestProcessor requestProcessor)472         RequestProcessorImplAdapter(@NonNull RequestProcessor requestProcessor) {
473             mRequestProcessor = requestProcessor;
474         }
475 
476         @Override
setImageProcessor(int outputConfigId, @NonNull ImageProcessorImpl imageProcessorImpl)477         public void setImageProcessor(int outputConfigId,
478                 @NonNull ImageProcessorImpl imageProcessorImpl) {
479             AdvancedSessionProcessor.this.setImageProcessor(outputConfigId,
480                     new ImageProcessorAdapter(imageProcessorImpl));
481         }
482 
483         @Override
submit( RequestProcessorImpl.@onNull Request request, @NonNull Callback callback)484         public int submit(
485                 RequestProcessorImpl.@NonNull Request request, @NonNull Callback callback) {
486             return mRequestProcessor.submit(new RequestAdapter(request),
487                     new CallbackAdapter(callback));
488         }
489 
490         @Override
submit( @onNull List<RequestProcessorImpl.Request> requests, @NonNull Callback callback)491         public int submit(
492                 @NonNull List<RequestProcessorImpl.Request> requests, @NonNull Callback callback) {
493             ArrayList<RequestProcessor.Request> outRequests = new ArrayList<>();
494             for (RequestProcessorImpl.Request request : requests) {
495                 outRequests.add(new RequestAdapter(request));
496             }
497             return mRequestProcessor.submit(outRequests, new CallbackAdapter(callback));
498         }
499 
500         @Override
setRepeating( RequestProcessorImpl.@onNull Request request, @NonNull Callback callback)501         public int setRepeating(
502                 RequestProcessorImpl.@NonNull Request request, @NonNull Callback callback) {
503             return mRequestProcessor.setRepeating(new RequestAdapter(request),
504                     new CallbackAdapter(callback));
505         }
506 
507         @Override
abortCaptures()508         public void abortCaptures() {
509             mRequestProcessor.abortCaptures();
510         }
511 
512         @Override
stopRepeating()513         public void stopRepeating() {
514             mRequestProcessor.stopRepeating();
515         }
516     }
517 
518     /**
519      * Adapter to transform a {@link RequestProcessorImpl.Request} to a
520      * {@link RequestProcessor.Request}.
521      */
522     private static class RequestAdapter implements RequestProcessor.Request {
523         private final RequestProcessorImpl.Request mImplRequest;
524         private final List<Integer> mTargetOutputConfigIds;
525         private final Config mParameters;
526         private final int mTemplateId;
527 
528         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
RequestAdapter(RequestProcessorImpl.@onNull Request implRequest)529         RequestAdapter(RequestProcessorImpl.@NonNull Request implRequest) {
530             mImplRequest = implRequest;
531 
532             List<Integer> targetOutputConfigIds = new ArrayList<>();
533             for (Integer outputConfigId : implRequest.getTargetOutputConfigIds()) {
534                 targetOutputConfigIds.add(outputConfigId);
535             }
536             mTargetOutputConfigIds = targetOutputConfigIds;
537 
538             RequestOptionConfig.Builder optionBuilder = new RequestOptionConfig.Builder();
539             for (CaptureRequest.Key<?> key : implRequest.getParameters().keySet()) {
540                 @SuppressWarnings("unchecked")
541                 CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
542                 optionBuilder.setCaptureRequestOption(objKey,
543                         implRequest.getParameters().get(objKey));
544             }
545             mParameters = optionBuilder.build();
546             mTemplateId = implRequest.getTemplateId();
547         }
548 
549         @Override
getTargetOutputConfigIds()550         public @NonNull List<Integer> getTargetOutputConfigIds() {
551             return mTargetOutputConfigIds;
552         }
553 
554         @Override
getParameters()555         public @NonNull Config getParameters() {
556             return mParameters;
557         }
558 
559         @Override
getTemplateId()560         public int getTemplateId() {
561             return mTemplateId;
562         }
563 
getImplRequest()564         public RequestProcessorImpl.@Nullable Request getImplRequest() {
565             return mImplRequest;
566         }
567     }
568 
569     /**
570      * Adapter to transform a {@link ImageProcessorImpl} to {@link ImageProcessor}.
571      */
572     private static class ImageProcessorAdapter implements ImageProcessor {
573         private final ImageProcessorImpl mImpl;
574 
575         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
ImageProcessorAdapter(ImageProcessorImpl impl)576         ImageProcessorAdapter(ImageProcessorImpl impl) {
577             mImpl = impl;
578         }
579 
580         @Override
onNextImageAvailable(int outputStreamId, long timestampNs, @NonNull ImageReference imageReference, @Nullable String physicalCameraId)581         public void onNextImageAvailable(int outputStreamId, long timestampNs,
582                 @NonNull ImageReference imageReference, @Nullable String physicalCameraId) {
583             mImpl.onNextImageAvailable(outputStreamId, timestampNs,
584                     new ImageReferenceImplAdapter(imageReference), physicalCameraId);
585         }
586     }
587 
588     /**
589      * Adapter to transform a {@link ImageReference} to a {@link ImageReferenceImpl}.
590      */
591     private static class ImageReferenceImplAdapter implements ImageReferenceImpl {
592         private final ImageReference mImageReference;
593 
594         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
ImageReferenceImplAdapter(ImageReference imageReference)595         ImageReferenceImplAdapter(ImageReference imageReference) {
596             mImageReference = imageReference;
597         }
598 
599         @Override
increment()600         public boolean increment() {
601             return mImageReference.increment();
602         }
603 
604         @Override
decrement()605         public boolean decrement() {
606             return mImageReference.decrement();
607         }
608 
609         @Override
get()610         public @Nullable Image get() {
611             return mImageReference.get();
612         }
613     }
614 
615     /**
616      * Adapter to transform a {@link RequestProcessorImpl.Callback} to a
617      * {@link RequestProcessor.Callback}.
618      */
619     private static class CallbackAdapter implements RequestProcessor.Callback {
620         private final RequestProcessorImpl.Callback mCallback;
621 
622         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
CallbackAdapter(RequestProcessorImpl.@onNull Callback callback)623         CallbackAdapter(RequestProcessorImpl.@NonNull Callback callback) {
624             mCallback = callback;
625         }
626 
627         @Override
onCaptureStarted( RequestProcessor.@onNull Request request, long frameNumber, long timestamp)628         public void onCaptureStarted(
629                 RequestProcessor.@NonNull Request request,
630                 long frameNumber, long timestamp) {
631             mCallback.onCaptureStarted(getImplRequest(request), frameNumber,
632                     timestamp);
633         }
634 
635         @Override
onCaptureProgressed( RequestProcessor.@onNull Request request, @NonNull CameraCaptureResult cameraCaptureResult)636         public void onCaptureProgressed(
637                 RequestProcessor.@NonNull Request request,
638                 @NonNull CameraCaptureResult cameraCaptureResult) {
639             CaptureResult captureResult = cameraCaptureResult.getCaptureResult();
640             Preconditions.checkArgument(captureResult != null,
641                     "Cannot get CaptureResult from the cameraCaptureResult ");
642             mCallback.onCaptureProgressed(getImplRequest(request), captureResult);
643         }
644 
645         @Override
onCaptureCompleted( RequestProcessor.@onNull Request request, @Nullable CameraCaptureResult cameraCaptureResult)646         public void onCaptureCompleted(
647                 RequestProcessor.@NonNull Request request,
648                 @Nullable CameraCaptureResult cameraCaptureResult) {
649             CaptureResult captureResult = cameraCaptureResult.getCaptureResult();
650             Preconditions.checkArgument(captureResult instanceof TotalCaptureResult,
651                     "CaptureResult in cameraCaptureResult is not a TotalCaptureResult");
652             mCallback.onCaptureCompleted(getImplRequest(request),
653                     (TotalCaptureResult) captureResult);
654         }
655 
656         @Override
onCaptureFailed( RequestProcessor.@onNull Request request, @Nullable CameraCaptureFailure cameraCaptureFailure)657         public void onCaptureFailed(
658                 RequestProcessor.@NonNull Request request,
659                 @Nullable CameraCaptureFailure cameraCaptureFailure) {
660             Object captureFailure = cameraCaptureFailure.getCaptureFailure();
661             Preconditions.checkArgument(captureFailure instanceof CaptureFailure,
662                     "CameraCaptureFailure does not contain CaptureFailure.");
663             mCallback.onCaptureFailed(getImplRequest(request), (CaptureFailure) captureFailure);
664         }
665 
666         @Override
onCaptureBufferLost( RequestProcessor.@onNull Request request, long frameNumber, int outputStreamId)667         public void onCaptureBufferLost(
668                 RequestProcessor.@NonNull Request request,
669                 long frameNumber, int outputStreamId) {
670             mCallback.onCaptureBufferLost(getImplRequest(request), frameNumber, outputStreamId);
671         }
672 
673         @Override
onCaptureSequenceCompleted( int sequenceId, long frameNumber)674         public void onCaptureSequenceCompleted(
675                 int sequenceId, long frameNumber) {
676             mCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
677         }
678 
679         @Override
onCaptureSequenceAborted(int sequenceId)680         public void onCaptureSequenceAborted(int sequenceId) {
681             mCallback.onCaptureSequenceAborted(sequenceId);
682         }
683 
getImplRequest( RequestProcessor.Request request)684         private RequestProcessorImpl.Request getImplRequest(
685                 RequestProcessor.Request request) {
686             Preconditions.checkArgument(request instanceof RequestAdapter);
687 
688             RequestAdapter requestProcessorRequest = (RequestAdapter) request;
689             return requestProcessorRequest.getImplRequest();
690         }
691     }
692 
693     /**
694      * Adapter to transform a {@link SessionProcessor.CaptureCallback} to a
695      * {@link SessionProcessorImpl.CaptureCallback}.
696      */
697     private static class SessionProcessorImplCaptureCallbackAdapter implements
698             SessionProcessorImpl.CaptureCallback {
699         private final SessionProcessor.CaptureCallback mCaptureCallback;
700         private final @Nullable ExtensionMetadataMonitor mExtensionMetadataMonitor;
701         private final @NonNull TagBundle mTagBundle;
702         private long mOnCaptureStartedTimestamp = -1;
703         private boolean mWillReceiveOnCaptureCompleted;
704 
SessionProcessorImplCaptureCallbackAdapter( SessionProcessor.@onNull CaptureCallback callback, @NonNull TagBundle tagBundle, boolean willReceiveOnCaptureCompleted)705         SessionProcessorImplCaptureCallbackAdapter(
706                 SessionProcessor.@NonNull CaptureCallback callback,
707                 @NonNull TagBundle tagBundle,
708                 boolean willReceiveOnCaptureCompleted) {
709             this(callback, tagBundle, null, willReceiveOnCaptureCompleted);
710         }
711 
712         @SuppressWarnings("WeakerAccess") /* synthetic accessor */
SessionProcessorImplCaptureCallbackAdapter( SessionProcessor.@onNull CaptureCallback callback, @NonNull TagBundle tagBundle, @Nullable ExtensionMetadataMonitor extensionMetadataMonitor, boolean willReceiveOnCaptureCompleted)713         SessionProcessorImplCaptureCallbackAdapter(
714                 SessionProcessor.@NonNull CaptureCallback callback,
715                 @NonNull TagBundle tagBundle,
716                 @Nullable ExtensionMetadataMonitor extensionMetadataMonitor,
717                 boolean willReceiveOnCaptureCompleted) {
718             mCaptureCallback = callback;
719             mTagBundle = tagBundle;
720             mExtensionMetadataMonitor = extensionMetadataMonitor;
721             mWillReceiveOnCaptureCompleted = willReceiveOnCaptureCompleted;
722         }
723 
724         @Override
onCaptureStarted( int captureSequenceId, long timestamp)725         public void onCaptureStarted(
726                 int captureSequenceId,
727                 long timestamp) {
728             mOnCaptureStartedTimestamp = timestamp;
729             mCaptureCallback.onCaptureStarted(captureSequenceId, timestamp);
730         }
731 
732         @Override
onCaptureProcessStarted( int captureSequenceId)733         public void onCaptureProcessStarted(
734                 int captureSequenceId) {
735             mCaptureCallback.onCaptureProcessStarted(captureSequenceId);
736         }
737 
738         @Override
onCaptureFailed(int captureSequenceId)739         public void onCaptureFailed(int captureSequenceId) {
740             mCaptureCallback.onCaptureFailed(captureSequenceId);
741         }
742 
743         @Override
onCaptureSequenceCompleted(int captureSequenceId)744         public void onCaptureSequenceCompleted(int captureSequenceId) {
745             if (!mWillReceiveOnCaptureCompleted) {
746                 // If SessionProcessorImpl.CaptureCallback.onCaptureCompleted won't be invoked,
747                 // We finish the capture sequence using the timestamp retrieved at onCaptureStarted
748                 // when onCaptureSequenceCompleted is invoked.
749                 mCaptureCallback.onCaptureCompleted(mOnCaptureStartedTimestamp,
750                         captureSequenceId,
751                         new KeyValueMapCameraCaptureResult(
752                                 mOnCaptureStartedTimestamp, mTagBundle, Collections.emptyMap()));
753                 mCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
754             }
755         }
756 
757         @Override
onCaptureSequenceAborted(int captureSequenceId)758         public void onCaptureSequenceAborted(int captureSequenceId) {
759             mCaptureCallback.onCaptureSequenceAborted(captureSequenceId);
760         }
761 
762         @Override
onCaptureCompleted(long timestamp, int captureSequenceId, Map<CaptureResult.Key, Object> result)763         public void onCaptureCompleted(long timestamp, int captureSequenceId,
764                 Map<CaptureResult.Key, Object> result) {
765             if (mExtensionMetadataMonitor != null) {
766                 mExtensionMetadataMonitor.checkExtensionMetadata(result);
767             }
768             if (mWillReceiveOnCaptureCompleted) {
769                 mCaptureCallback.onCaptureCompleted(timestamp, captureSequenceId,
770                         new KeyValueMapCameraCaptureResult(timestamp, mTagBundle, result));
771                 mCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
772             }
773         }
774 
775         @Override
onCaptureProcessProgressed(int progress)776         public void onCaptureProcessProgressed(int progress) {
777             mCaptureCallback.onCaptureProcessProgressed(progress);
778         }
779     }
780 
781     /**
782      * Monitors the extension metadata (extension strength, type) changes from the capture results.
783      */
784     private static class ExtensionMetadataMonitor {
785         private final @Nullable MutableLiveData<Integer> mCurrentExtensionTypeLiveData;
786         private final @Nullable MutableLiveData<Integer> mExtensionStrengthLiveData;
787 
ExtensionMetadataMonitor( @ullable MutableLiveData<Integer> currentExtensionTypeLiveData, @Nullable MutableLiveData<Integer> extensionStrengthLiveData)788         ExtensionMetadataMonitor(
789                 @Nullable MutableLiveData<Integer> currentExtensionTypeLiveData,
790                 @Nullable MutableLiveData<Integer> extensionStrengthLiveData) {
791             mCurrentExtensionTypeLiveData = currentExtensionTypeLiveData;
792             mExtensionStrengthLiveData = extensionStrengthLiveData;
793         }
794 
checkExtensionMetadata(Map<CaptureResult.Key, Object> captureResult)795         void checkExtensionMetadata(Map<CaptureResult.Key, Object> captureResult) {
796             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
797 
798                 if (mCurrentExtensionTypeLiveData != null) {
799                     // Monitors and update current extension type
800                     Object extensionType = captureResult.get(CaptureResult.EXTENSION_CURRENT_TYPE);
801                     // The returned type should be the value defined by the Camera2 API.
802                     // Needs to
803                     // convert it to the value defined by CameraX.
804                     if (extensionType != null && !Objects.equals(
805                             mCurrentExtensionTypeLiveData.getValue(),
806                             convertExtensionMode((int) extensionType))) {
807                         mCurrentExtensionTypeLiveData.postValue(
808                                 convertExtensionMode((int) extensionType));
809                     }
810                 }
811 
812                 if (mExtensionStrengthLiveData != null) {
813                     // Monitors and update current extension strength
814                     Object extensionStrength = captureResult.get(CaptureResult.EXTENSION_STRENGTH);
815                     if (extensionStrength != null && !Objects.equals(
816                             mExtensionStrengthLiveData.getValue(), extensionStrength)) {
817                         mExtensionStrengthLiveData.postValue((Integer) extensionStrength);
818                     }
819                 }
820             }
821         }
822 
823         @ExtensionMode.Mode
convertExtensionMode(int camera2ExtensionMode)824         private int convertExtensionMode(int camera2ExtensionMode) {
825             switch (camera2ExtensionMode) {
826                 case EXTENSION_AUTOMATIC:
827                     return ExtensionMode.AUTO;
828                 case EXTENSION_FACE_RETOUCH:
829                     return ExtensionMode.FACE_RETOUCH;
830                 case EXTENSION_BOKEH:
831                     return ExtensionMode.BOKEH;
832                 case EXTENSION_HDR:
833                     return ExtensionMode.HDR;
834                 case EXTENSION_NIGHT:
835                     return ExtensionMode.NIGHT;
836                 default:
837                     return ExtensionMode.NONE;
838             }
839         }
840     }
841 }
842