summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2023-03-15 04:18:00 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-15 04:18:00 +0000
commitd9af75e9404044bd50059b043f8f54ab2c19fa46 (patch)
treece783772c791f8c33ec2bd464176cbdfac04d403
parent854f3bf6040c3ff50c4819664734f48f86c36fa4 (diff)
parent48f538570bd87f9aa26fc71ce2fcfd57bbbd66c2 (diff)
downloadex-d9af75e9404044bd50059b043f8f54ab2c19fa46.tar.gz
Merge "Add service-based Camera Extensions reference implementation" am: 7d3c8a1ff8 am: 48f538570b
Original change: https://android-review.googlesource.com/c/platform/frameworks/ex/+/2446164 Change-Id: Ie91d26a73c03d92bc20598f8d6c7b36330126bed Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/Android.bp31
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml25
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml6
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java270
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java95
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java70
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java71
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java383
-rw-r--r--camera2/extensions/service_based_sample/oem_library/Android.bp45
-rw-r--r--camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml21
-rw-r--r--camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml5
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java124
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java105
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java123
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java105
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java121
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java100
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java66
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java91
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java84
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java123
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java105
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java171
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java115
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java123
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java105
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java117
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java64
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java45
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java57
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java39
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java188
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java51
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java243
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java46
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java123
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java54
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java50
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java32
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java123
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java281
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java31
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl21
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java102
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl38
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java88
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java89
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl29
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl29
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl24
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl22
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl22
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl33
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl30
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl39
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java281
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl23
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl23
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl25
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java121
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java245
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java345
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java59
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java229
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java171
81 files changed, 6812 insertions, 0 deletions
diff --git a/camera2/extensions/service_based_sample/extensions_service/Android.bp b/camera2/extensions/service_based_sample/extensions_service/Android.bp
new file mode 100644
index 00000000..383a3c0b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "ExtensionsService",
+ srcs: ["src/**/*.java"],
+ libs: ["service_based_camera_extensions"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ enforce_uses_libs: false,
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml
new file mode 100644
index 00000000..abd40763
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.oemextensions">
+ <queries>
+ <intent>
+ <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" />
+ </intent>
+ </queries>
+
+ <application
+ android:label="@string/app_name"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
+ <uses-library android:name="androidx.camera.extensions.impl" android:required="true" />
+ <service
+ android:name="ExtensionsService"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml
new file mode 100644
index 00000000..7a8f9d4a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Camera Extensions Service</string>
+
+</resources>
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
new file mode 100644
index 00000000..a10c1659
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub {
+ private static final String TAG = "AdvancedExtenderStub";
+ private Context mContext;
+ private int mExtensionType;
+ private String mCurrentCameraId;
+ private Map<String, CameraCharacteristics> mCharacteristicsMap = new HashMap<>();
+
+ /**
+ * Construct the AdvancedExtenderImplStub instance.
+ *
+ * @param context a context.
+ * @param extensionType CameraExtensionCharacteristics#EXTENSION_AUTOMATIC for Auto,
+ * CameraExtensionCharacteristics#EXTENSION_NIGHT for Night,
+ * CameraExtensionCharacteristics#EXTENSION_HDR for HDR,
+ * CameraExtensionCharacteristics#EXTENSION_BOKEH for Bokeh,
+ * CameraExtensionCharacteristics#EXTENSION_FACE_RETOUCH for face retouch.
+ */
+ public AdvancedExtenderImplStub(@NonNull Context context, int extensionType) {
+ mContext = context;
+ mExtensionType = extensionType;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId) throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId) throws RemoteException {
+ mCurrentCameraId = cameraId;
+ }
+
+ @Override
+ @NonNull
+ public LatencyRange getEstimatedCaptureLatencyRange(@NonNull String cameraId,
+ @NonNull androidx.camera.extensions.impl.service.Size outputSize,
+ int format) throws RemoteException {
+ Log.d(TAG, "getEstimatedCaptureLatencyRange format" + format);
+
+ LatencyRange latencyRange = new LatencyRange();
+ latencyRange.min = 100;
+ latencyRange.max = 1000;
+ return latencyRange;
+ }
+
+ private CameraCharacteristics getCameraCharacteristics(String cameraId) {
+ CameraCharacteristics characteristics = mCharacteristicsMap.get(cameraId);
+ if (characteristics != null) {
+ return characteristics;
+ }
+ try {
+ CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
+ characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ mCharacteristicsMap.put(cameraId, characteristics);
+ return characteristics;
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Cannot get CameraCharacteristics", e);
+ return null;
+ }
+ }
+
+ private static SizeList getSupportedSizeByFormat(
+ CameraCharacteristics cameraCharacteristics, int imageFormat) {
+ StreamConfigurationMap streamConfigMap =
+ cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ Size[] sizes = streamConfigMap.getOutputSizes(imageFormat);
+ SizeList sizeList = new SizeList();
+ sizeList.sizes = new ArrayList<>();
+ for (Size size : sizes) {
+ androidx.camera.extensions.impl.service.Size sz =
+ new androidx.camera.extensions.impl.service.Size();
+ sz.width = size.getWidth();
+ sz.height = size.getHeight();
+ sizeList.sizes.add(sz);
+ }
+ sizeList.format = imageFormat;
+ return sizeList;
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedPreviewOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.PRIVATE));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedCaptureOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics,
+ ImageFormat.JPEG),
+ getSupportedSizeByFormat(cameraCharacteristics,
+ ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedYuvAnalysisResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public ISessionProcessorImpl getSessionProcessor() throws RemoteException {
+ Log.d(TAG, "getSessionProcessor");
+ return new SimpleSessionProcessorStub(getCameraCharacteristics(mCurrentCameraId),
+ getSupportedCaptureRequestKeys(mCurrentCameraId).keySet(),
+ getSupportedCaptureResultKeys(mCurrentCameraId).keySet());
+ }
+
+ private Map<CaptureRequest.Key, Object> getSupportedCaptureRequestKeys(String cameraId) {
+ Map<CaptureRequest.Key, Object> map = new HashMap<>();
+ map.put(CaptureRequest.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureRequest.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported(cameraId)) {
+ Log.e("AAAAA", "support AF: cameraid=" + cameraId);
+ map.put(CaptureRequest.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ }
+ return map;
+ }
+
+ private Map<CaptureResult.Key, Object> getSupportedCaptureResultKeys(String cameraId) {
+ Map<CaptureResult.Key, Object> map = new HashMap<>();
+ map.put(CaptureResult.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureResult.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported(cameraId)) {
+ map.put(CaptureResult.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_STATE,
+ 0 /* don't care, must not be null */);
+ }
+ return map;
+ }
+
+ private boolean isAfAutoSupported(String cameraId) {
+ int[] afModes = getCameraCharacteristics(cameraId)
+ .get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+ if (afModes == null) {
+ return false;
+ }
+
+ for (int afMode : afModes) {
+ if (afMode == CameraCharacteristics.CONTROL_AF_MODE_AUTO) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureRequestKeys(String cameraId)
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(getCameraCharacteristics(cameraId));
+ Map<CaptureRequest.Key, Object> keysmap = getSupportedCaptureRequestKeys(cameraId);
+ for (CaptureRequest.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureResultKeys(String cameraId)
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(getCameraCharacteristics(cameraId));
+ Map<CaptureResult.Key, Object> keysmap = getSupportedCaptureResultKeys(cameraId);
+ for (CaptureResult.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
new file mode 100644
index 00000000..c339ed98
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.view.Surface;
+
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.Size;
+
+import java.util.ArrayList;
+
+public class CameraOutputConfigBuilder {
+ private final CameraOutputConfig mConfig;
+
+ private CameraOutputConfigBuilder(CameraOutputConfig config) {
+ mConfig = config;
+ mConfig.surfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ }
+
+ public static CameraOutputConfigBuilder createSurfaceOutput(
+ int outputId, @NonNull Surface surface) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_SURFACE;
+ config.outputId = outputId;
+ config.surface = surface;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public static CameraOutputConfigBuilder createImageReaderOutput(
+ int outputId, int width, int height, int imageFormat, int maxImages) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_IMAGEREADER;
+ config.outputId = outputId;
+ config.size = new Size();
+ config.size.width = width;
+ config.size.height = height;
+ config.imageFormat = imageFormat;
+ config.capacity = maxImages;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public CameraOutputConfigBuilder setPhysicalCameraId(String physicalCameraId) {
+ mConfig.physicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mConfig.surfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder addSharedOutputConfig(CameraOutputConfig cameraOutputConfig) {
+ if (mConfig.sharedSurfaceConfigs == null) {
+ mConfig.sharedSurfaceConfigs = new ArrayList<>();
+ }
+ mConfig.sharedSurfaceConfigs.add(cameraOutputConfig);
+ return this;
+ }
+
+ public CameraOutputConfig build() {
+ CameraOutputConfig result = new CameraOutputConfig();
+ result.outputId = mConfig.outputId;
+ result.type = mConfig.type;
+ result.surface = mConfig.surface;
+ result.physicalCameraId = mConfig.physicalCameraId;
+ result.surfaceGroupId = mConfig.surfaceGroupId;
+ result.capacity = mConfig.capacity;
+ result.imageFormat = mConfig.imageFormat;
+ if (mConfig.size != null) {
+ result.size = new Size();
+ result.size.width = mConfig.size.width;
+ result.size.height = mConfig.size.height;
+ }
+ if (mConfig.sharedSurfaceConfigs != null) {
+ result.sharedSurfaceConfigs = new ArrayList<>(mConfig.sharedSurfaceConfigs);
+ }
+ return result;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
new file mode 100644
index 00000000..c3d62351
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IExtensionsService;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+
+public class ExtensionsService extends Service {
+ private static final String TAG = "ExtensionsService";
+
+ public ExtensionsService() {
+ }
+
+ @Override
+ @NonNull
+ public IBinder onBind(Intent intent) {
+ return new ExtensionsServiceStub();
+ }
+
+ class ExtensionsServiceStub extends IExtensionsService.Stub {
+ @Override
+ public boolean isAdvancedExtenderImplemented() throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void initialize(String version, IOnExtensionsInitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "initialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public void deInitialize(IOnExtensionsDeinitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "deInitialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType)
+ throws RemoteException {
+ Log.d(TAG, "initializeAdvancedExtension");
+ return new AdvancedExtenderImplStub(ExtensionsService.this, extensionType);
+ }
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
new file mode 100644
index 00000000..52bb26b4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.Request;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RequestBuilder {
+ private static final AtomicInteger sNextRequestId = new AtomicInteger(0);
+ private final List<Integer> mTargetOutputConfigIds = new ArrayList<>();
+ private final CameraMetadataWrapper mParameters;
+ private int mTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ private final int mRequestId = 0;
+
+ public RequestBuilder(CameraCharacteristics cameraCharacteristics) {
+ mParameters = new CameraMetadataWrapper(cameraCharacteristics);
+ }
+
+ public RequestBuilder addTargetOutputConfigId(int... outputConfigIds) {
+ for (int id : outputConfigIds) {
+ mTargetOutputConfigIds.add(id);
+ }
+ return this;
+ }
+
+ public <T> RequestBuilder setParameter(CaptureRequest.Key<T> key, T value) {
+ mParameters.set(key, value);
+ return this;
+ }
+
+ public RequestBuilder setTemplateId(int templateId) {
+ mTemplateId = templateId;
+ return this;
+ }
+
+ public Request build() {
+ Request request = new Request();
+ int[] idArray = new int[mTargetOutputConfigIds.size()];
+ for (int i = 0; i < idArray.length; i++) {
+ idArray[i] = mTargetOutputConfigIds.get(i);
+ }
+ request.targetOutputConfigIds = idArray;
+ request.requestId = mRequestId;
+ request.parameters = mParameters;
+ request.templateId = mTemplateId;
+ request.requestId = sNextRequestId.getAndIncrement();
+ return request;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
new file mode 100644
index 00000000..ed749aec
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.OutputSurface;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Demonstrates a very simple SessionProcessor which just pass all the output surface into the
+ * camera pipeline directly. No postprocessing is performed.
+ */
+public class SimpleSessionProcessorStub extends ISessionProcessorImpl.Stub {
+ private static final String TAG = "SimpleSessionProcessor";
+ private final CameraCharacteristics mCameraCharacteristics;
+ private final Set<CaptureRequest.Key> mSupportedRequestKeys;
+ private final Set<CaptureResult.Key> mSupportedResultKeys;
+
+ private IRequestProcessorImpl mIRequestProcessor;
+ private AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
+ private Map<CaptureRequest.Key, Object> mParameters = new HashMap<>();
+ private boolean mHasAnalysisOutput = false;
+
+ private static final int PREVIEW_OUTPUT_ID = 1;
+ private static final int CAPTURE_OUTPUT_ID = 2;
+ private static final int ANALYSIS_OUTPUT_ID = 3;
+
+ public SimpleSessionProcessorStub(@NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Set<CaptureRequest.Key> supportedRequestKeys,
+ @NonNull Set<CaptureResult.Key> supportedResultKeys) {
+ mCameraCharacteristics = cameraCharacteristics;
+ mSupportedRequestKeys = supportedRequestKeys;
+ mSupportedResultKeys = supportedResultKeys;
+ }
+
+ @Override
+ public CameraSessionConfig initSession(@NonNull String cameraId,
+ @NonNull OutputSurface outputSurfacePreview,
+ @NonNull OutputSurface outputSurfaceStillCapture,
+ @Nullable OutputSurface outputSurfaceAnalysis) throws RemoteException {
+ Log.d(TAG, "initSession cameraId=" + cameraId);
+ CameraSessionConfig cameraSessionConfig = new CameraSessionConfig();
+ cameraSessionConfig.sessionParameter = new CameraMetadataWrapper(mCameraCharacteristics);
+ // if needed, invoke cameraSessionConfig.sessionParameter.set(...) to set session parameters
+ cameraSessionConfig.sessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ List<CameraOutputConfig> outputConfigList = new ArrayList<>();
+
+ // Preview
+ CameraOutputConfig previewOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(PREVIEW_OUTPUT_ID, outputSurfacePreview.surface)
+ .build();
+ outputConfigList.add(previewOutputConfig);
+
+ // Still capture
+ CameraOutputConfig captureOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(CAPTURE_OUTPUT_ID, outputSurfaceStillCapture.surface)
+ .build();
+ outputConfigList.add(captureOutputConfig);
+
+ // ImageAnalysis
+ if (outputSurfaceAnalysis != null) {
+ mHasAnalysisOutput = true;
+ CameraOutputConfig analysisOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(ANALYSIS_OUTPUT_ID, outputSurfaceAnalysis.surface)
+ .build();
+ outputConfigList.add(analysisOutputConfig);
+ }
+
+ cameraSessionConfig.outputConfigs = outputConfigList;
+ return cameraSessionConfig;
+ }
+
+ @Override
+ public void deInitSession() throws RemoteException {
+ Log.d(TAG, "deInitSession");
+ }
+
+ @Override
+ public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor)
+ throws RemoteException {
+ Log.d(TAG, "onCaptureSessionStart");
+ mIRequestProcessor = requestProcessor;
+ }
+
+ @Override
+ public void onCaptureSessionEnd() throws RemoteException {
+ Log.d(TAG, "onCaptureSessionEnd");
+
+ mIRequestProcessor = null;
+ }
+
+ @Override
+ public void setParameters(CaptureRequest captureRequest) throws RemoteException {
+ Log.d(TAG, "setParameters");
+
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ mParameters.put(key, captureRequest.get(key));
+ }
+ }
+ }
+
+ protected void notifyOnCaptureCompleted(
+ @NonNull int seqId,
+ @NonNull TotalCaptureResult result,
+ @NonNull ICaptureCallback captureCallback) {
+ Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (shutterTimestamp != null) {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+
+ for (CaptureResult.Key key : mSupportedResultKeys) {
+ if (result.get(key) != null) {
+ cameraMetadataWrapper.set(key, result.get(key));
+ }
+ }
+
+ try {
+ captureCallback.onCaptureCompleted(shutterTimestamp, seqId,
+ cameraMetadataWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot notify onCaptureCompleted", e);
+ }
+ }
+ }
+
+ @Override
+ public int startTrigger(CaptureRequest captureRequest, ICaptureCallback captureCallback)
+ throws RemoteException {
+ Log.d(TAG, "startTrigger");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ for (CaptureRequest.Key key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ requestBuilder.setParameter(key, captureRequest.get(key));
+ } else {
+ Log.e(TAG, "startTrigger: key " + key + " not supported");
+ }
+ }
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ private void applyParameters(RequestBuilder requestBuilder) {
+ for (CaptureRequest.Key key : mParameters.keySet()) {
+ requestBuilder.setParameter(key, mParameters.get(key));
+ }
+ }
+
+ @Override
+ public int startRepeating(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startRepeating");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.setRepeating(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void stopRepeating() throws RemoteException {
+ Log.d(TAG, "stopRepeating");
+
+ mIRequestProcessor.stopRepeating();
+ }
+
+ @Override
+ public int startCapture(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startCapture");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(CAPTURE_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId,
+ CaptureResultWrapper captureResultWrapper)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResultWrapper) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResultWrapper.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void abortCapture(int i) throws RemoteException {
+ Log.d(TAG, "abortCapture");
+ mIRequestProcessor.abortCaptures();
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/Android.bp b/camera2/extensions/service_based_sample/oem_library/Android.bp
new file mode 100644
index 00000000..adfb1b51
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "service_based_camera_extensions",
+ installable: true,
+ srcs: [
+ "src/java/**/*.java",
+ "src/java/**/*.aidl",
+ ],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
+ aidl: {
+ local_include_dirs: ["src/java"],
+ include_dirs: [
+ "frameworks/native/aidl/gui", // For SurfaceView AIDL
+ "frameworks/av/camera/aidl", // For CaptureRequest AIDL
+ ]
+ },
+ system_ext_specific: true,
+ platform_apis: true,
+}
+
+prebuilt_etc {
+ name: "service_based_camera_extensions.xml",
+ src: "service_based_camera_extensions.xml",
+ sub_dir: "permissions",
+ system_ext_specific: true,
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml
new file mode 100644
index 00000000..54b5b10a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="androidx.camera.extensions.impl" >
+</manifest>
diff --git a/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml
new file mode 100644
index 00000000..6501b9b4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <library name="androidx.camera.extensions.impl"
+ file="/system_ext/framework/service_based_camera_extensions.jar"/>
+</permissions>
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..514ca3b5
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public AutoImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
new file mode 100755
index 00000000..85b63df7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl {
+ public AutoPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..c547f772
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public BeautyImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
new file mode 100755
index 00000000..da5748cc
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl {
+ public BeautyPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..6901e5f3
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public BokehImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ }
+
+ @Nullable
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ return null;
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ return 2;
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ }
+
+ @Override
+ public void onDeInit() {
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ return null;
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
new file mode 100644
index 00000000..55902f04
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl {
+ public BokehPreviewExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ }
+
+ @NonNull
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_NONE;
+ }
+
+ @Nullable
+ @Override
+ public ProcessorImpl getProcessor() {
+ return null;
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ }
+
+ @Override
+ public void onDeInit() {
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
new file mode 100644
index 00000000..3eee146a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * The interface for processing a set of {@link Image}s that have captured.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface CaptureProcessorImpl extends ProcessorImpl {
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata to
+ * process. The {@link Image} that are contained within the map will become
+ * invalid after this method completes, so no references to them should be kept.
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
+
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata
+ * to process. The {@link Image} that are contained within the map will
+ * become invalid after this method completes, so no references to them
+ * should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
new file mode 100644
index 00000000..c4f4a47d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.CaptureRequest;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * The set of parameters that defines a single capture that will be sent to the camera.
+ *
+ * @since 1.0
+ */
+public interface CaptureStageImpl {
+ /** Returns the identifier for the {@link CaptureStageImpl}. */
+ int getId();
+
+ /**
+ * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
+ * set for a single {@link CaptureRequest}.
+ */
+ @NonNull
+ List<Pair<CaptureRequest.Key, Object>> getParameters();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
new file mode 100644
index 00000000..a74a8804
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Provides interfaces that the OEM needs to implement to handle the state change.
+ *
+ * @since 1.0
+ */
+public interface ExtenderStateListener {
+
+ /**
+ * Notify to initialize the extension. This will be called after bindToLifeCycle. This is
+ * where the use case is started and would be able to allocate resources here. After onInit() is
+ * called, the camera ID, cameraCharacteristics and context will not change until onDeInit()
+ * has been called.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @param context The {@link Context} used for CameraX.
+ */
+ void onInit(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after unbind.
+ * After onDeInit() was called, it is expected that the camera ID, cameraCharacteristics will
+ * no longer hold, this should be where to clear all resources allocated for this use case.
+ */
+ void onDeInit();
+
+ /**
+ * This will be invoked before creating a
+ * {@link CameraCaptureSession}. The {@link CaptureRequest}
+ * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
+ * part of the capture session initialization via
+ * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported from
+ * API level 28. The valid parameter is a subset of the available capture request parameters.
+ *
+ * @return The request information to set the session wide camera parameters.
+ */
+ @Nullable
+ CaptureStageImpl onPresetSession();
+
+ /**
+ * This will be invoked once after the {@link CameraCaptureSession}
+ * has been created. The {@link CaptureRequest} parameters returned via
+ * {@link CaptureStageImpl} will be used to generate a single request to the current
+ * configured {@link CameraDevice}. The generated request will be submitted to camera before
+ * processing other single requests.
+ *
+ * @return The request information to create a single capture request to camera device.
+ */
+ @Nullable
+ CaptureStageImpl onEnableSession();
+
+ /**
+ * This will be invoked before the {@link CameraCaptureSession} is
+ * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will
+ * be used to generate a single request to the currently configured {@link CameraDevice}. The
+ * generated request will be submitted to camera before the CameraCaptureSession is closed.
+ *
+ * @return The request information to customize the session.
+ */
+ @Nullable
+ CaptureStageImpl onDisableSession();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
new file mode 100644
index 00000000..cc357b1a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Stub implementation for the extension version check.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public class ExtensionVersionImpl {
+ public ExtensionVersionImpl() {
+ }
+
+ /**
+ * Provide the current CameraX extension library version to vendor library and vendor would
+ * need to return the supported version for this device. If the returned version is not
+ * supported by CameraX library, the Preview and ImageCapture would not be able to enable the
+ * specific effects provided by the vendor.
+ *
+ * <p>CameraX library provides the Semantic Versioning string in a form of
+ * MAJOR.MINOR.PATCH-description
+ * We will increment the
+ * MAJOR version when make incompatible API changes,
+ * MINOR version when add functionality in a backwards-compatible manner, and
+ * PATCH version when make backwards-compatible bug fixes. And the description can be ignored.
+ *
+ * <p>Vendor library should provide MAJOR.MINOR.PATCH to CameraX. The MAJOR and MINOR
+ * version is used to map to the version of CameraX that it supports, and CameraX extension
+ * would only available when MAJOR version is matched with CameraX current version. The PATCH
+ * version does not indicate compatibility. The patch version should be incremented whenever
+ * the vendor library makes bug fixes or updates to the algorithm.
+ *
+ * @param version the version of CameraX library formatted as MAJOR.MINOR.PATCH-description.
+ * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format
+ * should be used.
+ */
+ @SuppressWarnings("unused")
+ @NonNull
+ public String checkApiVersion(@NonNull String version) {
+ // This sample implements Extensions-Interface 1.3.0.
+ return "1.3.0";
+ }
+
+ /**
+ * Specify whether or not CameraX should invoke the AdvancedExtenderImpl instead of
+ * PreviewExtenderImpl/ImageCaptureExtenderImpl.
+ *
+ * <p>Starting from version 1.2, a set of alternative interfaces called advanced extender for
+ * implementing extensions are provided to OEMs as another option. OEMs can continue using
+ * previous interfaces (PreviewExtenderImpl/ImageCaptureExtenderImpl, also called basic
+ * extender).
+ *
+ * <p>OEMs should return false here if only basic extender is implemented. When returning true,
+ * CameraX will invoke the AdvancedExtenderImpl implementation in advanced package for all
+ * types of extension modes.
+ *
+ * <p>ExtensionVersionImpl, InitializerImpl will still be called for both basic and advanced
+ * extender implementation paths.
+ *
+ * @return true if AdvancedExtenderImpl is implemented
+ * @since 1.2
+ */
+ public boolean isAdvancedExtenderImplemented() {
+ return true;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..507f2143
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public HdrImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
new file mode 100644
index 00000000..83f1a348
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
+ public HdrPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..10b45134
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions for image capture.
+ *
+ * @since 1.0
+ */
+public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The processing that will be done on a set of captures to create and image with the effect.
+ */
+ @Nullable
+ CaptureProcessorImpl getCaptureProcessor();
+
+ /** The set of captures that are needed to create an image with the effect. */
+ @Nullable
+ List<CaptureStageImpl> getCaptureStages();
+
+ /**
+ * Returns the maximum size of the list returned by {@link #getCaptureStages()}.
+ * @return the maximum count.
+ */
+ int getMaxCaptureStage();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link StreamConfigurationMap}.
+ * @since 1.1
+ */
+ @Nullable
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the target capture
+ * resolution.
+ *
+ * <p>This includes the time spent processing the multi-frame capture request along with any
+ * additional time for encoding of the processed buffer in the framework if necessary.</p>
+ *
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds, or
+ * null if no capture latency info can be provided.
+ * @since 1.2
+ */
+ @Nullable
+ Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize);
+
+ /**
+ * Return a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * <p>Also note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ * On basic extensions that implement 1.2 or prior version, the above keys are all supported
+ * explicitly. When migrating from 1.2 or prior to 1.3, please note that both CameraX and
+ * Camera2 will honor the returned list and support only the keys contained in it. For
+ * example, if OEM decides to return only {@link CaptureRequest#CONTROL_ZOOM_RATIO} and
+ * {@link CaptureRequest#SCALER_CROP_REGION} in the 1.3 implementation, it means only zoom is
+ * supported for the app while tap-to-focus , flash and exposure compensation are not allowed.
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ @NonNull
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Return a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link ProcessResultImpl} callback. In case frame processing is not supported,
+ * then the Camera2/CameraX framework will use the list to filter and notify camera clients
+ * using the respective camera results.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * @return List of supported capture result keys, or an empty list if capture results are not
+ * supported.
+ * @since 1.3
+ */
+ @NonNull
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java
new file mode 100644
index 00000000..5a9f0ffc
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ServiceManager;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Used for initializing the extensions library.
+ *
+ * @since 1.1
+ */
+public class InitializerImpl {
+ private InitializerImpl() {
+ }
+
+ /** An unknown error has occurred. */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Error reported if the application version of extensions is incompatible with the on device
+ * library version.
+ */
+ public static final int ERROR_INITIALIZE_VERSION_INCOMPATIBLE = 1;
+
+ /**
+ * Initializes the {@link Context}.
+ *
+ * <p>Before this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param version The version of the extension used by the application.
+ * @param context The {@link Context} of the calling application.
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ */
+ public static void init(@NonNull String version, @NonNull Context context,
+ @NonNull OnExtensionsInitializedCallback callback, @Nullable Executor executor) {
+ ServiceManager.init(context, version, callback, executor);
+ }
+
+ /**
+ * Deinitializes the extensions to release resources.
+ *
+ * <p>After this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ */
+ public static void deinit(@NonNull OnExtensionsDeinitializedCallback callback,
+ @Nullable Executor executor) {
+ ServiceManager.getInstance().deinit(callback, executor);
+ }
+
+ /**
+ * Callback that gets called when the library has finished initializing and is ready for used.
+ */
+ public interface OnExtensionsInitializedCallback {
+ /** Called if the library successfully initializes. */
+ void onSuccess();
+
+ /**
+ * Called if the library is unable to successfully initialize.
+ *
+ * @param error The reason for failing to initialize.
+ */
+ void onFailure(int error);
+ }
+
+ /**
+ * Callback that gets called when the library has finished deinitialized.
+ *
+ * <p> Once this interface has been called then
+ * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} can be called
+ * again regardless of whether or not the deinitialization has succeeded or failed.
+ */
+ public interface OnExtensionsDeinitializedCallback {
+ /**
+ * Called if the library successfully deinitializes.
+ */
+ void onSuccess();
+
+ /**
+ * Called if the library encountered some error during the deinitialization.
+ *
+ * <p>Even if the library fails to deinitialize it is now valid for
+ * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} to be called
+ * again.
+ *
+ * @param error The reason for failing to deinitialize.
+ */
+ void onFailure(int error);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..05a195e1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public NightImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
new file mode 100755
index 00000000..eeb254b2
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightPreviewExtenderImpl implements PreviewExtenderImpl {
+ public NightPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @NonNull
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
new file mode 100644
index 00000000..b3208137
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions in the preview.
+ *
+ * @since 1.0
+ */
+public interface PreviewExtenderImpl extends ExtenderStateListener {
+ /** The different types of the preview processing. */
+ enum ProcessorType {
+ /** Processor which only updates the {@link CaptureStageImpl}. */
+ PROCESSOR_TYPE_REQUEST_UPDATE_ONLY,
+ /** Processor which updates the received {@link android.media.Image}. */
+ PROCESSOR_TYPE_IMAGE_PROCESSOR,
+ /** No processor, only a {@link CaptureStageImpl} is defined. */
+ PROCESSOR_TYPE_NONE
+ }
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The set of parameters required to produce the effect on the preview stream.
+ *
+ * <p> This will be the initial set of parameters used for the preview
+ * {@link CaptureRequest}. If the {@link ProcessorType} is defined as
+ * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when
+ * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link
+ * #getProcessor()} has been called, this should be updated to reflect the new {@link
+ * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required
+ * parameters has not changed, then calling this will return the previous non-null value.
+ */
+ @NonNull
+ CaptureStageImpl getCaptureStage();
+
+ /** The type of preview processing to use. */
+ @NonNull
+ ProcessorType getProcessorType();
+
+ /**
+ * Returns a processor which only updates the {@link CaptureStageImpl}.
+ *
+ * <p>The type of processor is dependent on the return of {@link #getProcessorType()}. The
+ * type of ProcessorImpl returned will be according to the following table.
+ *
+ * <table>
+ * <tr><th> ProcessorType </th> <th> ProcessorImpl </th> </tr>
+ * <tr><td> PROCESSOR_TYPE_REQUEST_UPDATE_ONLY </td> <td> RequestUpdateProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_IMAGE_PROCESSOR </td> <td> PreviewImageProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr>
+ * </table>
+ */
+ @Nullable
+ ProcessorImpl getProcessor();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions.
+ * @since 1.1
+ */
+ @Nullable
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
new file mode 100644
index 00000000..f203ebad
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Processes a single {@link Image} and {@link TotalCaptureResult} to produce an output to a
+ * stream.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface PreviewImageProcessorImpl extends ProcessorImpl {
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will be
+ * invalid after the method completes so no reference to it should be kept.
+ * @param result The metadata associated with the image to process.
+ */
+ void process(Image image, TotalCaptureResult result);
+
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will
+ * be invalid after the method completes so no reference to it should be
+ * kept.
+ * @param result The metadata associated with the image to process.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Image image, TotalCaptureResult result, ProcessResultImpl resultCallback,
+ Executor executor);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
new file mode 100644
index 00000000..d0e3605d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+
+import java.util.List;
+
+/**
+ * Allows clients to receive information about the capture result values of processed frames.
+ *
+ * @since 1.3
+ */
+@SuppressLint("UnknownNullness")
+public interface ProcessResultImpl {
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * @param shutterTimestamp The shutter time stamp of the processed frame.
+ * @param result Key value pairs for all supported capture results. Do note that
+ * if results 'android.jpeg.quality' and 'android.jpeg.orientation'
+ * are present in the process capture input results, then the values
+ * must also be passed as part of this callback. Both Camera2 and
+ * CameraX guarantee that those two settings and results are always
+ * supported and applied by the corresponding framework.
+ */
+ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
new file mode 100644
index 00000000..e5ca19e9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Processes an input image stream and produces an output image stream.
+ *
+ * @since 1.0
+ */
+public interface ProcessorImpl {
+ /**
+ * Updates where the ProcessorImpl should write the output to.
+ *
+ * @param surface The {@link Surface} that the ProcessorImpl should write data into.
+ * @param imageFormat The format of that the surface expects.
+ */
+ void onOutputSurface(@NonNull Surface surface, int imageFormat);
+
+ /**
+ * Invoked when CameraX changes the configured output resolution.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any
+ * {@link android.media.Image} received as input to be at the specified resolution.
+ *
+ * @param size for the surface.
+ */
+ void onResolutionUpdate(@NonNull Size size);
+
+ /**
+ * Invoked when CameraX changes the configured input image format.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any
+ * {@link android.media.Image} received as input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
new file mode 100644
index 00000000..ac3bfb3e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.TotalCaptureResult;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Processes a {@link TotalCaptureResult} to update a CaptureStage.
+ *
+ * @since 1.0
+ */
+public interface RequestUpdateProcessorImpl extends ProcessorImpl {
+ /**
+ * Process the {@link TotalCaptureResult} to update the {@link CaptureStageImpl}
+ *
+ * @param result The metadata associated with the image. Can be null if the image and meta have
+ * not been synced.
+ * @return The updated parameters used for the repeating requests. If this is {@code null} then
+ * the previous parameters will be used.
+ */
+ @Nullable
+ CaptureStageImpl process(@Nullable TotalCaptureResult result);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
new file mode 100644
index 00000000..465bfe88
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.camera.extensions.impl.ExtensionVersionImpl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Advanced OEM contract for implementing Extensions. ImageCapture/Preview Extensions are both
+ * implemented on this interface.
+ *
+ * <p>This advanced OEM contract empowers OEM to gain access to more Camera2 capability. This
+ * includes: (1) Add custom surfaces with specific formats like YUV, RAW, RAW_DEPTH. (2) Access to
+ * the capture request callbacks as well as all the images retrieved of various image formats. (3)
+ * Able to triggers single or repeating request with the capabilities to specify target surfaces,
+ * template id and parameters.
+ *
+ * <p>OEM needs to implement it with class name HdrAdvancedExtenderImpl for HDR,
+ * NightAdvancedExtenderImpl for night mode, BeautyAdvancedExtenderImpl for beauty mode,
+ * BokehAdvancedExtenderImpl for bokeh mode and AutoAdvancedExtenderImpl for auto mode.
+ *
+ * <p>OEMs are required to return true in
+ * {@link ExtensionVersionImpl#isAdvancedExtenderImplemented()} in order to request CameraX to
+ * use advanced extender over basic extender. OEM is okay to implement advanced
+ * extender only Or basic extender only. However the caveat of advanced-only implementation is,
+ * extensions will be unavailable on the apps using interfaces prior to 1.2.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public interface AdvancedExtenderImpl {
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ */
+ void init(String cameraId, Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the
+ * target capture resolution during the calls to
+ * {@link SessionProcessorImpl#startCapture}. This
+ * includes the time spent processing the multi-frame capture request along with any additional
+ * time for encoding of the processed buffer in the framework if necessary.
+ *
+ * @param cameraId the camera id
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @param imageFormat the image format of the capture output surface.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds.
+ * Returns null if no capture latency info can be provided.
+ */
+ Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
+ Size captureOutputSize, int imageFormat);
+
+ /**
+ * Returns supported output format/size map for preview. The format could be PRIVATE or
+ * YUV_420_888. OEM must support PRIVATE format at least. CameraX will only use resolutions
+ * for preview from the list.
+ *
+ * <p>The preview surface format in the CameraCaptureSession may not be identical to the
+ * supported preview output format returned here. Like in the basic extender interface, the
+ * preview PRIVATE surface could be added to the CameraCaptureSession and OEM processes it in
+ * the HAL. Alternatively OEM can configure a intermediate YUV surface of the same size and
+ * writes the output to the preview output surface.
+ */
+ Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output format/size map for image capture. OEM is required to support
+ * both JPEG and YUV_420_888 format output.
+ *
+ * <p>Like in the basic extender interface, the surface created with this supported
+ * format/size could be either added in CameraCaptureSession with HAL processing OR it
+ * configures intermediate surfaces(YUV/RAW..) and writes the output to the output surface.
+ */
+ Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output sizes for Image Analysis (YUV_420_888 format).
+ *
+ * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture
+ * output surfaces. If imageAnalysis YUV surface is not supported, OEM should return null or
+ * empty list.
+ */
+ List<Size> getSupportedYuvAnalysisResolutions(String cameraId);
+
+ /**
+ * Returns a processor for activating extension sessions. It implements all the interactions
+ * required for starting a extension and cleanup.
+ */
+ SessionProcessorImpl createSessionProcessor();
+
+ /**
+ * Returns a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Please note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Returns a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link SessionProcessorImpl.CaptureCallback#onCaptureCompleted} callback.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * @return List of supported capture result keys, or
+ * an empty list if capture results are not supported.
+ * @since 1.3
+ */
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
new file mode 100644
index 00000000..c67dc799
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for auto.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class AutoAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public AutoAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_AUTOMATIC);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
new file mode 100644
index 00000000..2e10e255
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for beauty.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class BeautyAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public BeautyAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BEAUTY);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
new file mode 100644
index 00000000..ae55790b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for bokeh.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class BokehAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public BokehAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BOKEH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
new file mode 100644
index 00000000..68de01b6
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+import java.util.List;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.OutputConfiguration} where
+ * Surface will be created by the information in this config.
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2OutputConfigImpl {
+ /**
+ * Gets thd id of this output config. The id can be used to identify the stream in vendor
+ * implementations.
+ */
+ int getId();
+
+ /**
+ * Gets the surface group id. Vendor can use the surface group id to share memory between
+ * Surfaces.
+ */
+ int getSurfaceGroupId();
+
+ /**
+ * Gets the physical camera id. Returns null if not specified.
+ */
+ String getPhysicalCameraId();
+
+ /**
+ * If non-null, enable surface sharing and add the surface constructed by the return
+ * Camera2OutputConfig.
+ */
+ List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
new file mode 100644
index 00000000..718870f4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2OutputConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2OutputConfigImplBuilder {
+ static AtomicInteger sLastId = new AtomicInteger(0);
+ private OutputConfigImplImpl mOutputConfig;
+ private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ private int mOutputConfigId = -1;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) {
+ mOutputConfig = outputConfig;
+ }
+
+ private int getNextId() {
+ return sLastId.getAndIncrement();
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a {@link android.media.ImageReader}
+ * with the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newImageReaderConfig(
+ Size size, int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a MultiResolutionImageReader with
+ * the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newMultiResolutionImageReaderConfig(
+ int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new MultiResolutionImageReaderOutputConfigImplImpl(imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that contains the Surface directly.
+ */
+ public static Camera2OutputConfigImplBuilder newSurfaceConfig(Surface surface) {
+ return new Camera2OutputConfigImplBuilder(new SurfaceOutputConfigImplImpl(surface));
+ }
+
+ /**
+ * Adds a {@link Camera2SessionConfigImpl} to be shared with current config.
+ */
+ public Camera2OutputConfigImplBuilder addSurfaceSharingOutputConfig(
+ Camera2OutputConfigImpl camera2OutputConfig) {
+ if (mSurfaceSharingConfigs == null) {
+ mSurfaceSharingConfigs = new ArrayList<>();
+ }
+
+ mSurfaceSharingConfigs.add(camera2OutputConfig);
+ return this;
+ }
+
+ /**
+ * Sets a physical camera id.
+ */
+ public Camera2OutputConfigImplBuilder setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ /**
+ * Sets surface group id.
+ */
+ public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mSurfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ /**
+ * Sets output config id.
+ */
+ public Camera2OutputConfigImplBuilder setOutputConfigId(int outputConfigId) {
+ mOutputConfigId = outputConfigId;
+ return this;
+ }
+
+
+ /**
+ * Build a {@link Camera2OutputConfigImpl} instance.
+ */
+ public Camera2OutputConfigImpl build() {
+ // Use the Atomic Integer if setOutputConfigId is never called
+ if(mOutputConfigId == -1) {
+ mOutputConfig.setId(getNextId());
+ }
+ else {
+ mOutputConfig.setId(mOutputConfigId);
+ }
+ mOutputConfig.setPhysicalCameraId(mPhysicalCameraId);
+ mOutputConfig.setSurfaceGroup(mSurfaceGroupId);
+ mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs);
+ return mOutputConfig;
+ }
+
+ private static class OutputConfigImplImpl implements Camera2OutputConfigImpl {
+ private int mId;
+ private int mSurfaceGroup;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ OutputConfigImplImpl() {
+ mId = -1;
+ mSurfaceGroup = 0;
+ mPhysicalCameraId = null;
+ mSurfaceSharingConfigs = null;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public int getSurfaceGroupId() {
+ return mSurfaceGroup;
+ }
+
+ @Override
+ public String getPhysicalCameraId() {
+ return mPhysicalCameraId;
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() {
+ return mSurfaceSharingConfigs;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ public void setSurfaceGroup(int surfaceGroup) {
+ mSurfaceGroup = surfaceGroup;
+ }
+
+ public void setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ }
+
+ public void setSurfaceSharingConfigs(
+ List<Camera2OutputConfigImpl> surfaceSharingConfigs) {
+ mSurfaceSharingConfigs = surfaceSharingConfigs;
+ }
+ }
+
+ private static class SurfaceOutputConfigImplImpl extends OutputConfigImplImpl
+ implements SurfaceOutputConfigImpl {
+ private Surface mSurface;
+
+ SurfaceOutputConfigImplImpl(Surface surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public Surface getSurface() {
+ return mSurface;
+ }
+ }
+
+ private static class ImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements ImageReaderOutputConfigImpl {
+ private Size mSize;
+ private int mImageFormat;
+ private int mMaxImages;
+
+ ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) {
+ mSize = size;
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public Size getSize() {
+ return mSize;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+
+ private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements MultiResolutionImageReaderOutputConfigImpl {
+ private int mImageFormat;
+ private int mMaxImages;
+
+ MultiResolutionImageReaderOutputConfigImplImpl(int imageFormat, int maxImages) {
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
new file mode 100644
index 00000000..d1217177
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureRequest;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.SessionConfiguration}
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2SessionConfigImpl {
+ /**
+ * Returns all the {@link Camera2OutputConfigImpl}s that will be used to create
+ * {@link android.hardware.camera2.params.OutputConfiguration}.
+ */
+ List<Camera2OutputConfigImpl> getOutputConfigs();
+
+ /**
+ * Gets all the parameters to create the session parameters with.
+ */
+ Map<CaptureRequest.Key<?>, Object> getSessionParameters();
+
+ /**
+ * Gets the template id used for creating {@link CaptureRequest}s to be passed in
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}.
+ */
+ int getSessionTemplateId();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
new file mode 100644
index 00000000..a3011666
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2SessionConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2SessionConfigImplBuilder {
+ private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>();
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>();
+
+ public Camera2SessionConfigImplBuilder() {
+ }
+
+ /**
+ * Adds a output config.
+ */
+ public Camera2SessionConfigImplBuilder addOutputConfig(
+ Camera2OutputConfigImpl outputConfig) {
+ mCamera2OutputConfigs.add(outputConfig);
+ return this;
+ }
+
+ /**
+ * Sets session parameters.
+ */
+ public <T> Camera2SessionConfigImplBuilder addSessionParameter(
+ CaptureRequest.Key<T> key, T value) {
+ mSessionParameters.put(key, value);
+ return this;
+ }
+
+ /**
+ * Sets the template id for session parameters request.
+ */
+ public Camera2SessionConfigImplBuilder setSessionTemplateId(int templateId) {
+ mSessionTemplateId = templateId;
+ return this;
+ }
+
+ /**
+ * Gets the session template id.
+ */
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+
+ /**
+ * Gets the session parameters.
+ */
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ /**
+ * Gets all the output configs.
+ */
+ public List<Camera2OutputConfigImpl> getCamera2OutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ /**
+ * Builds a {@link Camera2SessionConfigImpl} instance.
+ */
+ public Camera2SessionConfigImpl build() {
+ return new Camera2SessionConfigImplImpl(this);
+ }
+
+ private static class Camera2SessionConfigImplImpl implements
+ Camera2SessionConfigImpl {
+ int mSessionTemplateId;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters;
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs;
+
+ Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) {
+ mSessionTemplateId = builder.getSessionTemplateId();
+ mSessionParameters = builder.getSessionParameters();
+ mCamera2OutputConfigs = builder.getCamera2OutputConfigs();
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getOutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ @Override
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+ }
+}
+
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
new file mode 100644
index 00000000..e7dbb7d8
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for hdr.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class HdrAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public HdrAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_HDR);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
new file mode 100644
index 00000000..ce17c4f7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+/**
+ * A interface to receive and process the upcoming next available Image.
+ *
+ * <p>Implemented by OEM.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageProcessorImpl {
+ /**
+ * The reference count will be decremented when this method returns. If an extension wants
+ * to hold onto the image it should increment the reference count in this method and
+ * decrement it when the image is no longer needed.
+ *
+ * <p>If OEM is not closing(decrement) the image fast enough, the imageReference passed
+ * in this method might contain null image meaning that the Image was closed to prevent
+ * preview from stalling.
+ *
+ * @param outputConfigId the id of {@link Camera2OutputConfigImpl} which identifies
+ * corresponding Surface
+ * @param timestampNs the timestamp in nanoseconds associated with this image
+ * @param imageReference A reference to the {@link android.media.Image} which might contain
+ * null if OEM close(decrement) the image too slowly
+ * @param physicalCameraId used to distinguish which physical camera id the image comes from
+ * when the output configuration is
+ * MultiResolutionImageReaderOutputConfigImpl. It is also set if
+ * physicalCameraId is set in other Camera2OutputConfigImpl types.
+ *
+ */
+ void onNextImageAvailable(
+ int outputConfigId,
+ long timestampNs,
+ ImageReferenceImpl imageReference,
+ String physicalCameraId
+ );
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..ca4dcafa
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+
+/**
+ * Surface will be created by constructing a ImageReader.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Returns the size of the surface.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the capacity for TYPE_IMAGEREADER.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
new file mode 100644
index 00000000..95f2c3b9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.media.Image;
+
+/**
+ * A Image reference container that enables the Image sharing between Camera2/CameraX and OEM
+ * using reference counting. The wrapped Image will be closed once the reference count
+ * reaches 0.
+ *
+ * <p>Implemented by Camera2/CameraX.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReferenceImpl {
+
+ /**
+ * Increment the reference count. Returns true if the value was incremented.
+ * (returns false if the reference count has already reached zero.)
+ */
+ boolean increment();
+
+ /**
+ * Decrement the reference count. Image will be closed if reference count reaches 0.
+ * Returns true if the value was decremented (returns false if the reference count has
+ * already reached zero)
+ */
+ boolean decrement();
+
+ /**
+ * Return the Android image. This object MUST not be closed directly.
+ * Returns null when the reference count is zero.
+ */
+ Image get();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..c3ad61bc
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+/**
+ * Surface will be created by constructing a MultiResolutionImageReader.
+ */
+public interface MultiResolutionImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the max images of the ImageReader.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
new file mode 100644
index 00000000..be298443
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for night.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class NightAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public NightAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_NIGHT);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
new file mode 100644
index 00000000..f6920296
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * For specifying output surface of the extension.
+ */
+@SuppressLint("UnknownNullness")
+public interface OutputSurfaceImpl {
+ /**
+ * Gets the surface.
+ */
+ Surface getSurface();
+
+ /**
+ * Gets the size.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format.
+ */
+ int getImageFormat();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
new file mode 100644
index 00000000..51853334
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Interface to execute Camera2 capture requests.
+ */
+@SuppressLint("UnknownNullness")
+public interface RequestProcessorImpl {
+ /**
+ * Sets a {@link ImageProcessorImpl} to receive {@link ImageReferenceImpl} to process.
+ */
+ void setImageProcessor(int outputconfigId, ImageProcessorImpl imageProcessor);
+
+ /**
+ * Submits a request.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(Request request, Callback callback);
+
+ /**
+ * Submits a list of requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(List<Request> requests, Callback callback);
+
+ /**
+ * Set repeating requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int setRepeating(Request request, Callback callback);
+
+
+ /**
+ * Abort captures.
+ */
+ void abortCaptures();
+
+ /**
+ * Stop Repeating.
+ */
+ void stopRepeating();
+
+ /**
+ * A interface representing a capture request configuration used for submitting requests in
+ * {@link RequestProcessorImpl}.
+ */
+ interface Request {
+ /**
+ * Gets the target ids of {@link Camera2OutputConfigImpl} which identifies corresponding
+ * Surface to be the targeted for the request.
+ */
+ List<Integer> getTargetOutputConfigIds();
+
+ /**
+ * Gets all the parameters.
+ */
+ Map<CaptureRequest.Key<?>, Object> getParameters();
+
+ /**
+ * Gets the template id.
+ */
+ Integer getTemplateId();
+ }
+
+ /**
+ * Callback to be invoked during the capture.
+ */
+ interface Callback {
+ void onCaptureStarted(
+ Request request,
+ long frameNumber,
+ long timestamp);
+
+ void onCaptureProgressed(
+ Request request,
+ CaptureResult partialResult);
+
+ void onCaptureCompleted(
+ Request request,
+ TotalCaptureResult totalCaptureResult);
+
+ void onCaptureFailed(
+ Request request,
+ CaptureFailure captureFailure);
+
+ void onCaptureBufferLost(
+ Request request,
+ long frameNumber,
+ int outputStreamId);
+
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+
+ void onCaptureSequenceAborted(int sequenceId);
+
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
new file mode 100644
index 00000000..fabfc2bf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.view.Surface;
+
+import java.util.Map;
+
+/**
+ * Interface for creating Camera2 CameraCaptureSessions with extension enabled based on
+ * advanced vendor implementation.
+ *
+ * <p><pre>
+ * The flow of a extension session is shown below:
+ * (1) {@link #initSession}: CameraX prepares streams configuration for creating
+ * CameraCaptureSession. Output surfaces for Preview, ImageCapture and ImageAnalysis are passed
+ * in and vendor is responsible for outputting the results to these surfaces.
+ *
+ * (2) {@link #onCaptureSessionStart}: It is called after CameraCaptureSession is configured.
+ * A {@link RequestProcessorImpl} is passed for vendor to send repeating requests and
+ * single requests.
+ *
+ * (3) {@link #startRepeating}: CameraX will call this method to start the repeating request
+ * after CameraCaptureSession is called. Vendor should start the repeating request by
+ * {@link RequestProcessorImpl}. Vendor can also update the repeating request if needed later.
+ *
+ * (4) {@link #setParameters(Map)}: The passed parameters will be attached to the repeating request
+ * and single requests but vendor can choose to apply some of them only.
+ *
+ * (5) {@link #startCapture(CaptureCallback)}: It is called when apps want to
+ * start a multi-frame image capture. {@link CaptureCallback} will be called
+ * to report the status and the output image will be written to the capture output surface
+ * specified in {@link #initSession}.
+ *
+ * (5) {@link #onCaptureSessionEnd}: It is called right BEFORE CameraCaptureSession.close() is
+ * called.
+ *
+ * (6) {@link #deInitSession}: called when CameraCaptureSession is closed.
+ * </pre>
+ */
+@SuppressLint("UnknownNullness")
+public interface SessionProcessorImpl {
+ /**
+ * Initializes the session for the extension. This is where the OEMs allocate resources for
+ * preparing a CameraCaptureSession. After initSession() is called, the camera ID,
+ * cameraCharacteristics and context will not change until deInitSession() has been called.
+ *
+ * <p>CameraX specifies the output surface configurations for preview, image capture and image
+ * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a
+ * list of {@link Camera2OutputConfigImpl} and session parameters. The
+ * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession.
+ *
+ * <p>OEM is responsible for outputting correct camera images output to these output surfaces.
+ * OEM can have the following options to enable the output:
+ * <pre>
+ * (1) Add these output surfaces in CameraCaptureSession directly using
+ * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in
+ * HAL.
+ *
+ * (2) Use surface sharing with other surface by calling
+ * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)}
+ * to add the output surface to the other {@link Camera2OutputConfigImpl}.
+ *
+ * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output
+ * surface. The output surface won't be contained in the returned
+ * {@link Camera2SessionConfigImpl}.
+ * </pre>
+ *
+ * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder}
+ * implementations are provided in the stub for OEM to construct the
+ * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances.
+ *
+ * @param previewSurfaceConfig output surface for preview
+ * @param imageCaptureSurfaceConfig output surface for image capture.
+ * @param imageAnalysisSurfaceConfig an optional output config for image analysis
+ * (YUV_420_888).
+ * @return a {@link Camera2SessionConfigImpl} consisting of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters which will decide the
+ * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the
+ * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any
+ * supported or mandatory stream combination BUT OEM must ensure this list will always
+ * produce a valid camera capture session.
+ */
+ Camera2SessionConfigImpl initSession(
+ String cameraId,
+ Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ Context context,
+ OutputSurfaceImpl previewSurfaceConfig,
+ OutputSurfaceImpl imageCaptureSurfaceConfig,
+ OutputSurfaceImpl imageAnalysisSurfaceConfig);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after
+ * CameraCaptureSession is closed. After onDeInit() was called, it is expected that the
+ * camera ID, cameraCharacteristics will no longer hold and tear down any resources allocated
+ * for this extension. Aborts all pending captures.
+ */
+ void deInitSession();
+
+ /**
+ * CameraX / Camera2 would call these API’s to pass parameters from the app to the OEM. It’s
+ * expected that the OEM would (eventually) update the repeating request if the keys are
+ * supported. Setting a value to null explicitly un-sets the value.
+ */
+ void setParameters(Map<CaptureRequest.Key<?>, Object> parameters);
+
+ /**
+ * CameraX / Camera2 will call this interface in response to client requests involving
+ * the output preview surface. Typical examples include requests that include AF/AE triggers.
+ * Extensions can disregard any capture request keys that were not advertised in
+ * {@link AdvancedExtenderImpl#getAvailableCaptureRequestKeys}.
+ *
+ * @param triggers Capture request key value map.
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ *
+ * @throws IllegalArgumentException If there are no valid settings that can be applied
+ *
+ * @since 1.3
+ */
+ int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback);
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+ * has been created. {@link RequestProcessorImpl} is passed for OEM to submit single
+ * requests or set repeating requests. This ExtensionRequestProcessor will be valid to use
+ * until onCaptureSessionEnd is called.
+ */
+ void onCaptureSessionStart(RequestProcessorImpl requestProcessor);
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * closed. {@link RequestProcessorImpl} passed in onCaptureSessionStart will no longer
+ * accept any requests after onCaptureSessionEnd() returns.
+ */
+ void onCaptureSessionEnd();
+
+ /**
+ * Starts the repeating request after CameraCaptureSession is called. Vendor should start the
+ * repeating request by {@link RequestProcessorImpl}. Vendor can also update the
+ * repeating request when needed later.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startRepeating(CaptureCallback callback);
+
+ /**
+ * Stop the repeating request. To prevent OEM from not calling stopRepeating, CameraX will
+ * first stop the repeating request of current CameraCaptureSession and call this API to signal
+ * OEM that the repeating request was stopped and going forward calling
+ * {@link RequestProcessorImpl#setRepeating} will simply do nothing.
+ */
+ void stopRepeating();
+
+ /**
+ * Start a multi-frame capture.
+ *
+ * When the capture is completed, {@link CaptureCallback#onCaptureSequenceCompleted}
+ * is called and {@code OnImageAvailableListener#onImageAvailable}
+ * will also be called on the ImageReader that creates the image capture output surface.
+ *
+ * <p>Only one capture can perform at a time. Starting a capture when another capture is running
+ * will cause onCaptureFailed to be called immediately.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startCapture(CaptureCallback callback);
+
+ /**
+ * Abort all capture tasks.
+ */
+ void abortCapture(int captureSequenceId);
+
+ /**
+ * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and
+ * {@link #startRepeating(CaptureCallback)}.
+ */
+ interface CaptureCallback {
+ /**
+ * This method is called when the camera device has started capturing the initial input
+ * image.
+ *
+ * For a multi-frame capture, the method is called when the
+ * CameraCaptureSession.CaptureCallback onCaptureStarted of first frame is called and its
+ * timestamp is directly forwarded to timestamp parameter of
+ * this method.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ * @param timestamp the timestamp at start of capture for repeating
+ * request or the timestamp at start of capture of the
+ * first frame in a multi-frame capture, in nanoseconds.
+ */
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+
+ /**
+ * This method is called when an image (or images in case of multi-frame
+ * capture) is captured and device-specific extension processing is triggered.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureProcessStarted(int captureSequenceId);
+
+ /**
+ * This method is called instead of
+ * {@link #onCaptureProcessStarted} when the camera device failed
+ * to produce the required input for the device-specific extension. The
+ * cause could be a failed camera capture request, a failed
+ * capture result or dropped camera frame.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureFailed(int captureSequenceId);
+
+ /**
+ * This method is called independently of the others in the CaptureCallback, when a capture
+ * sequence finishes.
+ *
+ * <p>In total, there will be at least one
+ * {@link #onCaptureProcessStarted}/{@link #onCaptureFailed}
+ * invocation before this callback is triggered. If the capture
+ * sequence is aborted before any requests have begun processing,
+ * {@link #onCaptureSequenceAborted} is invoked instead.</p>
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceCompleted(int captureSequenceId);
+
+ /**
+ * This method is called when a capture sequence aborts.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceAborted(int captureSequenceId);
+
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * This callback will fire after {@link #onCaptureStarted}, {@link #onCaptureProcessStarted}
+ * and before {@link #onCaptureSequenceCompleted}. The callback is not expected to fire
+ * in case of capture failure {@link #onCaptureFailed} or capture abort
+ * {@link #onCaptureSequenceAborted}.
+ *
+ * @param timestamp The timestamp at start of capture. The same timestamp value
+ * passed to {@link #onCaptureStarted}.
+ * @param captureSequenceId the capture id of the request that generated the capture
+ * results. This is the return value of either
+ * {@link #startRepeating} or {@link #startCapture}.
+ * @param result Map containing the supported capture results. Do note
+ * that if results 'android.jpeg.quality' and
+ * 'android.jpeg.orientation' are present in the process
+ * capture input results, then the values must also be passed
+ * as part of this callback. Both Camera2 and CameraX guarantee
+ * that those two settings and results are always supported and
+ * applied by the corresponding framework.
+ */
+ void onCaptureCompleted(long timestamp, int captureSequenceId,
+ Map<CaptureResult.Key, Object> result);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
new file mode 100644
index 00000000..7b8d83c1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.view.Surface;
+
+/**
+ * Use Surface directly to create the OutputConfiguration.
+ */
+@SuppressLint("UnknownNullness")
+public interface SurfaceOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Get the {@link Surface}. It'll return valid surface only when type is TYPE_SURFACE.
+ */
+ Surface getSurface();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl
new file mode 100644
index 00000000..5be2e737
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+parcelable CameraMetadataWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java
new file mode 100644
index 00000000..100203b2
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.camera.extensions.impl.serviceforward.PlatformApi;
+
+import java.util.ArrayList;
+
+public class CameraMetadataWrapper implements Parcelable {
+ private CameraMetadataNative mCameraMetadataNative;
+ private long mVendorId = Long.MAX_VALUE;
+
+ public CameraMetadataWrapper(CameraCharacteristics cameraCharacteristics) {
+ mCameraMetadataNative = new CameraMetadataNative();
+ if (cameraCharacteristics != null) {
+ setVendorId(cameraCharacteristics);
+ }
+ }
+
+ protected CameraMetadataWrapper(Parcel in) {
+ mCameraMetadataNative = in.readParcelable(CameraMetadataNative.class.getClassLoader());
+ }
+
+ public static final Creator<CameraMetadataWrapper> CREATOR =
+ new Creator<CameraMetadataWrapper>() {
+ @Override
+ public CameraMetadataWrapper createFromParcel(Parcel in) {
+ return new CameraMetadataWrapper(in);
+ }
+
+ @Override
+ public CameraMetadataWrapper[] newArray(int size) {
+ return new CameraMetadataWrapper[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mCameraMetadataNative, flags);
+ }
+
+ private void setVendorId(CameraCharacteristics chars) {
+ Object thisClass = CameraCharacteristics.Key.class;
+ Class<CameraCharacteristics.Key<?>> keyClass =
+ (Class<CameraCharacteristics.Key<?>>) thisClass;
+ ArrayList<CameraCharacteristics.Key<?>> vendorKeys =
+ chars.getNativeMetadata().getAllVendorKeys(keyClass);
+ if ((vendorKeys != null) && !vendorKeys.isEmpty()) {
+ mVendorId = vendorKeys.get(0).getVendorId();
+ mCameraMetadataNative.setVendorId(mVendorId);
+ }
+ }
+
+ public <T> T get(CaptureRequest.Key<T> key) {
+ return mCameraMetadataNative.get(key);
+ }
+
+ public <T> void set(CaptureRequest.Key<T> key, T value) {
+ mCameraMetadataNative.set(key, value);
+ }
+
+ public <T> void set(CaptureResult.Key<T> key, T value) {
+ mCameraMetadataNative.set(key, value);
+ }
+
+ public CaptureRequest toCaptureRequest() {
+ CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative);
+ return PlatformApi.createCaptureRequest(cameraMetadataNative);
+ }
+
+ public TotalCaptureResult toTotalCaptureResult() {
+ CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative);
+ return PlatformApi.createTotalCaptureResult(cameraMetadataNative);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl
new file mode 100644
index 00000000..0c008487
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.Size;
+import android.view.Surface;
+
+parcelable CameraOutputConfig
+{
+ Size size;
+ Surface surface;
+ int imageFormat;
+ int capacity;
+
+ const int TYPE_SURFACE = 0;
+ const int TYPE_IMAGEREADER = 1;
+ const int TYPE_MULTIRES_IMAGEREADER = 2;
+ int type;
+
+ int outputId;
+ int surfaceGroupId;
+ String physicalCameraId;
+ List<CameraOutputConfig> sharedSurfaceConfigs;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl
new file mode 100644
index 00000000..c0d1dece
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+
+parcelable CameraSessionConfig
+{
+ List<CameraOutputConfig> outputConfigs;
+ CameraMetadataWrapper sessionParameter;
+ int sessionTemplateId;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl
new file mode 100644
index 00000000..bf3b331e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable CaptureFailureWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java
new file mode 100644
index 00000000..7deb089b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureFailure;
+
+public class CaptureFailureWrapper implements Parcelable {
+ private CaptureRequest mRequest;
+ private int mReason;
+ private boolean mWasImageCaptured;
+ private int mSequenceId;
+ private long mFrameNumber;
+ private String mErrorPhysicalCameraId;
+
+ public CaptureFailureWrapper(CaptureFailure captureFailure) {
+ mRequest = captureFailure.getRequest();
+ mReason = captureFailure.getReason();
+ mWasImageCaptured = captureFailure.wasImageCaptured();
+ mSequenceId = captureFailure.getSequenceId();
+ mFrameNumber = captureFailure.getFrameNumber();
+ mErrorPhysicalCameraId = captureFailure.getPhysicalCameraId();
+ }
+
+ public CaptureFailureWrapper(Parcel parcel) {
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mReason = parcel.readInt();
+ mWasImageCaptured = parcel.readBoolean();
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ mErrorPhysicalCameraId = parcel.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mReason);
+ parcel.writeBoolean(mWasImageCaptured);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ parcel.writeString(mErrorPhysicalCameraId);
+ }
+
+ public static final Parcelable.Creator<CaptureFailureWrapper> CREATOR
+ = new Parcelable.Creator<CaptureFailureWrapper>() {
+ @Override
+ public CaptureFailureWrapper createFromParcel(Parcel parcel) {
+ return new CaptureFailureWrapper(parcel);
+ }
+
+ @Override
+ public CaptureFailureWrapper[] newArray(int size) {
+ return new CaptureFailureWrapper[size];
+ }
+ };
+
+ public CaptureFailure toCaptureFailure() {
+ return new CaptureFailure(mRequest, mReason, mWasImageCaptured, mSequenceId,
+ mFrameNumber, mErrorPhysicalCameraId);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl
new file mode 100644
index 00000000..6a01aa3a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable CaptureResultWrapper;
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java
new file mode 100644
index 00000000..44b5bfa2
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+public class CaptureResultWrapper implements Parcelable {
+ private String mCameraId;
+ private CameraMetadataNative mResults;
+ private CaptureRequest mRequest;
+ private int mSequenceId;
+ private long mFrameNumber;
+
+ public CaptureResultWrapper(CaptureResult captureResult) {
+ mCameraId = captureResult.getCameraId();
+ mResults = captureResult.getNativeMetadata();
+ mRequest = captureResult.getRequest();
+ mSequenceId = captureResult.getSequenceId();
+ mFrameNumber = captureResult.getFrameNumber();
+ }
+
+ public CaptureResultWrapper(Parcel parcel) {
+ mCameraId = parcel.readString();
+ mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader());
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mCameraId);
+ parcel.writeParcelable(mResults, flags);
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ }
+
+ public static final Parcelable.Creator<CaptureResultWrapper> CREATOR =
+ new Parcelable.Creator<CaptureResultWrapper>() {
+ @Override
+ public CaptureResultWrapper createFromParcel(Parcel parcel) {
+ return new CaptureResultWrapper(parcel);
+ }
+
+ @Override
+ public CaptureResultWrapper[] newArray(int size) {
+ return new CaptureResultWrapper[size];
+ }
+ };
+
+ public CaptureResult toCaptureResult() {
+ return new CaptureResult(mCameraId, mResults, mRequest, mSequenceId, mFrameNumber);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl
new file mode 100644
index 00000000..7042c0b8
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+import androidx.camera.extensions.impl.service.Size;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+interface IAdvancedExtenderImpl {
+ boolean isExtensionAvailable(in String cameraId);
+ void init(in String cameraId);
+ LatencyRange getEstimatedCaptureLatencyRange(
+ in String cameraId, in Size outputSize, int format);
+ @nullable List<SizeList> getSupportedPreviewOutputResolutions(in String cameraId);
+ @nullable List<SizeList> getSupportedCaptureOutputResolutions(in String cameraId);
+ @nullable List<SizeList> getSupportedYuvAnalysisResolutions(in String cameraId);
+ ISessionProcessorImpl getSessionProcessor();
+ CameraMetadataWrapper getAvailableCaptureRequestKeys(in String cameraId);
+ CameraMetadataWrapper getAvailableCaptureResultKeys(in String cameraId);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl
new file mode 100644
index 00000000..0cf067fa
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+// Declare any non-default types here with import statements
+
+interface ICaptureCallback {
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+ void onCaptureProcessStarted(int captureSequenceId);
+ void onCaptureFailed(int captureSequenceId);
+ void onCaptureSequenceCompleted(int captureSequenceId);
+ void onCaptureSequenceAborted(int captureSequenceId);
+ void onCaptureCompleted(long shutterTimestamp, int captureSequenceId, in CameraMetadataWrapper results);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl
new file mode 100644
index 00000000..db73ad00
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.Size;
+
+interface IExtensionsService {
+ boolean isAdvancedExtenderImplemented();
+ void initialize(in String version, in IOnExtensionsInitializedCallback callback);
+ void deInitialize(in IOnExtensionsDeinitializedCallback callback);
+ @nullable IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl
new file mode 100644
index 00000000..940e0f14
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.ImageWrapper;
+
+interface IImageProcessorImpl
+{
+ void onNextImageAvailable(int outputConfigId, in ImageWrapper imageWrapper,
+ in String physicalCameraId);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl
new file mode 100644
index 00000000..c8aa43c8
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+interface IOnExtensionsDeinitializedCallback {
+ void onSuccess();
+ void onFailure(int error);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl
new file mode 100644
index 00000000..ada15d89
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+interface IOnExtensionsInitializedCallback {
+ void onSuccess();
+ void onFailure(int error);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl
new file mode 100644
index 00000000..8abed9e9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import android.hardware.camera2.CaptureRequest;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+interface IRequestCallback
+{
+ void onCaptureStarted(int requestId, long frameNumber, long timestamp);
+ void onCaptureProgressed(int requestId, in CaptureResultWrapper partialResult);
+ void onCaptureCompleted(int requestId, in TotalCaptureResultWrapper totalCaptureResult);
+ void onCaptureFailed(int requestId, in CaptureFailureWrapper captureFailure);
+ void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId);
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+ void onCaptureSequenceAborted(int sequenceId);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl
new file mode 100644
index 00000000..70b30fa7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.IImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.Request;
+
+interface IRequestProcessorImpl {
+ void setImageProcessor(int outputConfigId, in IImageProcessorImpl imageProcessor);
+ int submit(in Request request, in IRequestCallback callback);
+ int submitBurst(in List<Request> requests, in IRequestCallback callback);
+ int setRepeating(in Request request, in IRequestCallback callback);
+ void abortCaptures();
+ void stopRepeating();
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl
new file mode 100644
index 00000000..376a4a44
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.OutputSurface;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import android.hardware.camera2.CaptureRequest;
+
+interface ISessionProcessorImpl {
+ CameraSessionConfig initSession(in String cameraId,
+ in OutputSurface previewSurface,
+ in OutputSurface imageCaptureSurface,
+ in OutputSurface imageAnalysisSurface);
+ void deInitSession();
+ void onCaptureSessionStart(IRequestProcessorImpl requestProcessor);
+ void onCaptureSessionEnd();
+ int startRepeating(in ICaptureCallback callback);
+ void stopRepeating();
+ int startCapture(in ICaptureCallback callback);
+ void setParameters(in CaptureRequest captureRequest);
+ int startTrigger(in CaptureRequest captureRequest, in ICaptureCallback callback);
+ void abortCapture(int captureSequenceId);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl
new file mode 100644
index 00000000..09b7b485
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable ImageWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java
new file mode 100644
index 00000000..882980d1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+import android.graphics.Rect;
+
+import android.graphics.GraphicBuffer;
+import android.media.ImageReader;
+import android.hardware.SyncFence;
+
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+
+import androidx.camera.extensions.impl.advanced.ImageReferenceImpl;
+
+public class ImageWrapper implements Parcelable, ImageReferenceImpl {
+ private static final String TAG = "ImageWrapper";
+ private int mFormat;
+ private int mWidth;
+ private int mHeight;
+ private int mTransform;
+ private int mScalingMode;
+ private long mTimestamp;
+ private int mPlaneCount;
+ private Rect mCrop;
+ private HardwareBuffer mBuffer;
+ private ParcelFileDescriptor mFence;
+
+ public ImageWrapper(Image image) {
+ mFormat = image.getFormat();
+ mWidth = image.getWidth();
+ mHeight = image.getHeight();
+ mTransform = image.getTransform();
+ mScalingMode = image.getScalingMode();
+ mTimestamp = image.getTimestamp();
+ if (image.getPlaneCount() <= 0) {
+ mPlaneCount = image.getPlanes().length;
+ } else {
+ mPlaneCount = image.getPlaneCount();
+ }
+
+ mCrop = image.getCropRect();
+ mBuffer = image.getHardwareBuffer();
+ try {
+ SyncFence fd = image.getFence();
+ if (fd.isValid()) {
+ mFence = fd.getFdDup();
+ }
+ } catch (java.io.IOException e) {
+ Log.e(TAG, "Failed to parcel buffer fence!");
+ }
+ }
+
+ public ImageWrapper(Parcel parcel) {
+ mFormat = parcel.readInt();
+ mWidth = parcel.readInt();
+ mHeight = parcel.readInt();
+ mTransform = parcel.readInt();
+ mScalingMode = parcel.readInt();
+ mTimestamp = parcel.readLong();
+ mPlaneCount = parcel.readInt();
+ mCrop = parcel.readParcelable(Rect.class.getClassLoader());
+ mBuffer = parcel.readParcelable(HardwareBuffer.class.getClassLoader());
+ mFence = parcel.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mFormat);
+ parcel.writeInt(mWidth);
+ parcel.writeInt(mHeight);
+ parcel.writeInt(mTransform);
+ parcel.writeInt(mScalingMode);
+ parcel.writeLong(mTimestamp);
+ parcel.writeInt(mPlaneCount);
+ parcel.writeParcelable(mCrop, flags);
+ parcel.writeParcelable(mBuffer, flags);
+ parcel.writeParcelable(mFence, flags);
+ }
+
+ public static final Parcelable.Creator<ImageWrapper> CREATOR
+ = new Parcelable.Creator<ImageWrapper>() {
+ @Override
+ public ImageWrapper createFromParcel(Parcel parcel) {
+ return new ImageWrapper(parcel);
+ }
+
+ @Override
+ public ImageWrapper[] newArray(int size) {
+ return new ImageWrapper[size];
+ }
+ };
+
+
+ // ImageReferenceImpl implementations.
+ private Image mImage = null;
+ private int mRefCount = 1;
+ private final Object mImageLock = new Object();
+
+ @Override
+ public Image get() {
+ if (mImage == null) {
+ mImage = new ExtensionImage(this);
+ }
+ return mImage;
+ }
+
+ @Override
+ public boolean increment() {
+ synchronized (mImageLock) {
+ if (mRefCount <= 0) {
+ return false;
+ }
+ mRefCount++;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean decrement() {
+ synchronized (mImageLock) {
+ if (mRefCount <= 0) {
+ return false;
+ }
+ mRefCount--;
+ if (mRefCount <= 0) {
+ mImage.close();
+ }
+ }
+ return true;
+ }
+
+ private static class ExtensionImage extends android.media.Image {
+ private final ImageWrapper mImageWrapper;
+ private GraphicBuffer mGraphicBuffer;
+ private ImageReader.ImagePlane[] mPlanes;
+
+ private ExtensionImage(ImageWrapper imageWrapper) {
+ mImageWrapper = imageWrapper;
+ mIsImageValid = true;
+ }
+
+ @Override
+ public int getFormat() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mFormat;
+ }
+
+ @Override
+ public int getWidth() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mWidth;
+ }
+
+ @Override
+ public HardwareBuffer getHardwareBuffer() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mBuffer;
+ }
+
+ @Override
+ public int getHeight() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mHeight;
+ }
+
+ @Override
+ public long getTimestamp() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mTimestamp;
+ }
+
+ @Override
+ public int getTransform() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mTransform;
+ }
+
+ @Override
+ public int getScalingMode() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mScalingMode;
+ }
+
+ @Override
+ public Plane[] getPlanes() {
+ throwISEIfImageIsInvalid();
+ if (mPlanes == null) {
+ int fenceFd = mImageWrapper.mFence != null ? mImageWrapper.mFence.getFd() : -1;
+ mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mImageWrapper.mBuffer);
+ mPlanes = ImageReader.initializeImagePlanes(mImageWrapper.mPlaneCount,
+ mGraphicBuffer,
+ fenceFd, mImageWrapper.mFormat, mImageWrapper.mTimestamp,
+ mImageWrapper.mTransform, mImageWrapper.mScalingMode, mImageWrapper.mCrop);
+
+ }
+ // Shallow copy is fine.
+ return mPlanes.clone();
+ }
+
+ @Override
+ protected final void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public boolean isAttachable() {
+ throwISEIfImageIsInvalid();
+ // Clients must always detach parcelable images
+ return true;
+ }
+
+ @Override
+ public Rect getCropRect() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mCrop;
+ }
+
+ @Override
+ public void close() {
+ mIsImageValid = false;
+ if (mGraphicBuffer != null) {
+ ImageReader.unlockGraphicBuffer(mGraphicBuffer);
+ mGraphicBuffer.destroy();
+ mGraphicBuffer = null;
+ }
+
+ if (mPlanes != null) {
+ mPlanes = null;
+ }
+
+ if (mImageWrapper.mBuffer != null) {
+ mImageWrapper.mBuffer.close();
+ mImageWrapper.mBuffer = null;
+ }
+
+ if (mImageWrapper.mFence != null) {
+ try {
+ mImageWrapper.mFence.close();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ mImageWrapper.mFence = null;
+ }
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl
new file mode 100644
index 00000000..9d9e22cf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable LatencyRange
+{
+ long min;
+ long max;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl
new file mode 100644
index 00000000..558928c3
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+// Declare any non-default types here with import statements
+import androidx.camera.extensions.impl.service.Size;
+import android.view.Surface;
+
+parcelable OutputSurface {
+ Surface surface;
+ Size size;
+ int imageFormat;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl
new file mode 100644
index 00000000..08dff963
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+parcelable Request
+{
+ int[] targetOutputConfigIds;
+ CameraMetadataWrapper parameters;
+ int templateId;
+ int requestId;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl
new file mode 100644
index 00000000..5341b604
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable Size
+{
+ int width;
+ int height;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl
new file mode 100644
index 00000000..443c769e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.Size;
+
+parcelable SizeList
+{
+ int format;
+ List<Size> sizes;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl
new file mode 100644
index 00000000..b28861d5
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable TotalCaptureResultWrapper;
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java
new file mode 100644
index 00000000..28bbcb23
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+public class TotalCaptureResultWrapper implements Parcelable {
+ private String mLogicalCameraId;
+ private CameraMetadataNative mResults;
+ private CaptureRequest mRequest;
+ private int mSequenceId;
+ private long mFrameNumber;
+ private List<CaptureResultWrapper> mPartials = new ArrayList<>();
+ private int mSessionId;
+ private List<PhysicalCaptureResultInfo> mPhysicalResultList = new ArrayList<>();
+
+ public TotalCaptureResultWrapper(TotalCaptureResult totalResult) {
+ mLogicalCameraId = totalResult.getCameraId();
+ mResults = totalResult.getNativeMetadata();
+ mRequest = totalResult.getRequest();
+ mSequenceId = totalResult.getSequenceId();
+ mFrameNumber = totalResult.getFrameNumber();
+ mSessionId = totalResult.getSessionId();
+ for (CaptureResult partial : totalResult.getPartialResults()) {
+ mPartials.add(new CaptureResultWrapper(partial));
+ }
+ Map<String, TotalCaptureResult> physicalResults =
+ totalResult.getPhysicalCameraTotalResults();
+ for (TotalCaptureResult physicalResult : physicalResults.values()) {
+ mPhysicalResultList.add(new PhysicalCaptureResultInfo(physicalResult.getCameraId(),
+ physicalResult.getNativeMetadata()));
+ }
+ }
+
+ public TotalCaptureResultWrapper(Parcel parcel) {
+ mLogicalCameraId = parcel.readString();
+ mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader());
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ parcel.readParcelableList(mPartials, CaptureResultWrapper.class.getClassLoader());
+ mSessionId = parcel.readInt();
+ parcel.readParcelableList(mPhysicalResultList,
+ PhysicalCaptureResultInfo.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mLogicalCameraId);
+ parcel.writeParcelable(mResults, flags);
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ parcel.writeParcelableList(mPartials, flags);
+ parcel.writeInt(mSessionId);
+ parcel.writeParcelableList(mPhysicalResultList, flags);
+ }
+
+ public static final Parcelable.Creator<TotalCaptureResultWrapper> CREATOR
+ = new Parcelable.Creator<TotalCaptureResultWrapper>() {
+ @Override
+ public TotalCaptureResultWrapper createFromParcel(Parcel parcel) {
+ return new TotalCaptureResultWrapper(parcel);
+ }
+
+ @Override
+ public TotalCaptureResultWrapper[] newArray(int size) {
+ return new TotalCaptureResultWrapper[size];
+ }
+ };
+
+ public TotalCaptureResult toTotalCaptureResult() {
+ PhysicalCaptureResultInfo[] physicalResults = new PhysicalCaptureResultInfo[0];
+ if ((mPhysicalResultList != null) && (!mPhysicalResultList.isEmpty())) {
+ physicalResults = new PhysicalCaptureResultInfo[mPhysicalResultList.size()];
+ physicalResults = mPhysicalResultList.toArray(physicalResults);
+ }
+ ArrayList<CaptureResult> partials = new ArrayList<>(mPartials.size());
+ for (CaptureResultWrapper resultWrapper : mPartials) {
+ partials.add(resultWrapper.toCaptureResult());
+ }
+ return new TotalCaptureResult(
+ mLogicalCameraId, mResults,
+ mRequest, mSequenceId,
+ mFrameNumber, partials, mSessionId,
+ physicalResults);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java
new file mode 100644
index 00000000..32a765b9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ForwardAdvancedExtender implements AdvancedExtenderImpl {
+ private static final String TAG = "ForwardAdvancedExtender";
+ private IAdvancedExtenderImpl mIAdvancedExtender;
+ private String mCameraId;
+ private final int mExtensionType;
+ private ForwardSessionProcessor mForwardSessionProcessor;
+
+ public ForwardAdvancedExtender(int extensionType) {
+ mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl(
+ extensionType);
+ mExtensionType = extensionType;
+ }
+
+ private static ArrayList<Size> getSupportedSizes(SizeList sizesList) {
+ ArrayList<Size> ret = new ArrayList<>();
+ for (androidx.camera.extensions.impl.service.Size size : sizesList.sizes) {
+ ret.add(new Size(size.width, size.height));
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ try {
+ return mIAdvancedExtender.isExtensionAvailable(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isExtensionAvailable failed", e);
+ throw new IllegalStateException("isExtensionAvailable failed", e);
+ }
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ try {
+ mCameraId = cameraId;
+ mIAdvancedExtender.init(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "init failed", e);
+ throw new IllegalStateException("init failed", e);
+ }
+ }
+
+ @Override
+ @Nullable
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull String cameraId,
+ @NonNull Size captureOutputSize,
+ int imageFormat) {
+ try {
+ androidx.camera.extensions.impl.service.Size size =
+ new androidx.camera.extensions.impl.service.Size();
+ size.width = captureOutputSize.getWidth();
+ size.height = captureOutputSize.getHeight();
+ LatencyRange latencyRange =
+ mIAdvancedExtender.getEstimatedCaptureLatencyRange(cameraId,
+ size, imageFormat);
+ return new Range<>(latencyRange.min, latencyRange.max);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getEstimatedCaptureLatencyRange failed", e);
+ throw new IllegalStateException("getEstimatedCaptureLatencyRange failed", e);
+ }
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedPreviewOutputResolutions(
+ cameraId);
+ Map<Integer, List<Size>> result = new HashMap<>();
+ for (SizeList sizeList : sizeLists) {
+ result.put(sizeList.format, getSupportedSizes(sizeList));
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedPreviewOutputResolutions failed", e);
+ throw new IllegalStateException("getSupportedPreviewOutputResolutions failed", e);
+ }
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedCaptureOutputResolutions(
+ cameraId);
+ Map<Integer, List<Size>> result = new HashMap<>();
+ for (SizeList sizeList : sizeLists) {
+ result.put(sizeList.format, getSupportedSizes(sizeList));
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedCaptureOutputResolutions failed", e);
+ throw new IllegalStateException("getSupportedCaptureOutputResolutions failed", e);
+ }
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedYuvAnalysisResolutions(
+ cameraId);
+
+ if (sizeLists == null) {
+ return null;
+ }
+
+ for (SizeList sizeList : sizeLists) {
+ if (sizeList.format == ImageFormat.YUV_420_888) {
+ return getSupportedSizes(sizeList);
+ }
+ }
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedYuvAnalysisResolutions failed", e);
+ throw new IllegalStateException("getSupportedYuvAnalysisResolutions failed", e);
+ }
+ }
+
+ /**
+ * Re-initialize IAdvancedExtenderImpl when binder died.
+ */
+ private void ensureIAdvancedExtenderImplAlive() {
+ try {
+ if (!mIAdvancedExtender.asBinder().pingBinder()) {
+ Log.e(TAG, "IAdvancedExtenderImpl binder died, recreate");
+ mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl(
+ mExtensionType);
+ mIAdvancedExtender.init(mCameraId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't create IAdvancedExtenderImpl", e);
+ throw new IllegalStateException("can't create IAdvancedExtenderImpl", e);
+ }
+ }
+ /**
+ * Re-initialize ISessionProcessImpl when binder died.
+ */
+ ISessionProcessorImpl recreateISessionProcessor() {
+ Log.e(TAG, "Recreating ISessionProcessorImpl");
+ try {
+ ensureIAdvancedExtenderImplAlive();
+ return mIAdvancedExtender.getSessionProcessor();
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ throw new IllegalStateException(
+ "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ }
+ }
+
+ @Override
+ @NonNull
+ public SessionProcessorImpl createSessionProcessor() {
+ try {
+ ISessionProcessorImpl sessionProcessor = mIAdvancedExtender.getSessionProcessor();
+ mForwardSessionProcessor =
+ new ForwardSessionProcessor(this, sessionProcessor);
+ return mForwardSessionProcessor;
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ throw new IllegalStateException(
+ "can't get the SessionProcessor from IAdvancedExtenderImpl", e); }
+ }
+
+ @Override
+ @Nullable
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIAdvancedExtender.getAvailableCaptureRequestKeys(mCameraId);
+
+ CaptureRequest captureRequest = cameraMetadataWrapper.toCaptureRequest();
+
+ List<CaptureRequest.Key> result = new ArrayList<>();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureRequestKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e);
+ }
+ }
+
+ @Override
+ @Nullable
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIAdvancedExtender.getAvailableCaptureResultKeys(mCameraId);
+ TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult();
+
+ List<CaptureResult.Key> result = new ArrayList<>();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureRequestKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e);
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java
new file mode 100644
index 00000000..bdb87be7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_IMAGEREADER;
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_SURFACE;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.Binder;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImplBuilder;
+import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
+import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImplBuilder;
+import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
+import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
+import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.OutputSurface;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ForwardSessionProcessor implements SessionProcessorImpl {
+ private static final String TAG = "ForwardSessionProcessor";
+ private final ForwardAdvancedExtender mForwardAdvancedExtender;
+
+ private ISessionProcessorImpl mISessionProcessor;
+ public ForwardSessionProcessor(@NonNull ForwardAdvancedExtender forwardAdvancedExtender,
+ @NonNull ISessionProcessorImpl sessionProcessor) {
+ mForwardAdvancedExtender = forwardAdvancedExtender;
+ mISessionProcessor = sessionProcessor;
+ }
+
+ private OutputSurface getOutputSurface(OutputSurfaceImpl outputSurfaceImpl) {
+ OutputSurface outputSurface = new OutputSurface();
+
+ androidx.camera.extensions.impl.service.Size extSize =
+ new androidx.camera.extensions.impl.service.Size();
+ extSize.width = outputSurfaceImpl.getSize().getWidth();
+ extSize.height = outputSurfaceImpl.getSize().getHeight();
+ outputSurface.size = extSize;
+ outputSurface.imageFormat = outputSurfaceImpl.getImageFormat();
+ outputSurface.surface = outputSurfaceImpl.getSurface();
+ return outputSurface;
+ }
+
+ @Override
+ @NonNull
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) {
+ return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig,
+ imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig,
+ /* isRecoveringFromBinderDeath */ false);
+ }
+
+ @NonNull
+ private Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig,
+ boolean isRecoveringFromBinderDeath) {
+ try {
+ OutputSurface outputSurfacePreview = getOutputSurface(previewSurfaceConfig);
+ OutputSurface outputSurfaceCapture = getOutputSurface(imageCaptureSurfaceConfig);
+ OutputSurface outputSurfaceAnalysis = null;
+ if (imageAnalysisSurfaceConfig != null) {
+ outputSurfaceAnalysis = getOutputSurface(imageAnalysisSurfaceConfig);
+ }
+
+ CameraSessionConfig sessionConfig = mISessionProcessor.initSession(
+ cameraId,
+ outputSurfacePreview,
+ outputSurfaceCapture,
+ outputSurfaceAnalysis);
+
+ Camera2SessionConfigImplBuilder sessionConfigBuilder =
+ new Camera2SessionConfigImplBuilder();
+ CaptureRequest captureRequest = sessionConfig.sessionParameter.toCaptureRequest();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ sessionConfigBuilder.addSessionParameter(objKey, captureRequest.get(objKey));
+ }
+ for (CameraOutputConfig outputConfig : sessionConfig.outputConfigs) {
+ Camera2OutputConfigImplBuilder builder =
+ getCamera2OutputConfigImplBuilder(outputConfig);
+ if (outputConfig.sharedSurfaceConfigs != null &&
+ (!outputConfig.sharedSurfaceConfigs.isEmpty())) {
+ for (CameraOutputConfig sharedSurfaceConfig :
+ outputConfig.sharedSurfaceConfigs) {
+ builder.addSurfaceSharingOutputConfig(
+ getCamera2OutputConfigImplBuilder(sharedSurfaceConfig).build());
+ }
+ }
+ sessionConfigBuilder.addOutputConfig(builder.build());
+ }
+
+ sessionConfigBuilder.setSessionTemplateId(sessionConfig.sessionTemplateId);
+ return sessionConfigBuilder.build();
+ } catch (RemoteException e) {
+ if ((e instanceof DeadObjectException) && !isRecoveringFromBinderDeath) {
+ // service died, reinitialize.
+ mISessionProcessor = mForwardAdvancedExtender.recreateISessionProcessor();
+ return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig
+ , imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig,
+ /* isRecoveringFromBinderDeath */ true );
+ }
+ Log.e(TAG, "initSession failed", e);
+ throw new IllegalStateException("initSession failed", e);
+ }
+ }
+
+ private static Camera2OutputConfigImplBuilder getCamera2OutputConfigImplBuilder(
+ CameraOutputConfig outputConfig) {
+ switch (outputConfig.type) {
+ case TYPE_SURFACE:
+ return Camera2OutputConfigImplBuilder
+ .newSurfaceConfig(outputConfig.surface)
+ .setPhysicalCameraId(outputConfig.physicalCameraId)
+ .setSurfaceGroupId(outputConfig.surfaceGroupId)
+ .setOutputConfigId(outputConfig.outputId);
+ case TYPE_IMAGEREADER:
+ android.util.Size size = new android.util.Size(
+ outputConfig.size.width, outputConfig.size.height);
+ return Camera2OutputConfigImplBuilder
+ .newImageReaderConfig(size, outputConfig.imageFormat, outputConfig.capacity)
+ .setPhysicalCameraId(outputConfig.physicalCameraId)
+ .setSurfaceGroupId(outputConfig.surfaceGroupId)
+ .setOutputConfigId(outputConfig.outputId);
+ case TYPE_MULTIRES_IMAGEREADER:
+ default:
+ throw new UnsupportedOperationException("Output config type not supported");
+ }
+ }
+
+ @Override
+ public void deInitSession() {
+ try {
+ mISessionProcessor.deInitSession();
+ } catch (RemoteException e) {
+ Log.e(TAG, "deInitSession failed", e);
+ throw new IllegalStateException("deInitSession failed", e);
+ }
+ }
+
+ @Override
+ public void setParameters(Map<CaptureRequest.Key<?>, Object> parameters) {
+ try {
+ mISessionProcessor.setParameters(PlatformApi.createCaptureRequest(parameters));
+ } catch (RemoteException e) {
+ Log.e(TAG, "setParameters failed", e);
+ // still capture normally will invoke setParameters first and then startCapture.
+ // We want to fail the startCapture not the setParameters so that the capture failure
+ // can be propagated to the app.
+ }
+ }
+
+ @Override
+ public int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startTrigger(PlatformApi.createCaptureRequest(triggers),
+ new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startTrigger failed", e);
+ throw new IllegalStateException("startTrigger failed", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSessionStart(RequestProcessorImpl requestProcessor) {
+ try {
+ mISessionProcessor.onCaptureSessionStart(
+ new RequestProcessorAdapter(requestProcessor));
+ } catch (RemoteException e) {
+ Log.e(TAG, "onCaptureSessionStart failed", e);
+ throw new IllegalStateException("onCaptureSessionStart failed", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSessionEnd() {
+ try {
+ mISessionProcessor.onCaptureSessionEnd();
+ } catch (RemoteException e) {
+ Log.e(TAG, "onCaptureSessionEnd failed", e);
+ throw new IllegalStateException("onCaptureSessionEnd failed", e);
+ }
+ }
+
+ @Override
+ public int startRepeating(CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startRepeating(new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startRepeating failed", e);
+ // notify the onCaptureFailed callback so that app is notified of the error.
+ callback.onCaptureFailed(0);
+ return 0;
+ }
+ }
+
+ @Override
+ public void stopRepeating() {
+ try {
+ mISessionProcessor.stopRepeating();
+ } catch (RemoteException e) {
+ Log.e(TAG, "stopRepeating failed", e);
+ throw new IllegalStateException("startRepeating failed", e);
+ }
+ }
+
+ @Override
+ public int startCapture(CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startCapture(new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startCapture failed", e);
+ // notify the onCaptureFailed callback so that app is notified of the error.
+ callback.onCaptureFailed(0);
+ return 0;
+ }
+ }
+
+ @Override
+ public void abortCapture(int captureSequenceId) {
+ try {
+ mISessionProcessor.abortCapture(captureSequenceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "abortCapture failed", e);
+ throw new IllegalStateException("abortCapture failed", e);
+ }
+ }
+
+ private static class CaptureCallbackAdapter extends ICaptureCallback.Stub {
+ private final SessionProcessorImpl.CaptureCallback mImplCaptureCallback;
+
+ CaptureCallbackAdapter(SessionProcessorImpl.CaptureCallback implCaptureCallback) {
+ mImplCaptureCallback = implCaptureCallback;
+ }
+
+ @Override
+ public void onCaptureStarted(int captureSequenceId, long timeStamp) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureStarted(captureSequenceId, timeStamp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureProcessStarted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureProcessStarted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureFailed(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureFailed(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureSequenceAborted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp, int captureSequenceId,
+ CameraMetadataWrapper cameraMetadataWrapper)
+ throws RemoteException {
+ TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult();
+
+ Map<CaptureResult.Key, Object> resultmap = new HashMap<>();
+ for (CaptureResult.Key key : captureResult.getKeys()) {
+ resultmap.put(key, captureResult.get(key));
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureCompleted(shutterTimestamp, captureSequenceId,
+ resultmap);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java
new file mode 100644
index 00000000..a40a16d0
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.util.Map;
+
+public class PlatformApi {
+ public static CaptureRequest createCaptureRequest(
+ Map<CaptureRequest.Key<?>, Object> parameters) {
+ CameraMetadataNative metadataNative = new CameraMetadataNative();
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(metadataNative, false, -1, "0", null);
+
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ builder.set(objKey, parameters.get(objKey));
+ }
+ return builder.build();
+ }
+
+ public static CaptureRequest createCaptureRequest(CameraMetadataNative cameraMetadataNative) {
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(cameraMetadataNative, false, -1, "0", null);
+ return builder.build();
+ }
+
+ public static TotalCaptureResult createTotalCaptureResult(
+ CameraMetadataNative cameraMetadataNative) {
+ return new TotalCaptureResult(cameraMetadataNative, 0);
+ }
+
+ public static CameraMetadataNative createCameraMetadataNative(
+ Map<CaptureRequest.Key<?>, Object> parameters) {
+ CameraMetadataNative metadataNative = new CameraMetadataNative();
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ metadataNative.set(objKey, parameters.get(objKey));
+ }
+ return metadataNative;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java
new file mode 100644
index 00000000..3cc1d24c
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
+import androidx.camera.extensions.impl.advanced.ImageReferenceImpl;
+import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.IImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import androidx.camera.extensions.impl.service.Request;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class RequestProcessorAdapter extends IRequestProcessorImpl.Stub {
+ private static final String TAG = "RequestProcessorAdapter";
+
+ private RequestProcessorImpl mRequestProcessorImpl;
+ RequestProcessorAdapter(RequestProcessorImpl requestProcessorImpl) {
+ mRequestProcessorImpl = requestProcessorImpl;
+ }
+ @Override
+ public void setImageProcessor(int outputfigId, IImageProcessorImpl imageProcessor)
+ throws RemoteException {
+ mRequestProcessorImpl.setImageProcessor(outputfigId, new ImageProcessorImpl() {
+ @Override
+ public void onNextImageAvailable(int outputConfigId, long timestampNs,
+ ImageReferenceImpl imageReference, String physicalCameraId) {
+ try {
+ imageProcessor.onNextImageAvailable(outputConfigId,
+ new ImageWrapper(imageReference.get()), physicalCameraId);
+ imageReference.decrement();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public int submit(Request request, IRequestCallback requestCallback)
+ throws RemoteException {
+ return submitBurst(Arrays.asList(request), requestCallback);
+ }
+
+ @Override
+ public int submitBurst(List<Request> requests, IRequestCallback requestCallback)
+ throws RemoteException {
+ List<RequestProcessorImpl.Request> implRequests = new ArrayList<>();
+ Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>();
+ for (Request request : requests) {
+ RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request);
+ implRequests.add(implRequest);
+ requestsMap.put(implRequest, request);
+ }
+ return mRequestProcessorImpl.submit(implRequests,
+ new ImplCaptureCallbackAdapter(requestsMap, requestCallback));
+ }
+
+ @Override
+ public int setRepeating(Request request, IRequestCallback requestCallback)
+ throws RemoteException {
+ Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>();
+ RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request);
+ requestsMap.put(implRequest, request);
+
+ return mRequestProcessorImpl.setRepeating(implRequest,
+ new ImplCaptureCallbackAdapter(requestsMap, requestCallback));
+ }
+
+ @Override
+ public void abortCaptures() throws RemoteException {
+ mRequestProcessorImpl.abortCaptures();
+ }
+
+ @Override
+ public void stopRepeating() throws RemoteException {
+ mRequestProcessorImpl.stopRepeating();
+ }
+
+ private static class ImplRequestAdapter implements RequestProcessorImpl.Request {
+ private Request mRequest;
+ ImplRequestAdapter(Request request) {
+ mRequest = request;
+ }
+
+ @Override
+ public List<Integer> getTargetOutputConfigIds() {
+ List<Integer> result = new ArrayList<>(mRequest.targetOutputConfigIds.length);
+ for (int id : mRequest.targetOutputConfigIds) {
+ result.add(id);
+ }
+ return result;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getParameters() {
+ CaptureRequest captureRequest = mRequest.parameters.toCaptureRequest();
+ Map<CaptureRequest.Key<?>, Object> parameters = new HashMap<>();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ parameters.put(key, captureRequest.get(key));
+ }
+ return parameters;
+ }
+
+ @Override
+ public Integer getTemplateId() {
+ return mRequest.templateId;
+ }
+ }
+
+ private static class ImplCaptureCallbackAdapter implements RequestProcessorImpl.Callback {
+ private Map<RequestProcessorImpl.Request, Request> mRequestsMap;
+ private IRequestCallback mRequestCallback;
+ ImplCaptureCallbackAdapter(Map<RequestProcessorImpl.Request, Request> requestsMap,
+ IRequestCallback requestCallback) {
+ mRequestCallback = requestCallback;
+ mRequestsMap = requestsMap;
+ }
+
+ private Request getRequest(RequestProcessorImpl.Request implRequest) {
+ return mRequestsMap.get(implRequest);
+ }
+
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request implRequest, long frameNumber,
+ long timestamp) {
+ try {
+ mRequestCallback.onCaptureStarted(getRequest(implRequest).requestId,
+ frameNumber, timestamp);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request implRequest,
+ CaptureResult partialResult) {
+ try {
+ mRequestCallback.onCaptureProgressed(getRequest(implRequest).requestId,
+ new CaptureResultWrapper(partialResult));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request implRequest,
+ TotalCaptureResult totalCaptureResult) {
+ try {
+ mRequestCallback.onCaptureCompleted(getRequest(implRequest).requestId,
+ new TotalCaptureResultWrapper(totalCaptureResult));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request implRequest,
+ CaptureFailure captureFailure) {
+ try {
+
+ mRequestCallback.onCaptureFailed(getRequest(implRequest).requestId,
+ new CaptureFailureWrapper(captureFailure));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request implRequest, long frameNumber,
+ int outputStreamId) {
+ try {
+ mRequestCallback.onCaptureBufferLost(getRequest(implRequest).requestId,
+ frameNumber, outputStreamId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ try {
+ mRequestCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ try {
+ mRequestCallback.onCaptureSequenceAborted(sequenceId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java
new file mode 100644
index 00000000..7e27a7b6
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.InitializerImpl;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IExtensionsService;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+public class ServiceManager {
+ private static final String TAG = "ServiceManager";
+ private static final int SERVICE_DELAY_MS = 1000;
+ private static final String SERVICE_PACKAGE_NAME = "com.android.oemextensions";
+ private static final String SERVICE_SERVICE_NAME =
+ "com.android.oemextensions.ExtensionsService";
+
+ private static ServiceManager sServiceManager;
+ private static final Object mLock = new Object();
+
+ public static void init(@Nullable Context context, @NonNull String version,
+ @NonNull InitializerImpl.OnExtensionsInitializedCallback callback,
+ @NonNull Executor executor) {
+ synchronized (mLock) {
+ if (sServiceManager == null) {
+ sServiceManager = new ServiceManager(context);
+ }
+ sServiceManager.bindServiceSync(context);
+ }
+
+ try {
+ sServiceManager.mExtensionService.initialize(version,
+ new IOnExtensionsInitializedCallback.Stub() {
+ @Override
+ public void onSuccess() throws RemoteException {
+ executor.execute( () -> {
+ callback.onSuccess();
+ Log.d(TAG, "success!");
+ });
+ }
+
+ @Override
+ public void onFailure(int error) throws RemoteException {
+ executor.execute( () -> {
+ callback.onFailure(error);
+ });
+ }
+ });
+ } catch (RemoteException e){
+ throw new IllegalStateException("Failed to connect to extensions service", e);
+ }
+ }
+
+ @NonNull
+ public static ServiceManager getInstance() {
+ return sServiceManager;
+ }
+
+ public ServiceManager(@NonNull Context context) {
+ mContext = context;
+ }
+
+ Context mContext;
+
+ ServiceConnection mServiceConnection;
+ IExtensionsService mExtensionService;
+
+ void bindServiceSync(Context context) {
+ if (mServiceConnection == null) {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder binder) {
+ mExtensionService = IExtensionsService.Stub.asInterface(binder);
+ Log.d(TAG, "service connected");
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ Log.e(TAG, "service disconnected");
+ mExtensionService = null;
+ mServiceConnection = null;
+ }
+ };
+
+ Intent intent = new Intent();
+ intent.setClassName(SERVICE_PACKAGE_NAME, SERVICE_SERVICE_NAME);
+ Log.d(TAG, "bindService start. intent = " + intent);
+ context.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |
+ Context.BIND_ABOVE_CLIENT, AsyncTask.THREAD_POOL_EXECUTOR,
+ mServiceConnection);
+
+ try {
+ boolean success = countDownLatch.await(SERVICE_DELAY_MS, TimeUnit.MILLISECONDS);
+ if (!success) {
+ Log.e(TAG, "Timed out while initializing proxy service!");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while initializing proxy service!");
+ }
+ }
+ }
+
+ public void deinit(@NonNull InitializerImpl.OnExtensionsDeinitializedCallback callback,
+ @NonNull Executor executor) {
+ try {
+ mExtensionService.deInitialize(new IOnExtensionsDeinitializedCallback.Stub() {
+ @Override
+ public void onSuccess() throws RemoteException {
+ executor.execute( () -> {
+ callback.onSuccess();
+ });
+ }
+
+ @Override
+ public void onFailure(int error) throws RemoteException {
+ executor.execute( () -> {
+ callback.onFailure(error);
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to connect to extensions service", e);
+ }
+ }
+
+ @NonNull
+ public IAdvancedExtenderImpl createAdvancedExtenderImpl(int extensionType) {
+ try {
+ synchronized (mLock) {
+ if (mExtensionService == null) {
+ bindServiceSync(mContext);
+ }
+ }
+ return mExtensionService.initializeAdvancedExtension(extensionType);
+ } catch (RemoteException e) {
+ Log.e(TAG, "initializeAdvancedExtension failed", e);
+ throw new IllegalStateException("initializeAdvancedExtension failed", e);
+ }
+ }
+}