1 /**
2  * Copyright (c) 2020, 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 package com.android.cameraextensions;
17 
18 import android.app.Service;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.graphics.GraphicBuffer;
23 import android.graphics.Rect;
24 import android.hardware.HardwareBuffer;
25 import android.hardware.camera2.CameraAccessException;
26 import android.hardware.camera2.CameraCharacteristics;
27 import android.hardware.camera2.CameraExtensionCharacteristics;
28 import android.hardware.camera2.CameraManager;
29 import android.hardware.camera2.CaptureRequest;
30 import android.hardware.camera2.CaptureResult;
31 import android.hardware.camera2.TotalCaptureResult;
32 import android.hardware.camera2.extension.CameraOutputConfig;
33 import android.hardware.camera2.extension.CameraSessionConfig;
34 import android.hardware.camera2.extension.CaptureBundle;
35 import android.hardware.camera2.extension.CaptureFailure;
36 import android.hardware.camera2.extension.CaptureStageImpl;
37 import android.hardware.camera2.extension.IAdvancedExtenderImpl;
38 import android.hardware.camera2.extension.ICameraExtensionsProxyService;
39 import android.hardware.camera2.extension.ICaptureCallback;
40 import android.hardware.camera2.extension.ICaptureProcessorImpl;
41 import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
42 import android.hardware.camera2.extension.IImageProcessorImpl;
43 import android.hardware.camera2.extension.IInitializeSessionCallback;
44 import android.hardware.camera2.extension.IPreviewExtenderImpl;
45 import android.hardware.camera2.extension.IPreviewImageProcessorImpl;
46 import android.hardware.camera2.extension.IProcessResultImpl;
47 import android.hardware.camera2.extension.IRequestCallback;
48 import android.hardware.camera2.extension.IRequestProcessorImpl;
49 import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
50 import android.hardware.camera2.extension.ISessionProcessorImpl;
51 import android.hardware.camera2.extension.LatencyPair;
52 import android.hardware.camera2.extension.LatencyRange;
53 import android.hardware.camera2.extension.OutputConfigId;
54 import android.hardware.camera2.extension.OutputSurface;
55 import android.hardware.camera2.extension.ParcelCaptureResult;
56 import android.hardware.camera2.extension.ParcelImage;
57 import android.hardware.camera2.extension.ParcelTotalCaptureResult;
58 import android.hardware.camera2.extension.Request;
59 import android.hardware.camera2.extension.SizeList;
60 import android.hardware.camera2.impl.CameraMetadataNative;
61 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
62 import android.hardware.camera2.params.ColorSpaceProfiles;
63 import android.hardware.camera2.params.DynamicRangeProfiles;
64 import android.hardware.camera2.utils.SurfaceUtils;
65 import android.media.Image;
66 import android.media.ImageReader;
67 import android.os.Binder;
68 import android.os.ConditionVariable;
69 import android.os.Handler;
70 import android.os.HandlerExecutor;
71 import android.os.HandlerThread;
72 import android.os.IBinder;
73 import android.os.RemoteException;
74 import android.util.ArraySet;
75 import android.util.Log;
76 import android.util.Pair;
77 import android.util.Range;
78 import android.util.Size;
79 import android.view.Surface;
80 
81 import androidx.annotation.NonNull;
82 import androidx.annotation.Nullable;
83 import androidx.camera.extensions.impl.AutoImageCaptureExtenderImpl;
84 import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
85 import androidx.camera.extensions.impl.BeautyImageCaptureExtenderImpl;
86 import androidx.camera.extensions.impl.BeautyPreviewExtenderImpl;
87 import androidx.camera.extensions.impl.BokehImageCaptureExtenderImpl;
88 import androidx.camera.extensions.impl.BokehPreviewExtenderImpl;
89 import androidx.camera.extensions.impl.CaptureProcessorImpl;
90 import androidx.camera.extensions.impl.ExtensionVersionImpl;
91 import androidx.camera.extensions.impl.HdrImageCaptureExtenderImpl;
92 import androidx.camera.extensions.impl.HdrPreviewExtenderImpl;
93 import androidx.camera.extensions.impl.ImageCaptureExtenderImpl;
94 import androidx.camera.extensions.impl.InitializerImpl;
95 import androidx.camera.extensions.impl.NightImageCaptureExtenderImpl;
96 import androidx.camera.extensions.impl.NightPreviewExtenderImpl;
97 import androidx.camera.extensions.impl.PreviewExtenderImpl;
98 import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType;
99 import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
100 import androidx.camera.extensions.impl.ProcessResultImpl;
101 import androidx.camera.extensions.impl.ProcessorImpl;
102 import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
103 import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
104 import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
105 import androidx.camera.extensions.impl.advanced.BeautyAdvancedExtenderImpl;
106 import androidx.camera.extensions.impl.advanced.BokehAdvancedExtenderImpl;
107 import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl;
108 import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
109 import androidx.camera.extensions.impl.advanced.EyesFreeVideographyAdvancedExtenderImpl;
110 import androidx.camera.extensions.impl.advanced.HdrAdvancedExtenderImpl;
111 import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
112 import androidx.camera.extensions.impl.advanced.ImageReaderOutputConfigImpl;
113 import androidx.camera.extensions.impl.advanced.MultiResolutionImageReaderOutputConfigImpl;
114 import androidx.camera.extensions.impl.advanced.NightAdvancedExtenderImpl;
115 import androidx.camera.extensions.impl.advanced.OutputSurfaceConfigurationImpl;
116 import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
117 import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
118 import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
119 import androidx.camera.extensions.impl.advanced.SurfaceOutputConfigImpl;
120 
121 import com.android.internal.camera.flags.Flags;
122 
123 import java.io.IOException;
124 import java.util.ArrayList;
125 import java.util.Collections;
126 import java.util.HashMap;
127 import java.util.List;
128 import java.util.Map;
129 import java.util.concurrent.Future;
130 import java.util.concurrent.TimeUnit;
131 import java.util.concurrent.TimeoutException;
132 
133 public class CameraExtensionsProxyService extends Service {
134     private static final String TAG = "CameraExtensionsProxyService";
135 
136     private static final String CAMERA_EXTENSION_VERSION_NAME =
137             "androidx.camera.extensions.impl.ExtensionVersionImpl";
138     private static final String LATEST_VERSION = "1.5.0";
139     // No support for the init sequence
140     private static final String NON_INIT_VERSION_PREFIX = "1.0";
141     // Support advanced API and latency queries
142     private static final String ADVANCED_VERSION_PREFIX = "1.2";
143     // Support for the capture request & result APIs
144     private static final String RESULTS_VERSION_PREFIX = "1.3";
145     // Support for various latency improvements
146     private static final String LATENCY_VERSION_PREFIX = "1.4";
147     private static final String EFV_VERSION_PREFIX = "1.5";
148     private static final String GET_VERSION_PREFIX = "1.5";
149     private static final String[] ADVANCED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
150             LATENCY_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX,
151             GET_VERSION_PREFIX};
152     private static final String[] SUPPORTED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
153             LATENCY_VERSION_PREFIX, RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1",
154             NON_INIT_VERSION_PREFIX, GET_VERSION_PREFIX};
155     private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
156     private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
157             (new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
158     private static final boolean ESTIMATED_LATENCY_API_SUPPORTED = checkForLatencyAPI();
159     private static final boolean LATENCY_IMPROVEMENTS_SUPPORTED = EXTENSIONS_PRESENT &&
160             (EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
161                     (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX)));
162     private static final boolean EFV_SUPPORTED = EXTENSIONS_PRESENT &&
163             (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
164     private static final boolean GET_API_SUPPORTED = EXTENSIONS_PRESENT
165             && (EXTENSIONS_VERSION.startsWith(GET_VERSION_PREFIX));
166     private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI();
167     private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT &&
168             (!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX));
169     private static final boolean RESULT_API_SUPPORTED = EXTENSIONS_PRESENT &&
170             (EXTENSIONS_VERSION.startsWith(RESULTS_VERSION_PREFIX) ||
171             EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
172             EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
173 
174     private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
175     private CameraManager mCameraManager;
176 
checkForLatencyAPI()177     private static boolean checkForLatencyAPI() {
178         if (!EXTENSIONS_PRESENT) {
179             return false;
180         }
181 
182         for (String advancedVersions : ADVANCED_VERSION_PREFIXES) {
183             if (EXTENSIONS_VERSION.startsWith(advancedVersions)) {
184                 return true;
185             }
186         }
187 
188         return false;
189     }
190 
checkForAdvancedAPI()191     private static boolean checkForAdvancedAPI() {
192         if (!checkForLatencyAPI()) {
193             return false;
194         }
195 
196         try {
197             return (new ExtensionVersionImpl()).isAdvancedExtenderImplemented();
198         } catch (NoSuchMethodError e) {
199             // This could happen in case device specific extension implementations are using
200             // an older extension API but incorrectly set the extension version.
201         }
202 
203         return false;
204     }
205 
checkForExtensions()206     private static boolean checkForExtensions() {
207         try {
208             Class.forName(CAMERA_EXTENSION_VERSION_NAME);
209         } catch (ClassNotFoundException e) {
210             return false;
211         }
212 
213         String extensionVersion = (new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION);
214         for (String supportedVersion : SUPPORTED_VERSION_PREFIXES) {
215             if (extensionVersion.startsWith(supportedVersion)) {
216                 return true;
217             }
218         }
219 
220         return false;
221     }
222 
223     /**
224      * A per-process global camera extension manager instance, to track and
225      * initialize/release extensions depending on client activity.
226      */
227     private static final class CameraExtensionManagerGlobal implements IBinder.DeathRecipient {
228         private static final String TAG = "CameraExtensionManagerGlobal";
229         private final int EXTENSION_DELAY_MS = 1000;
230 
231         private final Handler mHandler;
232         private final HandlerThread mHandlerThread;
233         private final Object mLock = new Object();
234 
235         private ArraySet<IBinder> mActiveClients = new ArraySet<>();
236         private HashMap<IBinder, ArraySet<IBinder.DeathRecipient>> mClientDeathRecipient =
237                 new HashMap<>();
238         private IInitializeSessionCallback mInitializeCb = null;
239 
240         // Singleton instance
241         private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
242                 new CameraExtensionManagerGlobal();
243 
244         // Singleton, don't allow construction
CameraExtensionManagerGlobal()245         private CameraExtensionManagerGlobal() {
246             mHandlerThread = new HandlerThread(TAG);
247             mHandlerThread.start();
248             mHandler = new Handler(mHandlerThread.getLooper());
249         }
250 
251         private final static class InitializeHandler
252                 implements InitializerImpl.OnExtensionsInitializedCallback {
253             private final InitializerFuture mStatusFuture;
254 
InitializeHandler(InitializerFuture statusFuture)255             public InitializeHandler(InitializerFuture statusFuture) {
256                 mStatusFuture = statusFuture;
257             }
258 
259             @Override
onSuccess()260             public void onSuccess() {
261                 mStatusFuture.setStatus(true);
262             }
263 
264             @Override
onFailure(int error)265             public void onFailure(int error) {
266                 mStatusFuture.setStatus(false);
267             }
268         }
269 
270         private final static class ReleaseHandler
271                 implements InitializerImpl.OnExtensionsDeinitializedCallback {
272             private final InitializerFuture mStatusFuture;
273 
ReleaseHandler(InitializerFuture statusFuture)274             public ReleaseHandler(InitializerFuture statusFuture) {
275                 mStatusFuture = statusFuture;
276             }
277 
onSuccess()278             @Override public void onSuccess() {
279                 mStatusFuture.setStatus(true);
280             }
281 
282             @Override
onFailure(int i)283             public void onFailure(int i) {
284                 mStatusFuture.setStatus(false);
285             }
286         }
287 
288         private static class InitializerFuture implements Future<Boolean> {
289             private volatile Boolean mStatus;
290             ConditionVariable mCondVar = new ConditionVariable(/*opened*/false);
291 
setStatus(boolean status)292             public void setStatus(boolean status) {
293                 mStatus = status;
294                 mCondVar.open();
295             }
296 
297             @Override
cancel(boolean mayInterruptIfRunning)298             public boolean cancel(boolean mayInterruptIfRunning) {
299                 return false; // don't allow canceling this task
300             }
301 
302             @Override
isCancelled()303             public boolean isCancelled() {
304                 return false; // can never cancel this task
305             }
306 
307             @Override
isDone()308             public boolean isDone() {
309                 return mStatus != null;
310             }
311 
312             @Override
get()313             public Boolean get() {
314                 mCondVar.block();
315                 return mStatus;
316             }
317 
318             @Override
get(long timeout, TimeUnit unit)319             public Boolean get(long timeout, TimeUnit unit) throws TimeoutException {
320                 long timeoutMs = unit.convert(timeout, TimeUnit.MILLISECONDS);
321                 if (!mCondVar.block(timeoutMs)) {
322                     throw new TimeoutException(
323                             "Failed to receive status after " + timeout + " " + unit);
324                 }
325 
326                 if (mStatus == null) {
327                     throw new AssertionError();
328                 }
329                 return mStatus;
330             }
331 
332         }
333 
get()334         public static CameraExtensionManagerGlobal get() {
335             return GLOBAL_CAMERA_MANAGER;
336         }
337 
registerClient(Context ctx, IBinder token)338         public boolean registerClient(Context ctx, IBinder token) {
339             synchronized (mLock) {
340                 if (mActiveClients.contains(token)) {
341                     Log.e(TAG, "Failed to register existing client!");
342                     return false;
343                 }
344 
345                 try {
346                     token.linkToDeath(this, 0);
347                 } catch (RemoteException e) {
348                     Log.e(TAG, "Failed to link to binder token!");
349                     return false;
350                 }
351 
352                 if (INIT_API_SUPPORTED) {
353                     if (mActiveClients.isEmpty()) {
354                         InitializerFuture status = new InitializerFuture();
355                         InitializerImpl.init(LATEST_VERSION, ctx, new InitializeHandler(status),
356                                 new HandlerExecutor(mHandler));
357                         boolean initSuccess;
358                         try {
359                             initSuccess = status.get(EXTENSION_DELAY_MS,
360                                     TimeUnit.MILLISECONDS);
361                         } catch (TimeoutException e) {
362                             Log.e(TAG, "Timed out while initializing camera extensions!");
363                             return false;
364                         }
365                         if (!initSuccess) {
366                             Log.e(TAG, "Failed while initializing camera extensions!");
367                             return false;
368                         }
369                     }
370                 }
371 
372                 mActiveClients.add(token);
373                 mClientDeathRecipient.put(token, new ArraySet<>());
374 
375                 return true;
376             }
377         }
378 
unregisterClient(IBinder token)379         public void unregisterClient(IBinder token) {
380             synchronized (mLock) {
381                 if (mActiveClients.remove(token)) {
382                     token.unlinkToDeath(this, 0);
383                     mClientDeathRecipient.remove(token);
384                     if (mActiveClients.isEmpty() && INIT_API_SUPPORTED) {
385                         InitializerFuture status = new InitializerFuture();
386                         InitializerImpl.deinit(new ReleaseHandler(status),
387                                 new HandlerExecutor(mHandler));
388                         boolean releaseSuccess;
389                         try {
390                             releaseSuccess = status.get(EXTENSION_DELAY_MS, TimeUnit.MILLISECONDS);
391                         } catch (TimeoutException e) {
392                             Log.e(TAG, "Timed out while releasing camera extensions!");
393                             return;
394                         }
395                         if (!releaseSuccess) {
396                             Log.e(TAG, "Failed while releasing camera extensions!");
397                         }
398                     }
399                 }
400             }
401         }
402 
403         @Override
binderDied()404         public void binderDied() {
405             // Do nothing, handled below
406         }
407 
408         @Override
binderDied(@onNull IBinder who)409         public void binderDied(@NonNull IBinder who) {
410             synchronized (mLock) {
411                 if (mClientDeathRecipient.containsKey(who)) {
412                     mClientDeathRecipient.get(who).stream().forEach(
413                             recipient -> recipient.binderDied(who));
414                 }
415                 unregisterClient(who);
416             }
417         }
418 
registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient)419         public void registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
420             synchronized (mLock) {
421                 if (mClientDeathRecipient.containsKey(token)) {
422                     ArraySet<IBinder.DeathRecipient> recipients = mClientDeathRecipient.get(token);
423                     recipients.add(recipient);
424                 }
425             }
426         }
427 
unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient)428         public void unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
429             synchronized (mLock) {
430                 if (mClientDeathRecipient.containsKey(token)) {
431                     ArraySet<IBinder.DeathRecipient> recipients = mClientDeathRecipient.get(token);
432                     recipients.remove(recipient);
433                 }
434             }
435         }
436 
437         private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
438             @Override
439             public void binderDied() {
440                 synchronized (mLock) {
441                     mInitializeCb = null;
442                 }
443             }
444         };
445 
initializeSession(IInitializeSessionCallback cb)446         public boolean initializeSession(IInitializeSessionCallback cb) {
447             synchronized (mLock) {
448                 if (mInitializeCb == null) {
449                     mInitializeCb = cb;
450                     try {
451                         mInitializeCb.asBinder().linkToDeath(mDeathRecipient, 0);
452                     } catch (RemoteException e) {
453                         e.printStackTrace();
454                     }
455                 } else {
456                     return false;
457                 }
458             }
459             return true;
460         }
461 
releaseSession()462         public void releaseSession() {
463             synchronized (mLock) {
464                 if (mInitializeCb != null) {
465                     mInitializeCb.asBinder().unlinkToDeath(mDeathRecipient, 0);
466                     mInitializeCb = null;
467                 }
468             }
469         }
470     }
471 
472     /**
473      * @hide
474      */
registerClient(Context ctx, IBinder token)475     private static boolean registerClient(Context ctx, IBinder token) {
476         if (!EXTENSIONS_PRESENT) {
477             return false;
478         }
479         return CameraExtensionManagerGlobal.get().registerClient(ctx, token);
480     }
481 
482     /**
483      * @hide
484      */
unregisterClient(IBinder token)485     public static void unregisterClient(IBinder token) {
486         if (!EXTENSIONS_PRESENT) {
487             return;
488         }
489         CameraExtensionManagerGlobal.get().unregisterClient(token);
490     }
491 
492     /**
493      * @hide
494      */
registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient)495     private static void registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
496         CameraExtensionManagerGlobal.get().registerDeathRecipient(token, recipient);
497     }
498 
499     /**
500      * @hide
501      */
unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient)502     private static void unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
503         CameraExtensionManagerGlobal.get().unregisterDeathRecipient(token, recipient);
504     }
505 
506     /**
507      * @hide
508      */
initializeSession(IInitializeSessionCallback cb)509     public static boolean initializeSession(IInitializeSessionCallback cb) {
510         if (!EXTENSIONS_PRESENT) {
511             return false;
512         }
513         return CameraExtensionManagerGlobal.get().initializeSession(cb);
514     }
515 
516     /**
517      * @hide
518      */
releaseSession()519     public static void releaseSession() {
520         if (!EXTENSIONS_PRESENT) {
521             return;
522         }
523         CameraExtensionManagerGlobal.get().releaseSession();
524     }
525 
526     /**
527      * @hide
528      */
initializeExtension( int extensionType)529     public static Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> initializeExtension(
530             int extensionType) {
531         if (Flags.concertModeApi()) {
532             if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
533                 // Basic extensions are deprecated starting with extension version 1.5
534                 return new Pair<>(new PreviewExtenderImpl() {
535                     @Override
536                     public boolean isExtensionAvailable(String cameraId,
537                             CameraCharacteristics cameraCharacteristics) {
538                         return false;
539                     }
540 
541                     @Override
542                     public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
543 
544                     }
545 
546                     @Override
547                     public androidx.camera.extensions.impl.CaptureStageImpl getCaptureStage() {
548                         return null;
549                     }
550 
551                     @Override
552                     public ProcessorType getProcessorType() {
553                         return null;
554                     }
555 
556                     @Override
557                     public ProcessorImpl getProcessor() {
558                         return null;
559                     }
560 
561                     @Nullable
562                     @Override
563                     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
564                         return null;
565                     }
566 
567                     @Override
568                     public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
569                             Context context) { }
570 
571                     @Override
572                     public void onDeInit() { }
573 
574                     @Override
575                     public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
576                         return null;
577                     }
578 
579                     @Override
580                     public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
581                         return null;
582                     }
583 
584                     @Override
585                     public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
586                         return null;
587                     }
588 
589                     @Override
590                     public int onSessionType() {
591                         return 0;
592                     }
593                 }, new ImageCaptureExtenderImpl() {
594                     @Override
595                     public boolean isExtensionAvailable(String cameraId,
596                             CameraCharacteristics cameraCharacteristics) {
597                         return false;
598                     }
599 
600                     @Override
601                     public void init(String cameraId,
602                             CameraCharacteristics cameraCharacteristics) { }
603 
604                     @Override
605                     public CaptureProcessorImpl getCaptureProcessor() {
606                         return null;
607                     }
608 
609                     @Override
610                     public
611                     List<androidx.camera.extensions.impl.CaptureStageImpl> getCaptureStages() {
612                         return null;
613                     }
614 
615                     @Override
616                     public int getMaxCaptureStage() {
617                         return 0;
618                     }
619 
620                     @Override
621                     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
622                         return null;
623                     }
624 
625                     @Override
626                     public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(
627                             Size captureSize) {
628                         return null;
629                     }
630 
631                     @Override
632                     public Range<Long> getEstimatedCaptureLatencyRange(
633                             Size captureOutputSize) {
634                         return null;
635                     }
636 
637                     @Override
638                     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
639                         return null;
640                     }
641 
642                     @Override
643                     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
644                         return null;
645                     }
646 
647                     @Override
648                     public boolean isCaptureProcessProgressAvailable() {
649                         return false;
650                     }
651 
652                     @Override
653                     public Pair<Long, Long> getRealtimeCaptureLatency() {
654                         return null;
655                     }
656 
657                     @Override
658                     public boolean isPostviewAvailable() {
659                         return false;
660                     }
661 
662                     @Override
663                     public void onInit(String cameraId,
664                             CameraCharacteristics cameraCharacteristics, Context context) { }
665 
666                     @Override
667                     public void onDeInit() { }
668 
669                     @Override
670                     public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
671                         return null;
672                     }
673 
674                     @Override
675                     public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
676                         return null;
677                     }
678 
679                     @Override
680                     public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
681                         return null;
682                     }
683 
684                     @Override
685                     public int onSessionType() {
686                         return 0;
687                     }
688                 });
689             }
690         }
691 
692         switch (extensionType) {
693             case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
694                 return new Pair<>(new AutoPreviewExtenderImpl(),
695                         new AutoImageCaptureExtenderImpl());
696             case CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH:
697                 return new Pair<>(new BeautyPreviewExtenderImpl(),
698                         new BeautyImageCaptureExtenderImpl());
699             case CameraExtensionCharacteristics.EXTENSION_BOKEH:
700                 return new Pair<>(new BokehPreviewExtenderImpl(),
701                         new BokehImageCaptureExtenderImpl());
702             case CameraExtensionCharacteristics.EXTENSION_HDR:
703                 return new Pair<>(new HdrPreviewExtenderImpl(), new HdrImageCaptureExtenderImpl());
704             case CameraExtensionCharacteristics.EXTENSION_NIGHT:
705                 return new Pair<>(new NightPreviewExtenderImpl(),
706                         new NightImageCaptureExtenderImpl());
707             default:
708                 throw new IllegalArgumentException("Unknown extension: " + extensionType);
709         }
710     }
711 
712     /**
713      * @hide
714      */
715     public static AdvancedExtenderImpl initializeAdvancedExtensionImpl(int extensionType) {
716         if (Flags.concertModeApi()) {
717             if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
718                 if (EFV_SUPPORTED) {
719                     return new EyesFreeVideographyAdvancedExtenderImpl();
720                 } else {
721                     return new AdvancedExtenderImpl() {
722                         @Override
723                         public boolean isExtensionAvailable(String cameraId,
724                                 Map<String, CameraCharacteristics> characteristicsMap) {
725                             return false;
726                         }
727 
728                         @Override
729                         public void init(String cameraId,
730                                 Map<String, CameraCharacteristics> characteristicsMap) {
731 
732                         }
733 
734                         @Override
735                         public Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
736                                 Size captureOutputSize, int imageFormat) {
737                             return null;
738                         }
739 
740                         @Override
741                         public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
742                                 String cameraId) {
743                             return null;
744                         }
745 
746                         @Override
747                         public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
748                                 String cameraId) {
749                             return null;
750                         }
751 
752                         @Override
753                         public Map<Integer, List<Size>> getSupportedPostviewResolutions(
754                                 Size captureSize) {
755                             return null;
756                         }
757 
758                         @Override
759                         public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
760                             return null;
761                         }
762 
763                         @Override
764                         public SessionProcessorImpl createSessionProcessor() {
765                             return null;
766                         }
767 
768                         @Override
769                         public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
770                             return null;
771                         }
772 
773                         @Override
774                         public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
775                             return null;
776                         }
777 
778                         @Override
779                         public boolean isCaptureProcessProgressAvailable() {
780                             return false;
781                         }
782 
783                         @Override
784                         public boolean isPostviewAvailable() {
785                             return false;
786                         }
787 
788                         @Override
789                         public List<Pair<CameraCharacteristics.Key, Object>>
790                                 getAvailableCharacteristicsKeyValues() {
791                             return Collections.emptyList();
792                         }
793                     };
794                 }
795             }
796         }
797 
798         switch (extensionType) {
799             case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
800                 return new AutoAdvancedExtenderImpl();
801             case CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH:
802                 return new BeautyAdvancedExtenderImpl();
803             case CameraExtensionCharacteristics.EXTENSION_BOKEH:
804                 return new BokehAdvancedExtenderImpl();
805             case CameraExtensionCharacteristics.EXTENSION_HDR:
806                 return new HdrAdvancedExtenderImpl();
807             case CameraExtensionCharacteristics.EXTENSION_NIGHT:
808                 return new NightAdvancedExtenderImpl();
809             default:
810                 throw new IllegalArgumentException("Unknown extension: " + extensionType);
811         }
812     }
813 
814     @Override
815     public void onCreate() {
816         super.onCreate();
817         // This will setup the camera vendor tag descriptor in the service process
818         // along with all camera characteristics.
819         try {
820             mCameraManager = getSystemService(CameraManager.class);
821 
822             String [] cameraIds = mCameraManager.getCameraIdListNoLazy();
823             if (cameraIds != null) {
824                 for (String cameraId : cameraIds) {
825                     CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
826                     Object thisClass = CameraCharacteristics.Key.class;
827                     Class<CameraCharacteristics.Key<?>> keyClass =
828                             (Class<CameraCharacteristics.Key<?>>)thisClass;
829                     ArrayList<CameraCharacteristics.Key<?>> vendorKeys =
830                             chars.getNativeMetadata().getAllVendorKeys(keyClass);
831                     if ((vendorKeys != null) && !vendorKeys.isEmpty()) {
832                         mMetadataVendorIdMap.put(cameraId, vendorKeys.get(0).getVendorId());
833                     }
834                 }
835             }
836         } catch (CameraAccessException e) {
837             Log.e(TAG, "Failed to query camera characteristics!");
838         }
839     }
840 
841     @Override
842     public void onDestroy() {
843         super.onDestroy();
844     }
845 
846 
847     @Override
848     public IBinder onBind(Intent intent) {
849         return new CameraExtensionsProxyServiceStub();
850     }
851 
852     private static List<SizeList> initializeParcelable(
853             List<Pair<Integer, android.util.Size[]>> sizes) {
854         if (sizes == null) {
855             return null;
856         }
857         ArrayList<SizeList> ret = new ArrayList<>(sizes.size());
858         for (Pair<Integer, Size[]> entry : sizes) {
859             SizeList sizeList = new SizeList();
860             sizeList.format = entry.first;
861             sizeList.sizes = new ArrayList<>();
862             for (android.util.Size size : entry.second) {
863                 android.hardware.camera2.extension.Size sz =
864                         new android.hardware.camera2.extension.Size();
865                 sz.width = size.getWidth();
866                 sz.height = size.getHeight();
867                 sizeList.sizes.add(sz);
868             }
869 
870             if (!sizeList.sizes.isEmpty()) {
871                 ret.add(sizeList);
872             }
873         }
874 
875         return ret;
876     }
877 
878     private static Map<String, CameraCharacteristics> getCharacteristicsMap(
879             Map<String, CameraMetadataNative> charsMap) {
880         HashMap<String, CameraCharacteristics> ret = new HashMap<>();
881         for (Map.Entry<String, CameraMetadataNative> entry : charsMap.entrySet()) {
882             ret.put(entry.getKey(), new CameraCharacteristics(entry.getValue()));
883         }
884         return ret;
885     }
886 
887     private static List<SizeList> initializeParcelable(
888             Map<Integer, List<android.util.Size>> sizes) {
889         if (sizes == null) {
890             return null;
891         }
892         ArrayList<SizeList> ret = new ArrayList<>(sizes.size());
893         for (Map.Entry<Integer, List<android.util.Size>> entry : sizes.entrySet()) {
894             SizeList sizeList = new SizeList();
895             sizeList.format = entry.getKey();
896             sizeList.sizes = new ArrayList<>();
897             for (android.util.Size size : entry.getValue()) {
898                 android.hardware.camera2.extension.Size sz =
899                         new android.hardware.camera2.extension.Size();
900                 sz.width = size.getWidth();
901                 sz.height = size.getHeight();
902                 sizeList.sizes.add(sz);
903             }
904             ret.add(sizeList);
905         }
906 
907         return ret;
908     }
909 
910     private CameraMetadataNative initializeParcelableMetadata(
911             List<Pair<CaptureRequest.Key, Object>> paramList, String cameraId) {
912         if (paramList == null) {
913             return null;
914         }
915 
916         CameraMetadataNative ret = new CameraMetadataNative();
917         if (mMetadataVendorIdMap.containsKey(cameraId)) {
918             ret.setVendorId(mMetadataVendorIdMap.get(cameraId));
919         }
920         for (Pair<CaptureRequest.Key, Object> param : paramList) {
921             ret.set(param.first, param.second);
922         }
923 
924         return ret;
925     }
926 
927     private CameraMetadataNative initializeParcelableMetadata(
928             Map<CaptureRequest.Key<?>, Object> paramMap, String cameraId) {
929         if (paramMap == null) {
930             return null;
931         }
932 
933         CameraMetadataNative ret = new CameraMetadataNative();
934         if (mMetadataVendorIdMap.containsKey(cameraId)) {
935             ret.setVendorId(mMetadataVendorIdMap.get(cameraId));
936         }
937         for (Map.Entry<CaptureRequest.Key<?>, Object> param : paramMap.entrySet()) {
938             ret.set(((CaptureRequest.Key) param.getKey()), param.getValue());
939         }
940 
941         return ret;
942     }
943 
944     private android.hardware.camera2.extension.CaptureStageImpl initializeParcelable(
945             androidx.camera.extensions.impl.CaptureStageImpl captureStage, String cameraId) {
946         if (captureStage == null) {
947             return null;
948         }
949 
950         android.hardware.camera2.extension.CaptureStageImpl ret =
951                 new android.hardware.camera2.extension.CaptureStageImpl();
952         ret.id = captureStage.getId();
953         ret.parameters = initializeParcelableMetadata(captureStage.getParameters(), cameraId);
954 
955         return ret;
956     }
957 
958     private Request initializeParcelable(RequestProcessorImpl.Request request, int requestId,
959             String cameraId) {
960         Request ret = new Request();
961         ret.targetOutputConfigIds = new ArrayList<>();
962         for (int id : request.getTargetOutputConfigIds()) {
963             OutputConfigId configId = new OutputConfigId();
964             configId.id = id;
965             ret.targetOutputConfigIds.add(configId);
966         }
967         ret.templateId = request.getTemplateId();
968         ret.parameters = initializeParcelableMetadata(request.getParameters(), cameraId);
969         ret.requestId = requestId;
970         return ret;
971     }
972 
973     private class CameraExtensionsProxyServiceStub extends ICameraExtensionsProxyService.Stub {
974         @Override
975         public boolean registerClient(IBinder token) {
976             return CameraExtensionsProxyService.registerClient(CameraExtensionsProxyService.this,
977                     token);
978         }
979 
980         @Override
981         public void unregisterClient(IBinder token) {
982             CameraExtensionsProxyService.unregisterClient(token);
983         }
984 
985         private boolean checkCameraPermission() {
986             int allowed = CameraExtensionsProxyService.this.checkPermission(
987                     android.Manifest.permission.CAMERA, Binder.getCallingPid(),
988                     Binder.getCallingUid());
989             return (PackageManager.PERMISSION_GRANTED == allowed);
990         }
991 
992         @Override
993         public void initializeSession(IInitializeSessionCallback cb) {
994             try {
995                 if (!checkCameraPermission()) {
996                     Log.i(TAG, "Camera permission required for initializing capture session");
997                     cb.onFailure();
998                     return;
999                 }
1000 
1001                 if (CameraExtensionsProxyService.initializeSession(cb)) {
1002                     cb.onSuccess();
1003                 } else {
1004                     cb.onFailure();
1005                 }
1006             } catch (RemoteException e) {
1007                 Log.e(TAG, "Client doesn't respond!");
1008             }
1009         }
1010 
1011         @Override
1012         public void releaseSession() {
1013             if (checkCameraPermission()) {
1014                 CameraExtensionsProxyService.releaseSession();
1015             }
1016         }
1017 
1018         @Override
1019         public boolean advancedExtensionsSupported() {
1020             return ADVANCED_API_SUPPORTED;
1021         }
1022 
1023         @Override
1024         public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType) {
1025             AdvancedExtenderImpl extension;
1026             try {
1027                 extension = initializeAdvancedExtensionImpl(extensionType);
1028             } catch (IllegalArgumentException e) {
1029                 return null;
1030             }
1031 
1032             return new AdvancedExtenderImplStub(extension);
1033         }
1034 
1035         @Override
1036         public IPreviewExtenderImpl initializePreviewExtension(int extensionType) {
1037             Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> extension;
1038             try {
1039                 extension = initializeExtension(extensionType);
1040             } catch (IllegalArgumentException e) {
1041                 return null;
1042             }
1043 
1044             return new PreviewExtenderImplStub(extension.first);
1045         }
1046 
1047         @Override
1048         public IImageCaptureExtenderImpl initializeImageExtension(int extensionType) {
1049             Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> extension;
1050             try {
1051                 extension = initializeExtension(extensionType);
1052             } catch (IllegalArgumentException e) {
1053                 return null;
1054             }
1055 
1056             return new ImageCaptureExtenderImplStub(extension.second);
1057         }
1058     }
1059 
1060     private class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub {
1061         private final AdvancedExtenderImpl mAdvancedExtender;
1062 
1063         public AdvancedExtenderImplStub(AdvancedExtenderImpl advancedExtender) {
1064             mAdvancedExtender = advancedExtender;
1065         }
1066 
1067         @Override
1068         public boolean isExtensionAvailable(String cameraId,
1069                 Map<String, CameraMetadataNative> charsMapNative) {
1070             return mAdvancedExtender.isExtensionAvailable(cameraId,
1071                     getCharacteristicsMap(charsMapNative));
1072         }
1073 
1074         @Override
1075         public void init(String cameraId, Map<String, CameraMetadataNative> charsMapNative) {
1076             mAdvancedExtender.init(cameraId, getCharacteristicsMap(charsMapNative));
1077         }
1078 
1079         @Override
1080         public List<SizeList> getSupportedPostviewResolutions(
1081                 android.hardware.camera2.extension.Size captureSize) {
1082             Size sz = new Size(captureSize.width, captureSize.height);
1083             Map<Integer, List<Size>> supportedSizesMap =
1084                     mAdvancedExtender.getSupportedPostviewResolutions(sz);
1085             if (supportedSizesMap != null) {
1086                 return initializeParcelable(supportedSizesMap);
1087             }
1088 
1089             return null;
1090         }
1091 
1092         @Override
1093         public List<SizeList> getSupportedPreviewOutputResolutions(String cameraId) {
1094             Map<Integer, List<Size>> supportedSizesMap =
1095                     mAdvancedExtender.getSupportedPreviewOutputResolutions(cameraId);
1096             if (supportedSizesMap != null) {
1097                 return initializeParcelable(supportedSizesMap);
1098             }
1099 
1100             return null;
1101         }
1102 
1103         @Override
1104         public List<SizeList> getSupportedCaptureOutputResolutions(String cameraId) {
1105             Map<Integer, List<Size>> supportedSizesMap =
1106                     mAdvancedExtender.getSupportedCaptureOutputResolutions(cameraId);
1107             if (supportedSizesMap != null) {
1108                 return initializeParcelable(supportedSizesMap);
1109             }
1110 
1111             return null;
1112         }
1113 
1114         @Override
1115         public LatencyRange getEstimatedCaptureLatencyRange(String cameraId,
1116                 android.hardware.camera2.extension.Size outputSize, int format) {
1117             Size sz = new Size(outputSize.width, outputSize.height);
1118             Range<Long> latencyRange = mAdvancedExtender.getEstimatedCaptureLatencyRange(cameraId,
1119                     sz, format);
1120             if (latencyRange != null) {
1121                 LatencyRange ret = new LatencyRange();
1122                 ret.min = latencyRange.getLower();
1123                 ret.max = latencyRange.getUpper();
1124                 return ret;
1125             }
1126 
1127             return null;
1128         }
1129 
1130         @Override
1131         public ISessionProcessorImpl getSessionProcessor() {
1132             return new SessionProcessorImplStub(mAdvancedExtender.createSessionProcessor());
1133         }
1134 
1135         @Override
1136         public CameraMetadataNative getAvailableCaptureRequestKeys(String cameraId) {
1137             if (RESULT_API_SUPPORTED) {
1138                 List<CaptureRequest.Key> supportedCaptureKeys =
1139                         mAdvancedExtender.getAvailableCaptureRequestKeys();
1140 
1141                 if ((supportedCaptureKeys != null) && !supportedCaptureKeys.isEmpty()) {
1142                     CameraMetadataNative ret = new CameraMetadataNative();
1143                     long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
1144                             mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
1145                     ret.setVendorId(vendorId);
1146                     int requestKeyTags [] = new int[supportedCaptureKeys.size()];
1147                     int i = 0;
1148                     for (CaptureRequest.Key key : supportedCaptureKeys) {
1149                         requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
1150                     }
1151                     ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags);
1152 
1153                     return ret;
1154                 }
1155             }
1156 
1157             return null;
1158         }
1159 
1160         @Override
1161         public CameraMetadataNative getAvailableCaptureResultKeys(String cameraId) {
1162             if (RESULT_API_SUPPORTED) {
1163                 List<CaptureResult.Key> supportedResultKeys =
1164                         mAdvancedExtender.getAvailableCaptureResultKeys();
1165 
1166                 if ((supportedResultKeys != null) && !supportedResultKeys.isEmpty()) {
1167                     CameraMetadataNative ret = new CameraMetadataNative();
1168                     long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
1169                             mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
1170                     ret.setVendorId(vendorId);
1171                     int resultKeyTags [] = new int[supportedResultKeys.size()];
1172                     int i = 0;
1173                     for (CaptureResult.Key key : supportedResultKeys) {
1174                         resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
1175                     }
1176                     ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags);
1177 
1178                     return ret;
1179                 }
1180             }
1181 
1182             return null;
1183         }
1184 
1185         @Override
1186         public boolean isCaptureProcessProgressAvailable() {
1187             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1188                 return mAdvancedExtender.isCaptureProcessProgressAvailable();
1189             }
1190 
1191             return false;
1192         }
1193 
1194         @Override
1195         public boolean isPostviewAvailable() {
1196             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1197                 return mAdvancedExtender.isPostviewAvailable();
1198             }
1199 
1200             return false;
1201         }
1202 
1203         @Override
1204         public CameraMetadataNative getAvailableCharacteristicsKeyValues(String cameraId) {
1205             if (GET_API_SUPPORTED) {
1206                 List<Pair<CameraCharacteristics.Key, Object>> entries =
1207                         mAdvancedExtender.getAvailableCharacteristicsKeyValues();
1208 
1209                 if (entries == null || entries.isEmpty()) {
1210                     throw new RuntimeException("A valid set of key/value pairs are required that "
1211                             + "are supported by the extension.");
1212                 }
1213 
1214                 CameraMetadataNative ret = new CameraMetadataNative();
1215                 long vendorId = mMetadataVendorIdMap.containsKey(cameraId)
1216                         ? mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
1217                 ret.setVendorId(vendorId);
1218                 int[] characteristicsKeyTags = new int[entries.size()];
1219                 int i = 0;
1220                 for (Pair<CameraCharacteristics.Key, Object> entry : entries) {
1221                     int tag = CameraMetadataNative.getTag(entry.first.getName(), vendorId);
1222                     characteristicsKeyTags[i++] = tag;
1223                     ret.set(entry.first, entry.second);
1224                 }
1225                 ret.set(CameraCharacteristics.REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
1226                         characteristicsKeyTags);
1227 
1228                 return ret;
1229             }
1230 
1231             return null;
1232         }
1233     }
1234 
1235     private class CaptureCallbackStub implements SessionProcessorImpl.CaptureCallback {
1236         private final ICaptureCallback mCaptureCallback;
1237         private final String mCameraId;
1238 
1239         private CaptureCallbackStub(ICaptureCallback captureCallback, String cameraId) {
1240             mCaptureCallback = captureCallback;
1241             mCameraId = cameraId;
1242         }
1243 
1244         @Override
1245         public void onCaptureStarted(int captureSequenceId, long timestamp) {
1246             if (mCaptureCallback != null) {
1247                 try {
1248                     mCaptureCallback.onCaptureStarted(captureSequenceId, timestamp);
1249                 } catch (RemoteException e) {
1250                     Log.e(TAG, "Failed to notify capture start due to remote " +
1251                             "exception!");
1252                 }
1253             }
1254         }
1255 
1256         @Override
1257         public void onCaptureProcessStarted(int captureSequenceId) {
1258             if (mCaptureCallback != null) {
1259                 try {
1260                     mCaptureCallback.onCaptureProcessStarted(captureSequenceId);
1261                 } catch (RemoteException e) {
1262                     Log.e(TAG, "Failed to notify capture process start due to remote " +
1263                             "exception!");
1264                 }
1265             }
1266         }
1267 
1268         @Override
1269         public void onCaptureFailed(int captureSequenceId) {
1270             if (mCaptureCallback != null) {
1271                 try {
1272                     mCaptureCallback.onCaptureFailed(captureSequenceId);
1273                 } catch (RemoteException e) {
1274                     Log.e(TAG, "Failed to notify capture failure due to remote " +
1275                             "exception!");
1276                 }
1277             }
1278         }
1279 
1280         @Override
1281         public void onCaptureFailed(int captureSequenceId, int reason) {
1282             if (Flags.concertMode()) {
1283                 if (mCaptureCallback != null) {
1284                     try {
1285                         mCaptureCallback.onCaptureProcessFailed(captureSequenceId, reason);
1286                     } catch (RemoteException e) {
1287                         Log.e(TAG, "Failed to notify capture failure due to remote " +
1288                                 "exception!");
1289                     }
1290                 }
1291             }
1292         }
1293 
1294         @Override
1295         public void onCaptureSequenceCompleted(int captureSequenceId) {
1296             if (mCaptureCallback != null) {
1297                 try {
1298                     mCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
1299                 } catch (RemoteException e) {
1300                     Log.e(TAG, "Failed to notify capture sequence end due to remote " +
1301                             "exception!");
1302                 }
1303             }
1304         }
1305 
1306         @Override
1307         public void onCaptureSequenceAborted(int captureSequenceId) {
1308             if (mCaptureCallback != null) {
1309                 try {
1310                     mCaptureCallback.onCaptureSequenceAborted(captureSequenceId);
1311                 } catch (RemoteException e) {
1312                     Log.e(TAG, "Failed to notify capture sequence abort due to remote " +
1313                             "exception!");
1314                 }
1315             }
1316         }
1317 
1318         @Override
1319         public void onCaptureCompleted(long timestamp, int requestId,
1320                 Map<CaptureResult.Key, Object> result) {
1321 
1322             if (result == null) {
1323                 Log.e(TAG, "Invalid capture result received!");
1324             }
1325 
1326             CameraMetadataNative captureResults = new CameraMetadataNative();
1327             if (mMetadataVendorIdMap.containsKey(mCameraId)) {
1328                 captureResults.setVendorId(mMetadataVendorIdMap.get(mCameraId));
1329             }
1330             for (Map.Entry<CaptureResult.Key, Object> entry : result.entrySet()) {
1331                 captureResults.set(entry.getKey(), entry.getValue());
1332             }
1333 
1334             try {
1335                 mCaptureCallback.onCaptureCompleted(timestamp, requestId, captureResults);
1336             } catch (RemoteException e) {
1337                 Log.e(TAG, "Failed to notify capture complete due to remote exception!");
1338             }
1339         }
1340 
1341         @Override
1342         public void onCaptureProcessProgressed(int progress) {
1343             try {
1344                 mCaptureCallback.onCaptureProcessProgressed(progress);
1345             } catch (RemoteException e) {
1346                 Log.e(TAG, "Remote client doesn't respond to capture progress callbacks!");
1347             }
1348         }
1349     }
1350 
1351     private class RequestCallbackStub extends IRequestCallback.Stub {
1352         private final List<RequestProcessorImpl.Request> mRequests;
1353         private final RequestProcessorImpl.Callback mCallback;
1354 
1355         public RequestCallbackStub(List<RequestProcessorImpl.Request> requests,
1356                 RequestProcessorImpl.Callback callback) {
1357             mCallback = callback;
1358             if (mCallback != null) {
1359                 mRequests = requests;
1360             } else {
1361                 Log.w(TAG, "No valid request callbacks!");
1362                 mRequests = new ArrayList<>();
1363             }
1364         }
1365 
1366         @Override
1367         public void onCaptureStarted(int requestId, long frameNumber, long timestamp) {
1368             if (mCallback != null) {
1369                 if (mRequests.get(requestId) != null) {
1370                     mCallback.onCaptureStarted(mRequests.get(requestId), frameNumber, timestamp);
1371                 } else {
1372                     Log.e(TAG,"Request id: " + requestId + " not found!");
1373                 }
1374             }
1375         }
1376 
1377         @Override
1378         public void onCaptureProgressed(int requestId, ParcelCaptureResult partialResult) {
1379             if (mCallback != null) {
1380                 if (mRequests.get(requestId) != null) {
1381                     CaptureResult result = new CaptureResult(partialResult.cameraId,
1382                             partialResult.results, partialResult.parent, partialResult.sequenceId,
1383                             partialResult.frameNumber);
1384                     mCallback.onCaptureProgressed(mRequests.get(requestId), result);
1385                 } else {
1386                     Log.e(TAG,"Request id: " + requestId + " not found!");
1387                 }
1388             }
1389         }
1390 
1391         @Override
1392         public void onCaptureCompleted(int requestId, ParcelTotalCaptureResult totalCaptureResult) {
1393             if (mCallback != null) {
1394                 if (mRequests.get(requestId) != null) {
1395                     PhysicalCaptureResultInfo[] physicalResults = new PhysicalCaptureResultInfo[0];
1396                     if ((totalCaptureResult.physicalResult != null) &&
1397                             (!totalCaptureResult.physicalResult.isEmpty())) {
1398                         int count = totalCaptureResult.physicalResult.size();
1399                         physicalResults = new PhysicalCaptureResultInfo[count];
1400                         physicalResults = totalCaptureResult.physicalResult.toArray(
1401                                 physicalResults);
1402                     }
1403                     ArrayList<CaptureResult> partials = new ArrayList<>(
1404                             totalCaptureResult.partials.size());
1405                     for (ParcelCaptureResult parcelResult : totalCaptureResult.partials) {
1406                         partials.add(new CaptureResult(parcelResult.cameraId, parcelResult.results,
1407                                 parcelResult.parent, parcelResult.sequenceId,
1408                                 parcelResult.frameNumber));
1409                     }
1410                     TotalCaptureResult result = new TotalCaptureResult(
1411                             totalCaptureResult.logicalCameraId, totalCaptureResult.results,
1412                             totalCaptureResult.parent, totalCaptureResult.sequenceId,
1413                             totalCaptureResult.frameNumber, partials, totalCaptureResult.sessionId,
1414                             physicalResults);
1415                     mCallback.onCaptureCompleted(mRequests.get(requestId), result);
1416                 } else {
1417                     Log.e(TAG,"Request id: " + requestId + " not found!");
1418                 }
1419             }
1420         }
1421 
1422         @Override
1423         public void onCaptureFailed(int requestId, CaptureFailure captureFailure) {
1424             if (mCallback != null) {
1425                 if (mRequests.get(requestId) != null) {
1426                     android.hardware.camera2.CaptureFailure failure =
1427                             new android.hardware.camera2.CaptureFailure(captureFailure.request,
1428                                     captureFailure.reason, captureFailure.dropped,
1429                                     captureFailure.sequenceId, captureFailure.frameNumber,
1430                                     captureFailure.errorPhysicalCameraId);
1431                     mCallback.onCaptureFailed(mRequests.get(requestId), failure);
1432                 } else {
1433                     Log.e(TAG,"Request id: " + requestId + " not found!");
1434                 }
1435             }
1436         }
1437 
1438         @Override
1439         public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId) {
1440             if (mCallback != null) {
1441                 if (mRequests.get(requestId) != null) {
1442                     mCallback.onCaptureBufferLost(mRequests.get(requestId), frameNumber,
1443                             outputStreamId);
1444                 } else {
1445                     Log.e(TAG,"Request id: " + requestId + " not found!");
1446                 }
1447             }
1448         }
1449 
1450         @Override
1451         public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
1452             if (mCallback != null) {
1453                 mCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
1454             }
1455         }
1456 
1457         @Override
1458         public void onCaptureSequenceAborted(int sequenceId) {
1459             if (mCallback != null) {
1460                 mCallback.onCaptureSequenceAborted(sequenceId);
1461             }
1462         }
1463     }
1464 
1465     private class ImageProcessorImplStub extends IImageProcessorImpl.Stub {
1466         private final ImageProcessorImpl mImageProcessor;
1467 
1468         public ImageProcessorImplStub(ImageProcessorImpl imageProcessor) {
1469             mImageProcessor = imageProcessor;
1470         }
1471 
1472         @Override
1473         public void onNextImageAvailable(OutputConfigId outputConfigId, ParcelImage img,
1474                 String physicalCameraId) {
1475             if (mImageProcessor != null) {
1476                 mImageProcessor.onNextImageAvailable(outputConfigId.id, img.timestamp,
1477                         new ImageReferenceImpl(img), physicalCameraId);
1478             }
1479         }
1480     }
1481 
1482     private class RequestProcessorStub implements RequestProcessorImpl {
1483         private final IRequestProcessorImpl mRequestProcessor;
1484         private final String mCameraId;
1485 
1486         public RequestProcessorStub(IRequestProcessorImpl requestProcessor, String cameraId) {
1487             mRequestProcessor = requestProcessor;
1488             mCameraId = cameraId;
1489         }
1490 
1491         @Override
1492         public void setImageProcessor(int outputConfigId,
1493                 ImageProcessorImpl imageProcessor) {
1494             OutputConfigId  configId = new OutputConfigId();
1495             configId.id = outputConfigId;
1496             try {
1497                 mRequestProcessor.setImageProcessor(configId,
1498                         new ImageProcessorImplStub(imageProcessor));
1499             } catch (RemoteException e) {
1500                 Log.e(TAG, "Failed to set image processor due to remote exception!");
1501             }
1502         }
1503 
1504         @Override
1505         public int submit(Request request, Callback callback) {
1506             ArrayList<Request> requests = new ArrayList<>();
1507             requests.add(request);
1508             return submit(requests, callback);
1509         }
1510 
1511         @Override
1512         public int submit(List<Request> requests, Callback callback) {
1513             ArrayList<android.hardware.camera2.extension.Request> captureRequests =
1514                     new ArrayList<>();
1515             int requestId = 0;
1516             for (Request request : requests) {
1517                 captureRequests.add(initializeParcelable(request, requestId, mCameraId));
1518                 requestId++;
1519             }
1520 
1521             try {
1522                 return mRequestProcessor.submitBurst(captureRequests,
1523                         new RequestCallbackStub(requests, callback));
1524             } catch (RemoteException e) {
1525                 Log.e(TAG, "Failed to submit request due to remote exception!");
1526             }
1527             return -1;
1528         }
1529 
1530         @Override
1531         public int setRepeating(Request request, Callback callback) {
1532             try {
1533                 ArrayList<Request> requests = new ArrayList<>();
1534                 requests.add(request);
1535                 return mRequestProcessor.setRepeating(
1536                         initializeParcelable(request, 0, mCameraId),
1537                         new RequestCallbackStub(requests, callback));
1538             } catch (RemoteException e) {
1539                 Log.e(TAG, "Failed to submit repeating request due to remote exception!");
1540             }
1541 
1542             return -1;
1543         }
1544 
1545         @Override
1546         public void abortCaptures() {
1547             try {
1548                 mRequestProcessor.abortCaptures();
1549             } catch (RemoteException e) {
1550                 Log.e(TAG, "Failed to abort requests due to remote exception!");
1551             }
1552         }
1553 
1554         @Override
1555         public void stopRepeating() {
1556             try {
1557                 mRequestProcessor.stopRepeating();
1558             } catch (RemoteException e) {
1559                 Log.e(TAG, "Failed to stop repeating request due to remote exception!");
1560             }
1561         }
1562     }
1563 
1564     private class SessionProcessorImplStub extends ISessionProcessorImpl.Stub implements
1565             IBinder.DeathRecipient {
1566         private final SessionProcessorImpl mSessionProcessor;
1567         private String mCameraId = null;
1568         private IBinder mToken;
1569 
1570         OutputSurfaceImplStub mOutputPreviewSurfaceImpl;
1571         OutputSurfaceImplStub mOutputImageCaptureSurfaceImpl;
1572         OutputSurfaceImplStub mOutputPostviewSurfaceImpl;
1573 
1574         public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) {
1575             mSessionProcessor = sessionProcessor;
1576         }
1577 
1578         @Override
1579         public CameraSessionConfig initSession(IBinder token, String cameraId,
1580                 Map<String, CameraMetadataNative> charsMapNative, OutputSurface previewSurface,
1581                 OutputSurface imageCaptureSurface, OutputSurface postviewSurface) {
1582             mOutputPreviewSurfaceImpl = new OutputSurfaceImplStub(previewSurface);
1583             mOutputImageCaptureSurfaceImpl = new OutputSurfaceImplStub(imageCaptureSurface);
1584             mOutputPostviewSurfaceImpl = new OutputSurfaceImplStub(postviewSurface);
1585 
1586             Camera2SessionConfigImpl sessionConfig;
1587 
1588             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1589                 int outputsColorSpace = getColorSpaceFromOutputSurfaces(previewSurface,
1590                         imageCaptureSurface, postviewSurface);
1591                 OutputSurfaceConfigurationImplStub outputSurfaceConfigs =
1592                         new OutputSurfaceConfigurationImplStub(mOutputPreviewSurfaceImpl,
1593                         // Image Analysis Output is currently only supported in CameraX
1594                         mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/,
1595                         mOutputPostviewSurfaceImpl, outputsColorSpace);
1596 
1597                 sessionConfig = mSessionProcessor.initSession(cameraId,
1598                         getCharacteristicsMap(charsMapNative),
1599                         getApplicationContext(), outputSurfaceConfigs);
1600             } else {
1601                 sessionConfig = mSessionProcessor.initSession(cameraId,
1602                         getCharacteristicsMap(charsMapNative),
1603                         getApplicationContext(), mOutputPreviewSurfaceImpl,
1604                         mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
1605             }
1606 
1607             List<Camera2OutputConfigImpl> outputConfigs = sessionConfig.getOutputConfigs();
1608             CameraSessionConfig ret = new CameraSessionConfig();
1609             ret.outputConfigs = new ArrayList<>();
1610             for (Camera2OutputConfigImpl output : outputConfigs) {
1611                 CameraOutputConfig entry = getCameraOutputConfig(output);
1612                 List<Camera2OutputConfigImpl> sharedOutputs =
1613                         output.getSurfaceSharingOutputConfigs();
1614                 if ((sharedOutputs != null) && (!sharedOutputs.isEmpty())) {
1615                     entry.sharedSurfaceConfigs = new ArrayList<>();
1616                     for (Camera2OutputConfigImpl sharedOutput : sharedOutputs) {
1617                         entry.sharedSurfaceConfigs.add(getCameraOutputConfig(sharedOutput));
1618                     }
1619                 }
1620                 ret.outputConfigs.add(entry);
1621             }
1622             if (Flags.extension10Bit() && EFV_SUPPORTED) {
1623                 ret.colorSpace = sessionConfig.getColorSpace();
1624             } else {
1625                 ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
1626             }
1627             ret.sessionTemplateId = sessionConfig.getSessionTemplateId();
1628             ret.sessionType = -1;
1629             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1630                 ret.sessionType = sessionConfig.getSessionType();
1631             }
1632             ret.sessionParameter = initializeParcelableMetadata(
1633                     sessionConfig.getSessionParameters(), cameraId);
1634             mCameraId = cameraId;
1635             mToken = token;
1636             CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
1637             return ret;
1638         }
1639 
1640         @Override
1641         public void deInitSession(IBinder token) {
1642             CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
1643             mSessionProcessor.deInitSession();
1644 
1645             if (Flags.surfaceLeakFix()) {
1646                 if (mOutputImageCaptureSurfaceImpl.mSurface != null) {
1647                     mOutputImageCaptureSurfaceImpl.mSurface.release();
1648                 }
1649                 if (mOutputPreviewSurfaceImpl.mSurface != null) {
1650                     mOutputPreviewSurfaceImpl.mSurface.release();
1651                 }
1652                 if (mOutputPostviewSurfaceImpl.mSurface != null) {
1653                     mOutputPostviewSurfaceImpl.mSurface.release();
1654                 }
1655             }
1656         }
1657 
1658         @Override
1659         public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor, String statsKey) {
1660             mSessionProcessor.onCaptureSessionStart(
1661                     new RequestProcessorStub(requestProcessor, mCameraId));
1662         }
1663 
1664         @Override
1665         public void onCaptureSessionEnd() {
1666             mSessionProcessor.onCaptureSessionEnd();
1667         }
1668 
1669         @Override
1670         public int startRepeating(ICaptureCallback callback) {
1671             return mSessionProcessor.startRepeating(new CaptureCallbackStub(callback, mCameraId));
1672         }
1673 
1674         @Override
1675         public void stopRepeating() {
1676             mSessionProcessor.stopRepeating();
1677         }
1678 
1679         @Override
1680         public void setParameters(CaptureRequest captureRequest) {
1681             HashMap<CaptureRequest.Key<?>, Object> paramMap = new HashMap<>();
1682             for (CaptureRequest.Key captureRequestKey : captureRequest.getKeys()) {
1683                 paramMap.put(captureRequestKey, captureRequest.get(captureRequestKey));
1684             }
1685 
1686             mSessionProcessor.setParameters(paramMap);
1687         }
1688 
1689         @Override
1690         public int startTrigger(CaptureRequest captureRequest, ICaptureCallback callback) {
1691             HashMap<CaptureRequest.Key<?>, Object> triggerMap = new HashMap<>();
1692             for (CaptureRequest.Key captureRequestKey : captureRequest.getKeys()) {
1693                 triggerMap.put(captureRequestKey, captureRequest.get(captureRequestKey));
1694             }
1695 
1696             return mSessionProcessor.startTrigger(triggerMap,
1697                     new CaptureCallbackStub(callback, mCameraId));
1698         }
1699 
1700         @Override
1701         public int startCapture(ICaptureCallback callback, boolean isPostviewRequested) {
1702             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1703                 return isPostviewRequested ? mSessionProcessor.startCaptureWithPostview(
1704                         new CaptureCallbackStub(callback, mCameraId)) :
1705                         mSessionProcessor.startCapture(new CaptureCallbackStub(callback,
1706                         mCameraId));
1707             }
1708 
1709             return mSessionProcessor.startCapture(new CaptureCallbackStub(callback, mCameraId));
1710         }
1711 
1712         @Override
1713         public LatencyPair getRealtimeCaptureLatency() {
1714             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1715                 Pair<Long, Long> latency = mSessionProcessor.getRealtimeCaptureLatency();
1716                 if (latency != null) {
1717                     LatencyPair ret = new LatencyPair();
1718                     ret.first = latency.first;
1719                     ret.second = latency.second;
1720                     return ret;
1721                 }
1722             }
1723 
1724             return null;
1725         }
1726 
1727         @Override
1728         public void binderDied() {
1729             mSessionProcessor.deInitSession();
1730         }
1731 
1732         // Get the color space of the output configurations. All of the OutputSurfaces
1733         // can be assumed to have the same color space so return the color space
1734         // of any non-null OutputSurface
1735         private int getColorSpaceFromOutputSurfaces(OutputSurface previewSurface,
1736                 OutputSurface imageCaptureSurface, OutputSurface postviewSurface) {
1737             int colorSpace = ColorSpaceProfiles.UNSPECIFIED;
1738 
1739             if (previewSurface.surface != null) {
1740                 colorSpace = previewSurface.colorSpace;
1741             } else if (imageCaptureSurface.surface != null) {
1742                 colorSpace = imageCaptureSurface.colorSpace;
1743             } else if (postviewSurface.surface != null) {
1744                 colorSpace = postviewSurface.colorSpace;
1745             }
1746 
1747             return colorSpace;
1748         }
1749     }
1750 
1751     private class OutputSurfaceConfigurationImplStub implements OutputSurfaceConfigurationImpl {
1752         private OutputSurfaceImpl mOutputPreviewSurfaceImpl;
1753         private OutputSurfaceImpl mOutputImageCaptureSurfaceImpl;
1754         private OutputSurfaceImpl mOutputImageAnalysisSurfaceImpl;
1755         private OutputSurfaceImpl mOutputPostviewSurfaceImpl;
1756         private int mColorSpace;
1757 
1758         public OutputSurfaceConfigurationImplStub(OutputSurfaceImpl previewOutput,
1759                 OutputSurfaceImpl imageCaptureOutput, OutputSurfaceImpl imageAnalysisOutput,
1760                 OutputSurfaceImpl postviewOutput, int colorSpace) {
1761             mOutputPreviewSurfaceImpl = previewOutput;
1762             mOutputImageCaptureSurfaceImpl = imageCaptureOutput;
1763             mOutputImageAnalysisSurfaceImpl = imageAnalysisOutput;
1764             mOutputPostviewSurfaceImpl = postviewOutput;
1765             mColorSpace = colorSpace;
1766         }
1767 
1768         public OutputSurfaceConfigurationImplStub(OutputSurfaceImpl previewOutput,
1769                 OutputSurfaceImpl imageCaptureOutput, OutputSurfaceImpl imageAnalysisOutput,
1770                 OutputSurfaceImpl postviewOutput) {
1771             mOutputPreviewSurfaceImpl = previewOutput;
1772             mOutputImageCaptureSurfaceImpl = imageCaptureOutput;
1773             mOutputImageAnalysisSurfaceImpl = imageAnalysisOutput;
1774             mOutputPostviewSurfaceImpl = postviewOutput;
1775             mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
1776         }
1777 
1778         @Override
1779         public OutputSurfaceImpl getPreviewOutputSurface() {
1780             return mOutputPreviewSurfaceImpl;
1781         }
1782 
1783         @Override
1784         public OutputSurfaceImpl getImageCaptureOutputSurface() {
1785             return mOutputImageCaptureSurfaceImpl;
1786         }
1787 
1788         @Override
1789         public OutputSurfaceImpl getImageAnalysisOutputSurface() {
1790             return mOutputImageAnalysisSurfaceImpl;
1791         }
1792 
1793         @Override
1794         public OutputSurfaceImpl getPostviewOutputSurface() {
1795             return mOutputPostviewSurfaceImpl;
1796         }
1797 
1798         @Override
1799         public int getColorSpace() {
1800             return mColorSpace;
1801         }
1802     }
1803 
1804     private class OutputSurfaceImplStub implements OutputSurfaceImpl {
1805         private final Surface mSurface;
1806         private final Size mSize;
1807         private final int mImageFormat;
1808         private final int mDataspace;
1809         private final long mUsage;
1810         private final long mDynamicRangeProfile;
1811 
1812         public OutputSurfaceImplStub(OutputSurface outputSurface) {
1813             mSurface = outputSurface.surface;
1814             if (mSurface != null) {
1815                 mDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
1816                 mUsage = SurfaceUtils.getSurfaceUsage(mSurface);
1817             } else {
1818                 mDataspace = -1;
1819                 mUsage = 0;
1820             }
1821             mDynamicRangeProfile = outputSurface.dynamicRangeProfile;
1822             mSize = new Size(outputSurface.size.width, outputSurface.size.height);
1823             mImageFormat = outputSurface.imageFormat;
1824         }
1825 
1826         @Override
1827         public Surface getSurface() {
1828             return mSurface;
1829         }
1830 
1831         @Override
1832         public Size getSize() {
1833             return mSize;
1834         }
1835 
1836         @Override
1837         public int getImageFormat() {
1838             return mImageFormat;
1839         }
1840 
1841         @Override
1842         public int getDataspace() {
1843             return mDataspace;
1844         }
1845 
1846         @Override
1847         public long getUsage() {
1848             return mUsage;
1849         }
1850 
1851         @Override
1852         public long getDynamicRangeProfile() {
1853             return mDynamicRangeProfile;
1854         }
1855 
1856     }
1857 
1858     private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub implements
1859             IBinder.DeathRecipient {
1860         private final PreviewExtenderImpl mPreviewExtender;
1861         private String mCameraId = null;
1862         private boolean mSessionEnabled;
1863         private IBinder mToken;
1864 
1865         public PreviewExtenderImplStub(PreviewExtenderImpl previewExtender) {
1866             mPreviewExtender = previewExtender;
1867         }
1868 
1869         @Override
1870         public void onInit(IBinder token, String cameraId,
1871                 CameraMetadataNative cameraCharacteristics) {
1872             mCameraId = cameraId;
1873             CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics);
1874             mCameraManager.registerDeviceStateListener(chars);
1875             mPreviewExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this);
1876             mToken = token;
1877             CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
1878         }
1879 
1880         @Override
1881         public void onDeInit(IBinder token) {
1882             CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
1883             mPreviewExtender.onDeInit();
1884         }
1885 
1886         @Override
1887         public CaptureStageImpl onPresetSession() {
1888             return initializeParcelable(mPreviewExtender.onPresetSession(), mCameraId);
1889         }
1890 
1891         @Override
1892         public CaptureStageImpl onEnableSession() {
1893             mSessionEnabled = true;
1894             return initializeParcelable(mPreviewExtender.onEnableSession(), mCameraId);
1895         }
1896 
1897         @Override
1898         public CaptureStageImpl onDisableSession() {
1899             mSessionEnabled = false;
1900             return initializeParcelable(mPreviewExtender.onDisableSession(), mCameraId);
1901         }
1902 
1903         @Override
1904         public void init(String cameraId, CameraMetadataNative chars) {
1905             CameraCharacteristics c = new CameraCharacteristics(chars);
1906             mCameraManager.registerDeviceStateListener(c);
1907             mPreviewExtender.init(cameraId, c);
1908         }
1909 
1910         @Override
1911         public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) {
1912             CameraCharacteristics c = new CameraCharacteristics(chars);
1913             mCameraManager.registerDeviceStateListener(c);
1914             return mPreviewExtender.isExtensionAvailable(cameraId, c);
1915         }
1916 
1917         @Override
1918         public CaptureStageImpl getCaptureStage() {
1919             return initializeParcelable(mPreviewExtender.getCaptureStage(), mCameraId);
1920         }
1921 
1922         @Override
1923         public int getSessionType() {
1924             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
1925                 return mPreviewExtender.onSessionType();
1926             }
1927 
1928             return -1;
1929         }
1930 
1931         @Override
1932         public int getProcessorType() {
1933             ProcessorType processorType = mPreviewExtender.getProcessorType();
1934             if (processorType == ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
1935                 return IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
1936             } else if (processorType == ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR) {
1937                 return IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR;
1938             } else {
1939                 return IPreviewExtenderImpl.PROCESSOR_TYPE_NONE;
1940             }
1941         }
1942 
1943         @Override
1944         public IPreviewImageProcessorImpl getPreviewImageProcessor() {
1945             PreviewImageProcessorImpl processor;
1946             try {
1947                 processor = (PreviewImageProcessorImpl) mPreviewExtender.getProcessor();
1948             } catch (ClassCastException e) {
1949                 Log.e(TAG, "Failed casting preview processor!");
1950                 return null;
1951             }
1952 
1953             if (processor != null) {
1954                 return new PreviewImageProcessorImplStub(processor, mCameraId);
1955             }
1956 
1957             return null;
1958         }
1959 
1960         @Override
1961         public IRequestUpdateProcessorImpl getRequestUpdateProcessor() {
1962             RequestUpdateProcessorImpl processor;
1963             try {
1964                 processor = (RequestUpdateProcessorImpl) mPreviewExtender.getProcessor();
1965             } catch (ClassCastException e) {
1966                 Log.e(TAG, "Failed casting preview processor!");
1967                 return null;
1968             }
1969 
1970             if (processor != null) {
1971                 return new RequestUpdateProcessorImplStub(processor, mCameraId);
1972             }
1973 
1974             return null;
1975         }
1976 
1977         @Override
1978         public List<SizeList> getSupportedResolutions() {
1979             if (INIT_API_SUPPORTED) {
1980                 List<Pair<Integer, android.util.Size[]>> sizes =
1981                         mPreviewExtender.getSupportedResolutions();
1982                 if ((sizes != null) && !sizes.isEmpty()) {
1983                     return initializeParcelable(sizes);
1984                 }
1985             }
1986             return null;
1987         }
1988 
1989         @Override
1990         public void binderDied() {
1991             if (mSessionEnabled) {
1992                 mPreviewExtender.onDisableSession();
1993             }
1994             mPreviewExtender.onDeInit();
1995         }
1996     }
1997 
1998     private class ImageCaptureExtenderImplStub extends IImageCaptureExtenderImpl.Stub implements
1999             IBinder.DeathRecipient {
2000         private final ImageCaptureExtenderImpl mImageExtender;
2001         private String mCameraId = null;
2002         private boolean mSessionEnabled;
2003         private IBinder mToken;
2004 
2005         public ImageCaptureExtenderImplStub(ImageCaptureExtenderImpl imageExtender) {
2006             mImageExtender = imageExtender;
2007         }
2008 
2009         @Override
2010         public void onInit(IBinder token, String cameraId,
2011                 CameraMetadataNative cameraCharacteristics) {
2012             CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics);
2013             mCameraManager.registerDeviceStateListener(chars);
2014             mImageExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this);
2015             mCameraId = cameraId;
2016             mToken = token;
2017             CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
2018         }
2019 
2020         @Override
2021         public void onDeInit(IBinder token) {
2022             CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
2023             mImageExtender.onDeInit();
2024         }
2025 
2026         @Override
2027         public CaptureStageImpl onPresetSession() {
2028             return initializeParcelable(mImageExtender.onPresetSession(), mCameraId);
2029         }
2030 
2031         @Override
2032         public boolean isCaptureProcessProgressAvailable() {
2033             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
2034                 return mImageExtender.isCaptureProcessProgressAvailable();
2035             }
2036 
2037             return false;
2038         }
2039 
2040         @Override
2041         public boolean isPostviewAvailable() {
2042             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
2043                 return mImageExtender.isPostviewAvailable();
2044             }
2045 
2046             return false;
2047         }
2048 
2049         @Override
2050         public CaptureStageImpl onEnableSession() {
2051             mSessionEnabled = true;
2052             return initializeParcelable(mImageExtender.onEnableSession(), mCameraId);
2053         }
2054 
2055         @Override
2056         public CaptureStageImpl onDisableSession() {
2057             mSessionEnabled = false;
2058             return initializeParcelable(mImageExtender.onDisableSession(), mCameraId);
2059         }
2060 
2061         @Override
2062         public int getSessionType() {
2063             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
2064                 return mImageExtender.onSessionType();
2065             }
2066 
2067             return -1;
2068         }
2069 
2070         @Override
2071         public void init(String cameraId, CameraMetadataNative chars) {
2072             CameraCharacteristics c = new CameraCharacteristics(chars);
2073             mCameraManager.registerDeviceStateListener(c);
2074             mImageExtender.init(cameraId, c);
2075         }
2076 
2077         @Override
2078         public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) {
2079             CameraCharacteristics c = new CameraCharacteristics(chars);
2080             mCameraManager.registerDeviceStateListener(c);
2081             return mImageExtender.isExtensionAvailable(cameraId, c);
2082         }
2083 
2084         @Override
2085         public ICaptureProcessorImpl getCaptureProcessor() {
2086             CaptureProcessorImpl captureProcessor = mImageExtender.getCaptureProcessor();
2087             if (captureProcessor != null) {
2088                 return new CaptureProcessorImplStub(captureProcessor, mCameraId);
2089             }
2090 
2091             return null;
2092         }
2093 
2094 
2095         @Override
2096         public List<CaptureStageImpl> getCaptureStages() {
2097             List<androidx.camera.extensions.impl.CaptureStageImpl> captureStages =
2098                 mImageExtender.getCaptureStages();
2099             if (captureStages != null) {
2100                 ArrayList<android.hardware.camera2.extension.CaptureStageImpl> ret =
2101                         new ArrayList<>();
2102                 for (androidx.camera.extensions.impl.CaptureStageImpl stage : captureStages) {
2103                     ret.add(initializeParcelable(stage, mCameraId));
2104                 }
2105 
2106                 return ret;
2107             }
2108 
2109             return null;
2110         }
2111 
2112         @Override
2113         public int getMaxCaptureStage() {
2114             return mImageExtender.getMaxCaptureStage();
2115         }
2116 
2117         @Override
2118         public List<SizeList> getSupportedResolutions() {
2119             if (INIT_API_SUPPORTED) {
2120                 List<Pair<Integer, android.util.Size[]>> sizes =
2121                         mImageExtender.getSupportedResolutions();
2122                 if ((sizes != null) && !sizes.isEmpty()) {
2123                     return initializeParcelable(sizes);
2124                 }
2125             }
2126 
2127             return null;
2128         }
2129 
2130         @Override
2131         public List<SizeList> getSupportedPostviewResolutions(
2132                 android.hardware.camera2.extension.Size captureSize) {
2133             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
2134                 Size sz = new Size(captureSize.width, captureSize.height);
2135                 List<Pair<Integer, android.util.Size[]>> sizes =
2136                         mImageExtender.getSupportedPostviewResolutions(sz);
2137                 if ((sizes != null) && !sizes.isEmpty()) {
2138                     return initializeParcelable(sizes);
2139                 }
2140             }
2141 
2142             return null;
2143         }
2144 
2145         @Override
2146         public LatencyRange getEstimatedCaptureLatencyRange(
2147                 android.hardware.camera2.extension.Size outputSize) {
2148             if (ESTIMATED_LATENCY_API_SUPPORTED) {
2149                 Size sz = new Size(outputSize.width, outputSize.height);
2150                 Range<Long> latencyRange = mImageExtender.getEstimatedCaptureLatencyRange(sz);
2151                 if (latencyRange != null) {
2152                     LatencyRange ret = new LatencyRange();
2153                     ret.min = latencyRange.getLower();
2154                     ret.max = latencyRange.getUpper();
2155                     return ret;
2156                 }
2157             }
2158 
2159             return null;
2160         }
2161 
2162         @Override
2163         public LatencyPair getRealtimeCaptureLatency() {
2164             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
2165                 Pair<Long, Long> latency = mImageExtender.getRealtimeCaptureLatency();
2166                 if (latency != null) {
2167                     LatencyPair ret = new LatencyPair();
2168                     ret.first = latency.first;
2169                     ret.second = latency.second;
2170                     return ret;
2171                 }
2172             }
2173 
2174             return null;
2175         }
2176 
2177         @Override
2178         public CameraMetadataNative getAvailableCaptureRequestKeys() {
2179             if (RESULT_API_SUPPORTED) {
2180                 List<CaptureRequest.Key> supportedCaptureKeys =
2181                         mImageExtender.getAvailableCaptureRequestKeys();
2182 
2183                 if ((supportedCaptureKeys != null) && !supportedCaptureKeys.isEmpty()) {
2184                     CameraMetadataNative ret = new CameraMetadataNative();
2185                     long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ?
2186                             mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE;
2187                     ret.setVendorId(vendorId);
2188                     int requestKeyTags [] = new int[supportedCaptureKeys.size()];
2189                     int i = 0;
2190                     for (CaptureRequest.Key key : supportedCaptureKeys) {
2191                         requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
2192                     }
2193                     ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags);
2194 
2195                     return ret;
2196                 }
2197             }
2198 
2199             return null;
2200         }
2201 
2202         @Override
2203         public CameraMetadataNative getAvailableCaptureResultKeys() {
2204             if (RESULT_API_SUPPORTED) {
2205                 List<CaptureResult.Key> supportedResultKeys =
2206                         mImageExtender.getAvailableCaptureResultKeys();
2207 
2208                 if ((supportedResultKeys != null) && !supportedResultKeys.isEmpty()) {
2209                     CameraMetadataNative ret = new CameraMetadataNative();
2210                     long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ?
2211                             mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE;
2212                     ret.setVendorId(vendorId);
2213                     int resultKeyTags [] = new int[supportedResultKeys.size()];
2214                     int i = 0;
2215                     for (CaptureResult.Key key : supportedResultKeys) {
2216                         resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
2217                     }
2218                     ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags);
2219 
2220                     return ret;
2221                 }
2222             }
2223 
2224             return null;
2225         }
2226 
2227         @Override
2228         public void binderDied() {
2229             if (mSessionEnabled) {
2230                 mImageExtender.onDisableSession();
2231             }
2232             mImageExtender.onDeInit();
2233         }
2234     }
2235 
2236     private class ProcessResultCallback implements ProcessResultImpl {
2237         private final IProcessResultImpl mProcessResult;
2238         private final String mCameraId;
2239 
2240         private ProcessResultCallback(IProcessResultImpl processResult, String cameraId) {
2241             mProcessResult = processResult;
2242             mCameraId = cameraId;
2243         }
2244 
2245         @Override
2246         public void onCaptureProcessProgressed(int progress) {
2247             try {
2248                 mProcessResult.onCaptureProcessProgressed(progress);
2249             } catch (RemoteException e) {
2250                 Log.e(TAG, "Remote client doesn't respond to capture progress callbacks!");
2251             }
2252         }
2253 
2254         @Override
2255         public void onCaptureCompleted(long shutterTimestamp,
2256                 List<Pair<CaptureResult.Key, Object>> result) {
2257             if (result == null) {
2258                 Log.e(TAG, "Invalid capture result received!");
2259             }
2260 
2261             CameraMetadataNative captureResults = new CameraMetadataNative();
2262             if (mMetadataVendorIdMap.containsKey(mCameraId)) {
2263                 captureResults.setVendorId(mMetadataVendorIdMap.get(mCameraId));
2264             }
2265             for (Pair<CaptureResult.Key, Object> pair : result) {
2266                 captureResults.set(pair.first, pair.second);
2267             }
2268 
2269             try {
2270                 mProcessResult.onCaptureCompleted(shutterTimestamp, captureResults);
2271             } catch (RemoteException e) {
2272                 Log.e(TAG, "Remote client doesn't respond to capture results!");
2273             }
2274         }
2275     }
2276 
2277     private class CaptureProcessorImplStub extends ICaptureProcessorImpl.Stub {
2278         private final CaptureProcessorImpl mCaptureProcessor;
2279         private final String mCameraId;
2280 
2281         public CaptureProcessorImplStub(CaptureProcessorImpl captureProcessor, String cameraId) {
2282             mCaptureProcessor = captureProcessor;
2283             mCameraId = cameraId;
2284         }
2285 
2286         @Override
2287         public void onOutputSurface(Surface surface, int imageFormat) {
2288             mCaptureProcessor.onOutputSurface(surface, imageFormat);
2289         }
2290 
2291         @Override
2292         public void onPostviewOutputSurface(Surface surface) {
2293             mCaptureProcessor.onPostviewOutputSurface(surface);
2294         }
2295 
2296         @Override
2297         public void onResolutionUpdate(android.hardware.camera2.extension.Size size,
2298                 android.hardware.camera2.extension.Size postviewSize) {
2299             if (postviewSize != null) {
2300                 mCaptureProcessor.onResolutionUpdate(
2301                         new android.util.Size(size.width, size.height),
2302                         new android.util.Size(postviewSize.width, postviewSize.height));
2303             } else {
2304                 mCaptureProcessor.onResolutionUpdate(
2305                         new android.util.Size(size.width, size.height));
2306             }
2307         }
2308 
2309         @Override
2310         public void onImageFormatUpdate(int imageFormat) {
2311             mCaptureProcessor.onImageFormatUpdate(imageFormat);
2312         }
2313 
2314         @Override
2315         public void process(List<CaptureBundle> captureList, IProcessResultImpl resultCallback,
2316                 boolean isPostviewRequested) {
2317             HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap = new HashMap<>();
2318             for (CaptureBundle captureBundle : captureList) {
2319                 captureMap.put(captureBundle.stage, new Pair<> (
2320                         new ExtensionImage(captureBundle.captureImage),
2321                         new TotalCaptureResult(captureBundle.captureResult,
2322                                 captureBundle.sequenceId)));
2323             }
2324             if (!captureMap.isEmpty()) {
2325                 if ((LATENCY_IMPROVEMENTS_SUPPORTED) && (isPostviewRequested)) {
2326                     ProcessResultCallback processResultCallback = (resultCallback != null)
2327                             ? new ProcessResultCallback(resultCallback, mCameraId) : null;
2328                     mCaptureProcessor.processWithPostview(captureMap, processResultCallback,
2329                             null /*executor*/);
2330                 } else if ((resultCallback != null) && (RESULT_API_SUPPORTED)) {
2331                     mCaptureProcessor.process(captureMap, new ProcessResultCallback(resultCallback,
2332                                     mCameraId), null /*executor*/);
2333                 } else if (resultCallback == null) {
2334                     mCaptureProcessor.process(captureMap);
2335                 } else {
2336                     Log.e(TAG, "Process requests with capture results are not supported!");
2337                 }
2338             } else {
2339                 Log.e(TAG, "Process request with absent capture stages!");
2340             }
2341         }
2342     }
2343 
2344     private class PreviewImageProcessorImplStub extends IPreviewImageProcessorImpl.Stub {
2345         private final PreviewImageProcessorImpl mProcessor;
2346         private final String mCameraId;
2347 
2348         public PreviewImageProcessorImplStub(PreviewImageProcessorImpl processor, String cameraId) {
2349             mProcessor = processor;
2350             mCameraId = cameraId;
2351         }
2352 
2353         @Override
2354         public void onOutputSurface(Surface surface, int imageFormat) {
2355             mProcessor.onOutputSurface(surface, imageFormat);
2356         }
2357 
2358         @Override
2359         public void onResolutionUpdate(android.hardware.camera2.extension.Size size) {
2360             mProcessor.onResolutionUpdate(new android.util.Size(size.width, size.height));
2361         }
2362 
2363         @Override
2364         public void onImageFormatUpdate(int imageFormat) {
2365             mProcessor.onImageFormatUpdate(imageFormat);
2366         }
2367 
2368         @Override
2369         public void process(android.hardware.camera2.extension.ParcelImage image,
2370                 CameraMetadataNative result, int sequenceId, IProcessResultImpl resultCallback) {
2371             if ((resultCallback != null) && RESULT_API_SUPPORTED) {
2372                 mProcessor.process(new ExtensionImage(image),
2373                         new TotalCaptureResult(result, sequenceId),
2374                         new ProcessResultCallback(resultCallback, mCameraId), null /*executor*/);
2375             } else if (resultCallback == null) {
2376                 mProcessor.process(new ExtensionImage(image),
2377                         new TotalCaptureResult(result, sequenceId));
2378             } else {
2379 
2380             }
2381         }
2382     }
2383 
2384     private class RequestUpdateProcessorImplStub extends IRequestUpdateProcessorImpl.Stub {
2385         private final RequestUpdateProcessorImpl mProcessor;
2386         private final String mCameraId;
2387 
2388         public RequestUpdateProcessorImplStub(RequestUpdateProcessorImpl processor,
2389                 String cameraId) {
2390             mProcessor = processor;
2391             mCameraId = cameraId;
2392         }
2393 
2394         @Override
2395         public void onOutputSurface(Surface surface, int imageFormat) {
2396             mProcessor.onOutputSurface(surface, imageFormat);
2397         }
2398 
2399         @Override
2400         public void onResolutionUpdate(android.hardware.camera2.extension.Size size) {
2401             mProcessor.onResolutionUpdate(new android.util.Size(size.width, size.height));
2402         }
2403 
2404         @Override
2405         public void onImageFormatUpdate(int imageFormat) {
2406             mProcessor.onImageFormatUpdate(imageFormat);
2407         }
2408 
2409         @Override
2410         public CaptureStageImpl process(CameraMetadataNative result, int sequenceId) {
2411             return initializeParcelable(
2412                     mProcessor.process(new TotalCaptureResult(result, sequenceId)), mCameraId);
2413         }
2414     }
2415 
2416     private class ImageReferenceImpl extends ExtensionImage
2417             implements androidx.camera.extensions.impl.advanced.ImageReferenceImpl {
2418 
2419         private final Object mImageLock = new Object();
2420         private int mReferenceCount;
2421 
2422         private ImageReferenceImpl(ParcelImage parcelImage) {
2423             super(parcelImage);
2424             mReferenceCount = 1;
2425         }
2426 
2427         @Override
2428         public boolean increment() {
2429             synchronized (mImageLock) {
2430                 if (mReferenceCount <= 0) {
2431                     return false;
2432                 }
2433                 mReferenceCount++;
2434             }
2435 
2436             return true;
2437         }
2438 
2439         @Override
2440         public boolean decrement() {
2441             synchronized (mImageLock) {
2442                 if (mReferenceCount <= 0) {
2443                     return false;
2444                 }
2445                 mReferenceCount--;
2446 
2447                 if (mReferenceCount <= 0) {
2448                     close();
2449                 }
2450             }
2451 
2452             return true;
2453         }
2454 
2455         @Override
2456         public Image get() {
2457             return this;
2458         }
2459     }
2460 
2461     private class ExtensionImage extends android.media.Image {
2462         private final android.hardware.camera2.extension.ParcelImage mParcelImage;
2463         private GraphicBuffer mGraphicBuffer;
2464         private ImageReader.ImagePlane[] mPlanes;
2465 
2466         private ExtensionImage(android.hardware.camera2.extension.ParcelImage parcelImage) {
2467             mParcelImage = parcelImage;
2468             mIsImageValid = true;
2469         }
2470 
2471         @Override
2472         public int getFormat() {
2473             throwISEIfImageIsInvalid();
2474             return mParcelImage.format;
2475         }
2476 
2477         @Override
2478         public int getWidth() {
2479             throwISEIfImageIsInvalid();
2480             return mParcelImage.width;
2481         }
2482 
2483         @Override
2484         public HardwareBuffer getHardwareBuffer() {
2485             throwISEIfImageIsInvalid();
2486             return mParcelImage.buffer;
2487         }
2488 
2489         @Override
2490         public int getHeight() {
2491             throwISEIfImageIsInvalid();
2492             return mParcelImage.height;
2493         }
2494 
2495         @Override
2496         public long getTimestamp() {
2497             throwISEIfImageIsInvalid();
2498             return mParcelImage.timestamp;
2499         }
2500 
2501         @Override
2502         public int getTransform() {
2503             throwISEIfImageIsInvalid();
2504             return mParcelImage.transform;
2505         }
2506 
2507         @Override
2508         public int getScalingMode() {
2509             throwISEIfImageIsInvalid();
2510             return mParcelImage.scalingMode;
2511         }
2512 
2513         @Override
2514         public Plane[] getPlanes() {
2515             throwISEIfImageIsInvalid();
2516             if (mPlanes == null) {
2517                 int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.detachFd() : -1;
2518                 mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mParcelImage.buffer);
2519                 mPlanes = ImageReader.initializeImagePlanes(mParcelImage.planeCount, mGraphicBuffer,
2520                         fenceFd, mParcelImage.format, mParcelImage.timestamp,
2521                         mParcelImage.transform, mParcelImage.scalingMode, mParcelImage.crop);
2522             }
2523             // Shallow copy is fine.
2524             return mPlanes.clone();
2525         }
2526 
2527         @Override
2528         protected final void finalize() throws Throwable {
2529             try {
2530                 close();
2531             } finally {
2532                 super.finalize();
2533             }
2534         }
2535 
2536         @Override
2537         public boolean isAttachable() {
2538             throwISEIfImageIsInvalid();
2539             // Clients must always detach parcelable images
2540             return true;
2541         }
2542 
2543         @Override
2544         public Rect getCropRect() {
2545             throwISEIfImageIsInvalid();
2546             return mParcelImage.crop;
2547         }
2548 
2549         @Override
2550         public void close() {
2551             mIsImageValid = false;
2552 
2553             if (mGraphicBuffer != null) {
2554                 try {
2555                     ImageReader.unlockGraphicBuffer(mGraphicBuffer);
2556                 } catch (RuntimeException e) {
2557                     e.printStackTrace();
2558                 }
2559                 mGraphicBuffer.destroy();
2560                 mGraphicBuffer = null;
2561             }
2562 
2563             if (mPlanes != null) {
2564                 mPlanes = null;
2565             }
2566 
2567             if (mParcelImage.buffer != null) {
2568                 mParcelImage.buffer.close();
2569                 mParcelImage.buffer = null;
2570             }
2571 
2572             if (mParcelImage.fence != null) {
2573                 try {
2574                     mParcelImage.fence.close();
2575                 } catch (IOException e) {
2576                     e.printStackTrace();
2577                 }
2578                 mParcelImage.fence = null;
2579             }
2580         }
2581     }
2582 
2583     private static CameraOutputConfig getCameraOutputConfig(Camera2OutputConfigImpl output) {
2584         CameraOutputConfig ret = new CameraOutputConfig();
2585         if (Flags.extension10Bit() && EFV_SUPPORTED) {
2586             ret.dynamicRangeProfile = output.getDynamicRangeProfile();
2587         } else {
2588             ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
2589         }
2590         ret.outputId = new OutputConfigId();
2591         ret.outputId.id = output.getId();
2592         ret.physicalCameraId = output.getPhysicalCameraId();
2593         ret.surfaceGroupId = output.getSurfaceGroupId();
2594         ret.isMultiResolutionOutput = false;
2595         if (output instanceof SurfaceOutputConfigImpl) {
2596             SurfaceOutputConfigImpl surfaceConfig = (SurfaceOutputConfigImpl) output;
2597             ret.type = CameraOutputConfig.TYPE_SURFACE;
2598             ret.surface = surfaceConfig.getSurface();
2599         } else if (output instanceof ImageReaderOutputConfigImpl) {
2600             ImageReaderOutputConfigImpl imageReaderOutputConfig =
2601                     (ImageReaderOutputConfigImpl) output;
2602             ret.type = CameraOutputConfig.TYPE_IMAGEREADER;
2603             ret.size = new android.hardware.camera2.extension.Size();
2604             ret.size.width = imageReaderOutputConfig.getSize().getWidth();
2605             ret.size.height = imageReaderOutputConfig.getSize().getHeight();
2606             ret.imageFormat = imageReaderOutputConfig.getImageFormat();
2607             ret.capacity = imageReaderOutputConfig.getMaxImages();
2608             if (EFV_SUPPORTED) {
2609                 ret.usage = imageReaderOutputConfig.getUsage();
2610             } else {
2611                 ret.usage = 0;
2612             }
2613         } else if (output instanceof MultiResolutionImageReaderOutputConfigImpl) {
2614             MultiResolutionImageReaderOutputConfigImpl multiResReaderConfig =
2615                     (MultiResolutionImageReaderOutputConfigImpl) output;
2616             ret.type = CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
2617             ret.imageFormat = multiResReaderConfig.getImageFormat();
2618             ret.capacity = multiResReaderConfig.getMaxImages();
2619             ret.isMultiResolutionOutput = true;
2620         } else {
2621             throw new IllegalStateException("Unknown output config type!");
2622         }
2623 
2624         return ret;
2625     }
2626 }
2627