Merge Android 12
Bug: 202323961
Merged-In: Ied4e7a153b46e23aaca665b7812fafb2449357e2
Change-Id: I8b3b281b084629ad4a01afd87b4b7d1c92a990c5
diff --git a/camera2/extensions/README.android b/camera2/extensions/README.android
new file mode 100644
index 0000000..8c1a70a
--- /dev/null
+++ b/camera2/extensions/README.android
@@ -0,0 +1,12 @@
+Library Name: CameraX Extension stub and sample
+License: Apache 2
+Description: The CameraX Extension stub library along with a very basic sample
+implementation. The stub includes extension API versions 1.2.0, 1.1.0 and older.
+
+Local patches
+-------------
+- No changes to the stubs
+- Minor modifications to the sample implementation switching effects to white balance modes
+- The HDR preview processor doesn't use GL to render to the registered output surface instead
+ it will just attach the incoming image
+
diff --git a/camera2/extensions/sample/Android.bp b/camera2/extensions/sample/Android.bp
new file mode 100644
index 0000000..7029175
--- /dev/null
+++ b/camera2/extensions/sample/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 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: "androidx.camera.extensions.impl",
+ installable: true,
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "current",
+ vendor: true,
+}
+
+prebuilt_etc {
+ name: "sample_camera_extensions.xml",
+ src: "camera_extensions.xml",
+ sub_dir: "permissions",
+ vendor: true,
+}
diff --git a/camera2/extensions/sample/camera_extensions.xml b/camera2/extensions/sample/camera_extensions.xml
new file mode 100644
index 0000000..3f8c637
--- /dev/null
+++ b/camera2/extensions/sample/camera_extensions.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <library name="androidx.camera.extensions.impl"
+ file="/vendor/framework/androidx.camera.extensions.impl.jar"/>
+</permissions>
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..cabcaae
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -0,0 +1,235 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation for auto image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ private static final String TAG = "AutoICExtender";
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_DAYLIGHT;
+
+ /**
+ * @hide
+ */
+ public AutoImageCaptureExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ // Placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ List<CaptureStageImpl> captureStages = new ArrayList<>();
+ captureStages.add(captureStage);
+ return captureStages;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ CaptureProcessorImpl captureProcessor =
+ new CaptureProcessorImpl() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ Log.d(TAG, "Started auto CaptureProcessor");
+
+ Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
+
+ if (result == null) {
+ Log.w(TAG,
+ "Unable to process since images does not contain all stages.");
+ return;
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Image image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // Sample here just simply copy/paste the capture image result
+ yByteBuffer.put(result.first.getPlanes()[0].getBuffer());
+ uByteBuffer.put(result.first.getPlanes()[2].getBuffer());
+ vByteBuffer.put(result.first.getPlanes()[1].getBuffer());
+
+ mImageWriter.queueInputImage(image);
+ }
+ }
+
+ // Close all input images
+ for (Pair<Image, TotalCaptureResult> imageDataPair : results.values()) {
+ imageDataPair.first.close();
+ }
+
+ Log.d(TAG, "Completed auto CaptureProcessor");
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+ return captureProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getMaxCaptureStage() {
+ return 3;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
new file mode 100755
index 0000000..5018df8
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -0,0 +1,165 @@
+/*
+ * 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.util.Pair;
+import android.util.Size;
+
+import java.util.List;
+
+/**
+ * Implementation for auto preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl {
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_DAYLIGHT;
+
+ /**
+ * @hide
+ */
+ public AutoPreviewExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Implement the logic to check whether the extension function is supported or not.
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorImpl getProcessor() {
+ return RequestUpdateProcessorImpls.noUpdateProcessor();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..7297314
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -0,0 +1,258 @@
+/*
+ * 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.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation for beauty image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ private static final String TAG = "BeautyICExtender";
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_TWILIGHT;
+
+ private CameraCharacteristics mCameraCharacteristics;
+
+ public BeautyImageCaptureExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ mCameraCharacteristics = cameraCharacteristics;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ // Placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ List<CaptureStageImpl> captureStages = new ArrayList<>();
+ captureStages.add(captureStage);
+ return captureStages;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ CaptureProcessorImpl captureProcessor =
+ new CaptureProcessorImpl() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ Log.d(TAG, "Started beauty CaptureProcessor");
+
+ Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
+
+ if (result == null) {
+ Log.w(TAG,
+ "Unable to process since images does not contain all stages.");
+ return;
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Image image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // Sample here just simply copy/paste the capture image result
+ yByteBuffer.put(result.first.getPlanes()[0].getBuffer());
+ uByteBuffer.put(result.first.getPlanes()[2].getBuffer());
+ vByteBuffer.put(result.first.getPlanes()[1].getBuffer());
+
+ mImageWriter.queueInputImage(image);
+ }
+ }
+
+ // Close all input images
+ for (Pair<Image, TotalCaptureResult> imageDataPair : results.values()) {
+ imageDataPair.first.close();
+ }
+
+ Log.d(TAG, "Completed beauty CaptureProcessor");
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+ return captureProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getMaxCaptureStage() {
+ return 3;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
+
+ StreamConfigurationMap map =
+ mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ if (map != null) {
+ // The sample implementation only retrieves originally supported resolutions from
+ // CameraCharacteristics for JPEG and YUV_420_888 formats to return.
+ Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG);
+
+ if (outputSizes != null) {
+ formatResolutionsPairList.add(Pair.create(ImageFormat.JPEG, outputSizes));
+ }
+
+ outputSizes = map.getOutputSizes(ImageFormat.YUV_420_888);
+
+ if (outputSizes != null) {
+ formatResolutionsPairList.add(Pair.create(ImageFormat.YUV_420_888, outputSizes));
+ }
+ }
+
+ return formatResolutionsPairList;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
new file mode 100755
index 0000000..fcc78d5
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -0,0 +1,186 @@
+/*
+ * 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.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.util.Pair;
+import android.util.Size;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation for beauty preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl {
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_TWILIGHT;
+
+ /**
+ * @hide
+ */
+ private CameraCharacteristics mCameraCharacteristics;
+
+ /**
+ * @hide
+ */
+ public BeautyPreviewExtenderImpl() {
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ mCameraCharacteristics = cameraCharacteristics;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Implement the logic to check whether the extension function is supported or not.
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorImpl getProcessor() {
+ return RequestUpdateProcessorImpls.noUpdateProcessor();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
+
+ StreamConfigurationMap map =
+ mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ if (map != null) {
+ // The sample implementation only retrieves originally supported resolutions from
+ // CameraCharacteristics for PRIVATE format to return.
+ Size[] outputSizes = map.getOutputSizes(ImageFormat.PRIVATE);
+
+ if (outputSizes != null) {
+ formatResolutionsPairList.add(Pair.create(ImageFormat.PRIVATE, outputSizes));
+ }
+ }
+
+ return formatResolutionsPairList;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..db57461
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -0,0 +1,232 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation for bokeh image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ private static final String TAG = "BokehICExtender";
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+
+ /**
+ * @hide
+ */
+ public BokehImageCaptureExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Requires API 23 for ImageWriter
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ // Placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ List<CaptureStageImpl> captureStages = new ArrayList<>();
+ captureStages.add(captureStage);
+ return captureStages;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ CaptureProcessorImpl captureProcessor =
+ new CaptureProcessorImpl() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ Log.d(TAG, "Started bokeh CaptureProcessor");
+
+ Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
+
+ if (result == null) {
+ Log.w(TAG,
+ "Unable to process since images does not contain all stages.");
+ return;
+ } else {
+ if (android.os.Build.VERSION.SDK_INT
+ >= android.os.Build.VERSION_CODES.M) {
+ Image image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // Sample here just simply copy/paste the capture image result
+ yByteBuffer.put(result.first.getPlanes()[0].getBuffer());
+ uByteBuffer.put(result.first.getPlanes()[2].getBuffer());
+ vByteBuffer.put(result.first.getPlanes()[1].getBuffer());
+
+ mImageWriter.queueInputImage(image);
+ }
+ }
+
+ // Close all input images
+ for (Pair<Image, TotalCaptureResult> imageDataPair : results.values()) {
+ imageDataPair.first.close();
+ }
+
+ Log.d(TAG, "Completed bokeh CaptureProcessor");
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+ return captureProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getMaxCaptureStage() {
+ return 3;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
new file mode 100644
index 0000000..8c43d34
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -0,0 +1,204 @@
+/*
+ * 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.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.List;
+
+/**
+ * Implementation for bokeh preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl {
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+
+ SettableCaptureStage mCaptureStage;
+
+ /**
+ * @hide
+ */
+ public BokehPreviewExtenderImpl() {}
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ mCaptureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ mCaptureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE,
+ CaptureRequest.CONTROL_AWB_MODE_AUTO);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Implement the logic to check whether the extension function is supported or not.
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ return mCaptureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ }
+
+ /**
+ * @hide
+ */
+ // Switches effect every 90 frames
+ private RequestUpdateProcessorImpl mRequestUpdateProcessor = new RequestUpdateProcessorImpl() {
+ private int mFrameCount = 0;
+ private Integer mWBMode = CaptureRequest.CONTROL_AWB_MODE_AUTO;
+
+ @Override
+ public CaptureStageImpl process(TotalCaptureResult result) {
+ mFrameCount++;
+ if (mFrameCount % 90 == 0) {
+ mCaptureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ switch (mWBMode) {
+ case CaptureRequest.CONTROL_AWB_MODE_AUTO:
+ mWBMode = MODE;
+ break;
+ case MODE:
+ mWBMode = CaptureRequest.CONTROL_AWB_MODE_AUTO;
+ break;
+ default:
+ }
+ mCaptureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE,
+ mWBMode);
+ mFrameCount = 0;
+
+ return mCaptureStage;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {}
+
+ @Override
+ public void onResolutionUpdate(Size size) {}
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {}
+ };
+
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorImpl getProcessor() {
+ return mRequestUpdateProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CameraCharacteristicAvailability.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CameraCharacteristicAvailability.java
new file mode 100644
index 0000000..0b51c7c
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CameraCharacteristicAvailability.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 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.CameraCharacteristics;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * A utility class to check the availabilities of camera characteristics.
+ */
+final class CameraCharacteristicAvailability {
+ private static final String TAG = "CharacteristicAbility";
+
+ private CameraCharacteristicAvailability() {
+ }
+
+ /**
+ * Check if the given white balance mode id is available in the camera characteristics.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @param mode white balance mode id.
+ * @return {@code true} if the given white balance mode id is available in the camera
+ * characteristics.
+ * {@code false} otherwise.
+ */
+ static boolean isWBModeAvailable(CameraCharacteristics cameraCharacteristics,
+ int mode) {
+ int[] availableModes = cameraCharacteristics.get(
+ CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);
+ if (availableModes == null) {
+ Log.d(TAG, "No CONTROL_AWB_AVAILABLE_MODES info");
+ return false;
+ }
+
+ for (int availableMode : availableModes) {
+ if (availableMode == mode) {
+ return true;
+ }
+ }
+ Log.d(TAG, "wb mode: " + mode + " is not in available list "
+ + Arrays.toString(availableModes));
+ return false;
+ }
+
+ /**
+ * Check if the given effect id is available in the camera characteristics.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @param effect the effect id.
+ * @return {@code true} if the given effect id is available in the camera characteristics.
+ * {@code false} otherwise.
+ */
+ static boolean isEffectAvailable(CameraCharacteristics cameraCharacteristics,
+ int effect) {
+ int[] availableEffects = cameraCharacteristics.get(
+ CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS);
+ if (availableEffects == null) {
+ Log.d(TAG, "No CONTROL_AVAILABLE_EFFECTS info");
+ return false;
+ }
+
+ for (int availableEffect : availableEffects) {
+ if (availableEffect == effect) {
+ return true;
+ }
+ }
+ Log.d(TAG, "effect: " + effect + " is not in available list "
+ + Arrays.toString(availableEffects));
+ return false;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
new file mode 100644
index 0000000..1a257e2
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -0,0 +1,76 @@
+/*
+ * 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 android.media.Image;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.Map;
+
+/**
+ * The interface for processing a set of {@link Image}s that have captured.
+ *
+ * @since 1.0
+ * @hide
+ */
+public interface CaptureProcessorImpl {
+ /**
+ * This gets called to update where the CaptureProcessor should write the output of {@link
+ * #process(Map)}.
+ *
+ * @param surface The {@link Surface} that the CaptureProcessor should write data into.
+ * @param imageFormat The format of that the surface expects.
+ * @hide
+ */
+ void onOutputSurface(Surface surface, int imageFormat);
+
+ /**
+ * 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 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.
+ * @hide
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
+
+ /**
+ * This callback will be invoked when CameraX changes the configured input resolution. After
+ * this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as input
+ * to be at the specified resolution.
+ *
+ * @param size for the surface.
+ * @hide
+ */
+ void onResolutionUpdate(Size size);
+
+ /**
+ * This callback will be invoked when CameraX changes the configured input image format.
+ * After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ * @hide
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
new file mode 100644
index 0000000..268a49d
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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 java.util.List;
+
+/**
+ * The set of parameters that defines a single capture that will be sent to the camera.
+ *
+ * @since 1.0
+ * @hide
+ */
+public interface CaptureStageImpl {
+ /** Returns the identifier for the {@link CaptureStageImpl}. */
+ /**
+ * @hide
+ */
+ int getId();
+
+ /**
+ * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
+ * set for a single {@link CaptureRequest}.
+ */
+ /**
+ * @hide
+ */
+ List<Pair<CaptureRequest.Key, Object>> getParameters();
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
new file mode 100644
index 0000000..f926cff
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -0,0 +1,87 @@
+/*
+ * 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.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+/**
+ * Provides interfaces that the OEM needs to implement to handle the state change.
+ *
+ * @since 1.0
+ * @hide
+ */
+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.
+ * @hide
+ */
+ void onInit(String cameraId, CameraCharacteristics cameraCharacteristics, 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.
+ * @hide
+ */
+ void onDeInit();
+
+ /**
+ * This will be invoked before creating a
+ * {@link android.hardware.camera2.CameraCaptureSession}. The {@link CaptureRequest}
+ * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
+ * part of the capture session initialization via setSessionParameters(). The valid parameter
+ * is a subset of the available capture request parameters.
+ *
+ * @return The request information to set the session wide camera parameters.
+ * @hide
+ */
+ CaptureStageImpl onPresetSession();
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.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.
+ * @hide
+ */
+ CaptureStageImpl onEnableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.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.
+ * @hide
+ */
+ CaptureStageImpl onDisableSession();
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
new file mode 100644
index 0000000..76cc2c4
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -0,0 +1,70 @@
+/*
+ * 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.Log;
+
+/**
+ * Implementation for extension version check.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public class ExtensionVersionImpl {
+ private static final String TAG = "ExtenderVersionImpl";
+ private static final String VERSION = "1.1.0";
+
+ /**
+ * @hide
+ */
+ 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.
+ */
+ /**
+ * @hide
+ */
+ public String checkApiVersion(String version) {
+ Log.d(TAG, "Extension device library version " + VERSION);
+ return VERSION;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..d6f017f
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -0,0 +1,250 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementation for HDR image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ private static final String TAG = "HdrImageCaptureExtender";
+ private static final int UNDER_STAGE_ID = 0;
+ private static final int NORMAL_STAGE_ID = 1;
+ private static final int OVER_STAGE_ID = 2;
+ private static final int SESSION_STAGE_ID = 101;
+
+ /**
+ * @hide
+ */
+ public HdrImageCaptureExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Requires API 23 for ImageWriter
+ return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ // Under exposed capture stage
+ SettableCaptureStage captureStageUnder = new SettableCaptureStage(UNDER_STAGE_ID);
+ // Turn off AE so that ISO sensitivity can be controlled
+ captureStageUnder.addCaptureRequestParameters(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_OFF);
+ captureStageUnder.addCaptureRequestParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(8));
+
+ // Normal exposed capture stage
+ SettableCaptureStage captureStageNormal = new SettableCaptureStage(NORMAL_STAGE_ID);
+ captureStageNormal.addCaptureRequestParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(16));
+
+ // Over exposed capture stage
+ SettableCaptureStage captureStageOver = new SettableCaptureStage(OVER_STAGE_ID);
+ captureStageOver.addCaptureRequestParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(32));
+
+ List<CaptureStageImpl> captureStages = new ArrayList<>();
+ captureStages.add(captureStageUnder);
+ captureStages.add(captureStageNormal);
+ captureStages.add(captureStageOver);
+ return captureStages;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ CaptureProcessorImpl captureProcessor =
+ new CaptureProcessorImpl() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ Log.d(TAG, "Started HDR CaptureProcessor");
+
+ // Check for availability of all requested images
+ if (!results.containsKey(UNDER_STAGE_ID)) {
+ Log.w(TAG,
+ "Unable to process since images does not contain "
+ + "underexposed image.");
+ return;
+ }
+
+ if (!results.containsKey(NORMAL_STAGE_ID)) {
+ Log.w(TAG,
+ "Unable to process since images does not contain normal "
+ + "exposed image.");
+ return;
+ }
+
+ if (!results.containsKey(OVER_STAGE_ID)) {
+ Log.w(TAG,
+ "Unable to process since images does not contain "
+ + "overexposed image.");
+ return;
+ }
+
+ // Do processing of images, our placeholder logic just copies the first
+ // Image into the output buffer.
+ List<Pair<Image, TotalCaptureResult>> imageDataPairs = new ArrayList<>(
+ results.values());
+ Image image = null;
+ if (android.os.Build.VERSION.SDK_INT
+ >= android.os.Build.VERSION_CODES.M) {
+ image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // Sample here just simply return the normal image result
+ yByteBuffer.put(imageDataPairs.get(1).first.getPlanes()[0].getBuffer());
+ uByteBuffer.put(imageDataPairs.get(1).first.getPlanes()[2].getBuffer());
+ vByteBuffer.put(imageDataPairs.get(1).first.getPlanes()[1].getBuffer());
+
+ mImageWriter.queueInputImage(image);
+ }
+
+ // Close all input images
+ for (Pair<Image, TotalCaptureResult> imageDataPair : imageDataPairs) {
+ imageDataPair.first.close();
+ }
+
+ Log.d(TAG, "Completed HDR CaptureProcessor");
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+ return captureProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getMaxCaptureStage() {
+ return 4;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
new file mode 100644
index 0000000..2a47109
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -0,0 +1,179 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.ImageWriter;
+import android.media.Image;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.List;
+
+/**
+ * Implementation for HDR preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
+ private static final int DEFAULT_STAGE_ID = 0;
+
+ ImageWriter mWriter;
+
+ /**
+ * @hide
+ */
+ public HdrPreviewExtenderImpl() { }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Implement the logic to check whether the extension function is supported or not.
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorImpl getProcessor() {
+ return mProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ private PreviewImageProcessorImpl mProcessor = new PreviewImageProcessorImpl() {
+ Surface mSurface;
+ int mFormat = -1;
+
+ private void setWindowSurface() {
+ if (mSurface != null && mFormat >= 0) {
+ if (mWriter != null) {
+ mWriter.close();
+ }
+
+ mWriter = ImageWriter.newInstance(mSurface, 2, mFormat);
+ }
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ mSurface = surface;
+ mFormat = imageFormat;
+ setWindowSurface();
+ }
+
+ @Override
+ public void process(Image image, TotalCaptureResult result) {
+ mWriter.queueInputImage(image);
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+ if (mWriter != null) {
+ mWriter.close();
+ mWriter = null;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ return null;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..b70038f
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.Pair;
+import android.util.Size;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions for image capture.
+ *
+ * @since 1.0
+ * @hide
+ */
+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
+ * @hide
+ */
+ boolean isExtensionAvailable(String cameraId, 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.
+ * @hide
+ */
+ void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The processing that will be done on a set of captures to create and image with the effect.
+ * @hide
+ */
+ CaptureProcessorImpl getCaptureProcessor();
+
+ /**
+ * @hide
+ */
+ /** The set of captures that are needed to create an image with the effect. */
+ List<CaptureStageImpl> getCaptureStages();
+
+ /**
+ * Returns the maximum size of the list returned by {@link #getCaptureStages()}.
+ * @return the maximum count.
+ * @hide
+ */
+ 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 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
+ * @hide
+ */
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+}
+
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/InitializerImpl.java
new file mode 100644
index 0000000..fe2afd5
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/InitializerImpl.java
@@ -0,0 +1,129 @@
+/*
+ * 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 java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ * Used for initializing the extensions library.
+ *
+ * @since 1.1
+ * @hide
+ */
+public class InitializerImpl {
+ private InitializerImpl() {
+ }
+
+ private static final String TAG = "InitializerImpl";
+ /**
+ * An unknown error has occurred.
+ * @hide
+ */
+ public static final int ERROR_UNKNOWN = 0;
+ /**
+ * Error reported if the application version of extensions is incompatible with the on device
+ * library version.
+ * @hide
+ */
+ public static final int ERROR_INITIALIZE_VERSION_INCOMPATIBLE = 1;
+ private static Executor sExecutor = Executors.newSingleThreadExecutor();
+
+ /**
+ * 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.
+ * @hide
+ */
+ public static void init(String version, Context context,
+ OnExtensionsInitializedCallback callback, Executor executor) {
+ Log.d(TAG, "initializing extensions");
+ if (executor == null) {
+ sExecutor.execute(callback::onSuccess);
+ } else {
+ executor.execute(callback::onSuccess);
+ }
+ }
+
+ /**
+ * 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.
+ * @hide
+ */
+ public static void deinit(OnExtensionsDeinitializedCallback callback,
+ Executor executor) {
+ Log.d(TAG, "deinitializing extensions");
+ if (executor == null) {
+ sExecutor.execute(callback::onSuccess);
+ } else {
+ executor.execute(callback::onSuccess);
+ }
+ }
+
+ /**
+ * Callback that gets called when the library has finished initializing and is ready for used.
+ * @hide
+ */
+ 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.
+ * @hide
+ */
+ 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/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..3d00a46
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -0,0 +1,235 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation for night image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class NightImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ private static final String TAG = "NightICExtender";
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_INCANDESCENT;
+
+ /**
+ * @hide
+ */
+ public NightImageCaptureExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ // Placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ List<CaptureStageImpl> captureStages = new ArrayList<>();
+ captureStages.add(captureStage);
+ return captureStages;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ CaptureProcessorImpl captureProcessor =
+ new CaptureProcessorImpl() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ Log.d(TAG, "Started night CaptureProcessor");
+
+ Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
+
+ if (result == null) {
+ Log.w(TAG,
+ "Unable to process since images does not contain all stages.");
+ return;
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Image image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // Sample here just simply copy/paste the capture image result
+ yByteBuffer.put(result.first.getPlanes()[0].getBuffer());
+ uByteBuffer.put(result.first.getPlanes()[2].getBuffer());
+ vByteBuffer.put(result.first.getPlanes()[1].getBuffer());
+
+ mImageWriter.queueInputImage(image);
+ }
+ }
+
+ // Close all input images
+ for (Pair<Image, TotalCaptureResult> imageDataPair : results.values()) {
+ imageDataPair.first.close();
+ }
+
+ Log.d(TAG, "Completed night CaptureProcessor");
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+ return captureProcessor;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getMaxCaptureStage() {
+ return 3;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
new file mode 100755
index 0000000..e29abec
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -0,0 +1,165 @@
+/*
+ * 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.util.Pair;
+import android.util.Size;
+
+import java.util.List;
+
+/**
+ * Implementation for night preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public final class NightPreviewExtenderImpl implements PreviewExtenderImpl {
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_INCANDESCENT;
+
+ /**
+ * @hide
+ */
+ public NightPreviewExtenderImpl() {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ public boolean isExtensionAvailableOriginal(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ // Implement the logic to check whether the extension function is supported or not.
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics, MODE);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorType getProcessorType() {
+ return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public ProcessorImpl getProcessor() {
+ return RequestUpdateProcessorImpls.noUpdateProcessor();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDeInit() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
+ // placeholder set of CaptureRequest.Key values
+ SettableCaptureStage captureStage = new SettableCaptureStage(SESSION_STAGE_ID);
+ captureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_AWB_MODE, MODE);
+
+ return captureStage;
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
new file mode 100644
index 0000000..6b7be85
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions in the preview.
+ *
+ * @since 1.0
+ * @hide
+ */
+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(String cameraId, 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(String cameraId, 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 android.hardware.camera2.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.
+ */
+ CaptureStageImpl getCaptureStage();
+
+ /** The type of preview processing to use. */
+ 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>
+ */
+ 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
+ */
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
new file mode 100644
index 0000000..3c750db
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
@@ -0,0 +1,43 @@
+/*
+ * 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 android.media.Image;
+
+/**
+ * Processing a single {@link Image} and {@link TotalCaptureResult} to produce an output to a
+ * stream.
+ *
+ * @since 1.0
+ * @hide
+ */
+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 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.
+ * @hide
+ */
+ void process(Image image, TotalCaptureResult result);
+}
+
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
new file mode 100644
index 0000000..c97e6ed
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+/**
+ * Processes an input image stream and produces an output image stream.
+ *
+ * @since 1.0
+ * @hide
+ */
+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(Surface surface, int imageFormat);
+
+ /**
+ * Invoked when CameraX changes the configured output resolution.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to be at the specified resolution.
+ *
+ * @param size for the surface.
+ */
+ void onResolutionUpdate(Size size);
+
+ /**
+ * Invoked when CameraX changes the configured input image format.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
new file mode 100644
index 0000000..4edf05f
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * Processes a {@link TotalCaptureResult} to update a CaptureStage.
+ *
+ * @since 1.0
+ * @hide
+ */
+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.
+ */
+ CaptureStageImpl process(TotalCaptureResult result);
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java
new file mode 100644
index 0000000..afbad00
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.util.Size;
+import android.view.Surface;
+
+class RequestUpdateProcessorImpls {
+ private static final RequestUpdateProcessorImpl sNoUpdateProcessor =
+ new RequestUpdateProcessorImpl() {
+ @Override
+ public CaptureStageImpl process(TotalCaptureResult result) {
+ return null;
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {}
+
+ @Override
+ public void onResolutionUpdate(Size size) {}
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {}
+ };
+
+ static RequestUpdateProcessorImpl noUpdateProcessor() {
+ return sNoUpdateProcessor;
+ }
+
+ private RequestUpdateProcessorImpls() {
+ }
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/SettableCaptureStage.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/SettableCaptureStage.java
new file mode 100644
index 0000000..7d5dcb1
--- /dev/null
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/SettableCaptureStage.java
@@ -0,0 +1,74 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+final class SettableCaptureStage implements CaptureStageImpl {
+ private final int mId;
+
+ private Map<CaptureRequest.Key, Object> mCaptureRequestKeyValueMap = new HashMap<>();
+
+ /**
+ * Constructor for a {@link CaptureStageImpl} with specific identifier.
+ *
+ * <p>After this {@link CaptureStageImpl} is applied to a single capture operation,
+ * developers can
+ * retrieve the {@link android.media.Image} object with the identifier.
+ *
+ * @param id The identifier for the {@link CaptureStageImpl}.
+ */
+ SettableCaptureStage(int id) {
+ mId = id;
+ }
+
+ /**
+ * @hide
+ */
+ /** Returns the identifier for the {@link CaptureStageImpl}. */
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<Pair<CaptureRequest.Key, Object>> getParameters() {
+ List<Pair<CaptureRequest.Key, Object>> parameters = new ArrayList<>();
+
+ for (Map.Entry<CaptureRequest.Key, Object> entry : mCaptureRequestKeyValueMap.entrySet()) {
+ parameters.add(Pair.create(entry.getKey(), entry.getValue()));
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Adds necessary {@link CaptureRequest.Key} settings into the {@link CaptureStageImpl} object.
+ */
+ <T> void addCaptureRequestParameters(CaptureRequest.Key<T> key, T value) {
+ mCaptureRequestKeyValueMap.put(key, value);
+ }
+}
diff --git a/camera2/extensions/stub/Android.bp b/camera2/extensions/stub/Android.bp
new file mode 100644
index 0000000..7ebfdea
--- /dev/null
+++ b/camera2/extensions/stub/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 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: "androidx.camera.extensions.stub",
+ installable: true,
+
+ static_libs: ["androidx.annotation_annotation"],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "current",
+}
diff --git a/camera2/extensions/stub/src/main/AndroidManifest.xml b/camera2/extensions/stub/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..24ec9a7
--- /dev/null
+++ b/camera2/extensions/stub/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+<manifest package="androidx.camera.extensions.impl"/>
\ No newline at end of file
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..a364d4b
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @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(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
new file mode 100755
index 0000000..100f665
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..d68d8eb
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @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(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
new file mode 100755
index 0000000..bc3e48d
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..b943e0a
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @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(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
new file mode 100644
index 0000000..ff58862
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -0,0 +1,94 @@
+/*
+ * 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) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
new file mode 100644
index 0000000..90de15a
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.TotalCaptureResult;
+import android.media.Image;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.util.Map;
+
+/**
+ * The interface for processing a set of {@link Image}s that have captured.
+ *
+ * @since 1.0
+ */
+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);
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
new file mode 100644
index 0000000..c4796c2
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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 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}.
+ */
+ List<Pair<CaptureRequest.Key, Object>> getParameters();
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
new file mode 100644
index 0000000..2879568
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -0,0 +1,83 @@
+/*
+ * 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.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
+
+/**
+ * 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(String cameraId, CameraCharacteristics cameraCharacteristics, 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 android.hardware.camera2.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.
+ */
+ CaptureStageImpl onPresetSession();
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.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.
+ */
+ CaptureStageImpl onEnableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.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.
+ */
+ CaptureStageImpl onDisableSession();
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
new file mode 100644
index 0000000..7769551
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+/**
+ * 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.
+ */
+ public String checkApiVersion(String version) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ /**
+ * 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 false;
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..66f4a50
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @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(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
new file mode 100644
index 0000000..0eb4a61
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
new file mode 100644
index 0000000..571c2e3
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+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(String cameraId, 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(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The processing that will be done on a set of captures to create and image with the effect.
+ */
+ CaptureProcessorImpl getCaptureProcessor();
+
+ /** The set of captures that are needed to create an image with the effect. */
+ 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 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();
+
+ /**
+ * 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.
+ *
+ * @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);
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/InitializerImpl.java
new file mode 100644
index 0000000..779a2ee
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/InitializerImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+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) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ /**
+ * 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) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ /**
+ * 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/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
new file mode 100755
index 0000000..3b39cf1
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @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(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
new file mode 100755
index 0000000..a5809f6
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
new file mode 100644
index 0000000..4324987
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -0,0 +1,111 @@
+/*
+ * 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.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+
+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(String cameraId, 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(String cameraId, 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 android.hardware.camera2.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.
+ */
+ CaptureStageImpl getCaptureStage();
+
+ /** The type of preview processing to use. */
+ 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>
+ */
+ 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/stub/src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
new file mode 100644
index 0000000..e7ecaa1
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.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.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+
+/**
+ * Processes a single {@link Image} and {@link TotalCaptureResult} to produce an output to a
+ * stream.
+ *
+ * @since 1.0
+ */
+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);
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
new file mode 100644
index 0000000..6be328b
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * 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(Surface surface, int imageFormat);
+
+ /**
+ * Invoked when CameraX changes the configured output resolution.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to be at the specified resolution.
+ *
+ * @param size for the surface.
+ */
+ void onResolutionUpdate(Size size);
+
+ /**
+ * Invoked when CameraX changes the configured input image format.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
new file mode 100644
index 0000000..14637d7
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * 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.
+ */
+ CaptureStageImpl process(TotalCaptureResult result);
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
new file mode 100644
index 0000000..86424c4
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.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 will 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();
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
new file mode 100644
index 0000000..7753258
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 implements AdvancedExtenderImpl {
+ public AutoAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
new file mode 100644
index 0000000..91d8171
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 implements AdvancedExtenderImpl {
+ public BeautyAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
new file mode 100644
index 0000000..b05740d
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 implements AdvancedExtenderImpl {
+ public BokehAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
new file mode 100644
index 0000000..68de01b
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
new file mode 100644
index 0000000..1298d80
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -0,0 +1,227 @@
+/*
+ * 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;
+
+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.
+ * Implementation will be provided in the stub.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2OutputConfigImplBuilder {
+ static AtomicInteger sLastId = new AtomicInteger(0);
+ private OutputConfigImplImpl mOutputConfig;
+ private int mSurfaceGroupId;
+ 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;
+ }
+
+ /**
+ * Build a {@link Camera2OutputConfigImpl} instance.
+ */
+ public Camera2OutputConfigImpl build() {
+ mOutputConfig.setId(getNextId());
+ 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/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
new file mode 100644
index 0000000..d121717
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
new file mode 100644
index 0000000..6c052d1
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ * Implementation will be provided in the stub.
+ */
+@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/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
new file mode 100644
index 0000000..bfd8e9a
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 implements AdvancedExtenderImpl {
+ public HdrAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
new file mode 100644
index 0000000..ce17c4f
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
new file mode 100644
index 0000000..ca4dcaf
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
new file mode 100644
index 0000000..95f2c3b
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
new file mode 100644
index 0000000..c3ad61b
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
new file mode 100644
index 0000000..fc05224
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 implements AdvancedExtenderImpl {
+ public NightAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
new file mode 100644
index 0000000..f692029
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
new file mode 100644
index 0000000..e70ce37
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+/**
+ * A Interface to execute 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 and 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 and 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 and 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/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
new file mode 100644
index 0000000..9ac3eeb
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -0,0 +1,249 @@
+/*
+ * 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.view.Surface;
+
+import java.util.Map;
+
+/**
+ * Interface for activating extension sessions.
+ *
+ * <p><pre>
+ * The flow of a extension session.
+ * (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 at other
+ * time other than in this method.
+ *
+ * (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 statue 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 destroyed
+ * </pre>
+ */
+@SuppressLint("UnknownNullness")
+public interface SessionProcessorImpl {
+ /**
+ * Notify to start the session for the extension. 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 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
+ * may be 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>To ensure the preview, image capture and image analysis are working properly, OEM is
+ * responsible for setting corresponding {@link Camera2OutputConfigImpl.UsageType} in the
+ * {@link Camera2OutputConfigImpl}. CameraX will examine if all usage types
+ * (USAGE_PREVIEW/USAGE_CAPTURE/USAGE_ANALYSIS) can be found in the returned
+ * {@link Camera2SessionConfigImpl} and throws an {@link IllegalArgumentException} if some
+ * usage type is not found.
+ *
+ * <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 unbind. 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);
+
+ /**
+ * 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 at time other than in this method.
+ *
+ * @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 repeating of current CameraCaptureSession and call this API to signal OEM that
+ * all repeating request should stopped and calling
+ * {@link RequestProcessorImpl#setRepeating(RequestProcessorImpl.Request)} 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 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);
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
new file mode 100644
index 0000000..7b8d83c
--- /dev/null
+++ b/camera2/extensions/stub/src/main/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/public/src/com/android/ex/camera2/blocking/BlockingExtensionSessionCallback.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingExtensionSessionCallback.java
new file mode 100644
index 0000000..d191ef7
--- /dev/null
+++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingExtensionSessionCallback.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2020 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.ex.camera2.blocking;
+
+import android.hardware.camera2.CameraExtensionSession;
+import android.os.ConditionVariable;
+import android.util.Log;
+
+import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
+import com.android.ex.camera2.utils.StateChangeListener;
+import com.android.ex.camera2.utils.StateWaiter;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+/**
+ * A camera extension session listener that implements blocking operations on session state changes.
+ *
+ * <p>Provides a waiter that can be used to block until the next unobserved state of the
+ * requested type arrives.</p>
+ *
+ * <p>Pass-through all StateCallback changes to the proxy.</p>
+ *
+ * @see #getStateWaiter
+ */
+public class BlockingExtensionSessionCallback extends CameraExtensionSession.StateCallback {
+ /**
+ * Session is configured, ready for captures
+ */
+ public static final int SESSION_CONFIGURED = 0;
+
+ /**
+ * Session has failed to configure, can't do any captures
+ */
+ public static final int SESSION_CONFIGURE_FAILED = 1;
+
+ /**
+ * Session is closed
+ */
+ public static final int SESSION_CLOSED = 2;
+
+ private static final int NUM_STATES = 3;
+
+ /*
+ * Private fields
+ */
+ private static final String TAG = "BlockingExtensionSessionCallback";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private final CameraExtensionSession.StateCallback mProxy;
+ private final SessionFuture mSessionFuture = new SessionFuture();
+
+ private final StateWaiter mStateWaiter = new StateWaiter(sStateNames);
+ private final StateChangeListener mStateChangeListener = mStateWaiter.getListener();
+
+ private static final String[] sStateNames = {
+ "SESSION_CONFIGURED",
+ "SESSION_CONFIGURE_FAILED",
+ "SESSION_CLOSED"
+ };
+
+ /**
+ * Create a blocking session listener without forwarding the session listener invocations
+ * to another session listener.
+ */
+ public BlockingExtensionSessionCallback() {
+ mProxy = null;
+ }
+
+ /**
+ * Create a blocking session listener; forward original listener invocations
+ * into {@code listener}.
+ *
+ * @param listener a non-{@code null} listener to forward invocations into
+ *
+ * @throws NullPointerException if {@code listener} was {@code null}
+ */
+ public BlockingExtensionSessionCallback(CameraExtensionSession.StateCallback listener) {
+ if (listener == null) {
+ throw new NullPointerException("listener must not be null");
+ }
+ mProxy = listener;
+ }
+
+ /**
+ * Acquire the state waiter; can be used to block until a set of state transitions have
+ * been reached.
+ *
+ * <p>Only one thread should wait at a time.</p>
+ */
+ public StateWaiter getStateWaiter() {
+ return mStateWaiter;
+ }
+
+ /**
+ * Return session if already have it; otherwise wait until any of the session listener
+ * invocations fire and the session is available.
+ *
+ * <p>Does not consume any of the states from the state waiter.</p>
+ *
+ * @param timeoutMs how many milliseconds to wait for
+ * @return a non-{@code null}
+ * {@link android.example.com.cameraextensionbasic.CameraExtensionSession} instance
+ *
+ * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs}
+ */
+ public CameraExtensionSession waitAndGetSession(long timeoutMs) {
+ try {
+ return mSessionFuture.get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ throw new TimeoutRuntimeException(
+ String.format("Failed to get session after %s milliseconds", timeoutMs), e);
+ }
+ }
+
+ /*
+ * CameraExtensionSession.StateCallback implementation
+ */
+
+ @Override
+ public void onClosed(CameraExtensionSession session) {
+ mSessionFuture.setSession(session);
+ if (mProxy != null) mProxy.onClosed(session);
+ mStateChangeListener.onStateChanged(SESSION_CLOSED);
+ }
+
+ @Override
+ public void onConfigured(CameraExtensionSession session) {
+ mSessionFuture.setSession(session);
+ if (mProxy != null) {
+ mProxy.onConfigured(session);
+ }
+ mStateChangeListener.onStateChanged(SESSION_CONFIGURED);
+ }
+
+ @Override
+ public void onConfigureFailed(CameraExtensionSession session) {
+ mSessionFuture.setSession(session);
+ if (mProxy != null) {
+ mProxy.onConfigureFailed(session);
+ }
+ mStateChangeListener.onStateChanged(SESSION_CONFIGURE_FAILED);
+ }
+
+ private static class SessionFuture implements Future<CameraExtensionSession> {
+ private volatile CameraExtensionSession mSession;
+ ConditionVariable mCondVar = new ConditionVariable(/*opened*/false);
+
+ public void setSession(CameraExtensionSession session) {
+ mSession = session;
+ mCondVar.open();
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false; // don't allow canceling this task
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false; // can never cancel this task
+ }
+
+ @Override
+ public boolean isDone() {
+ return mSession != null;
+ }
+
+ @Override
+ public CameraExtensionSession get() {
+ mCondVar.block();
+ return mSession;
+ }
+
+ @Override
+ public CameraExtensionSession get(long timeout, TimeUnit unit) throws TimeoutException {
+ long timeoutMs = unit.convert(timeout, TimeUnit.MILLISECONDS);
+ if (!mCondVar.block(timeoutMs)) {
+ throw new TimeoutException(
+ "Failed to receive session after " + timeout + " " + unit);
+ }
+
+ if (mSession == null) {
+ throw new AssertionError();
+ }
+ return mSession;
+ }
+
+ }
+}