summaryrefslogtreecommitdiffstats
path: root/camera2/utils/src/com/android
diff options
context:
space:
mode:
authorSol Boucher <solb@google.com>2014-07-24 10:28:14 -0700
committerSol Boucher <solb@google.com>2014-07-30 14:13:52 -0700
commit8ba391e3f88936557ad6d44bbef32cb08f4ca310 (patch)
tree2e2af725f365bef500146fbd1af93f814a1802cc /camera2/utils/src/com/android
parent90aa7e817d1969b4fbbfc36dbeca6c500b6aaa0b (diff)
downloadandroid_frameworks_ex-8ba391e3f88936557ad6d44bbef32cb08f4ca310.tar.gz
android_frameworks_ex-8ba391e3f88936557ad6d44bbef32cb08f4ca310.tar.bz2
android_frameworks_ex-8ba391e3f88936557ad6d44bbef32cb08f4ca310.zip
Create new com.android.ex.camera2.utils package
It contains: - Camera2RequestSettingsSet class for storing/unioning CaptureRequest.Builders - A Camera2CaptureListenerSplitter class for connecting multiple such listeners - A Camera2CpatureListenerForwarder for relaying callbacks to another Handler Change-Id: I47381e4a45b4232b86e5498a1cc39cc600b5c5c5
Diffstat (limited to 'camera2/utils/src/com/android')
-rw-r--r--camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java99
-rw-r--r--camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java95
-rw-r--r--camera2/utils/src/com/android/ex/camera2/utils/Camera2RequestSettingsSet.java238
3 files changed, 432 insertions, 0 deletions
diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java
new file mode 100644
index 0000000..35b1c6d
--- /dev/null
+++ b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 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.utils;
+
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCaptureSession.CaptureListener;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.Handler;
+
+/**
+ * Proxy that forwards all updates to another {@link CaptureListener}, invoking
+ * its callbacks on a separate {@link Handler}.
+ */
+public class Camera2CaptureListenerForwarder extends CaptureListener {
+ private CaptureListener mListener;
+ private Handler mHandler;
+
+ public Camera2CaptureListenerForwarder(CaptureListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
+
+ @Override
+ public void onCaptureCompleted(final CameraCaptureSession session, final CaptureRequest request,
+ final TotalCaptureResult result) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureCompleted(session, request, result);
+ }});
+ }
+
+ @Override
+ public void onCaptureFailed(final CameraCaptureSession session, final CaptureRequest request,
+ final CaptureFailure failure) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureFailed(session, request, failure);
+ }});
+ }
+
+ @Override
+ public void onCaptureProgressed(final CameraCaptureSession session,
+ final CaptureRequest request,
+ final CaptureResult partialResult) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureProgressed(session, request, partialResult);
+ }});
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(final CameraCaptureSession session, final int sequenceId) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureSequenceAborted(session, sequenceId);
+ }});
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(final CameraCaptureSession session, final int sequenceId,
+ final long frameNumber) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureSequenceCompleted(session, sequenceId, frameNumber);
+ }});
+ }
+
+ @Override
+ public void onCaptureStarted(final CameraCaptureSession session, final CaptureRequest request,
+ final long timestamp) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onCaptureStarted(session, request, timestamp);
+ }});
+ }
+}
diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java
new file mode 100644
index 0000000..a13dc04
--- /dev/null
+++ b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 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.utils;
+
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCaptureSession.CaptureListener;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Junction that allows notifying multiple {@link CaptureListener}s whenever
+ * the {@link CameraCaptureSession} posts a capture-related update.
+ */
+public class Camera2CaptureListenerSplitter extends CaptureListener {
+ private final List<CaptureListener> mRecipients = new LinkedList<>();
+
+ /**
+ * @param recipients The listeners to notify. Any {@code null} passed here
+ * will be completely ignored.
+ */
+ public Camera2CaptureListenerSplitter(CaptureListener... recipients) {
+ for (CaptureListener listener : recipients) {
+ if (listener != null) {
+ mRecipients.add(listener);
+ }
+ }
+ }
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureCompleted(session, request, result);
+ }
+ }
+
+ @Override
+ public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
+ CaptureFailure failure) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureFailed(session, request, failure);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
+ CaptureResult partialResult) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureProgressed(session, request, partialResult);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureSequenceAborted(session, sequenceId);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId,
+ long frameNumber) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureSequenceCompleted(session, sequenceId, frameNumber);
+ }
+ }
+
+ @Override
+ public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
+ long timestamp) {
+ for (CaptureListener target : mRecipients) {
+ target.onCaptureStarted(session, request, timestamp);
+ }
+ }
+}
diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2RequestSettingsSet.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2RequestSettingsSet.java
new file mode 100644
index 0000000..fac8f1a
--- /dev/null
+++ b/camera2/utils/src/com/android/ex/camera2/utils/Camera2RequestSettingsSet.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2014 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.utils;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureRequest.Builder;
+import android.hardware.camera2.CaptureRequest.Key;
+import android.view.Surface;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A set of settings to be used when filing a {@link CaptureRequest}.
+ */
+public class Camera2RequestSettingsSet {
+ private final Map<Key<?>, Object> mDictionary;
+ private long mRevision;
+
+ /**
+ * Create a new instance with no settings defined.
+ *
+ * <p>Creating a request from this object without first specifying any
+ * properties on it is equivalent to just creating a request directly
+ * from the template of choice. Its revision identifier is initially
+ * {@code 0}, and will remain thus until its first modification.</p>
+ */
+ public Camera2RequestSettingsSet() {
+ mDictionary = new HashMap<>();
+ mRevision = 0;
+ }
+
+ /**
+ * Perform a deep copy of the defined settings and revision number.
+ *
+ * @param other The reference instance.
+ *
+ * @throws NullPointerException If {@code other} is {@code null}.
+ */
+ public Camera2RequestSettingsSet(Camera2RequestSettingsSet other) {
+ if (other == null) {
+ throw new NullPointerException("Tried to copy null Camera2RequestSettingsSet");
+ }
+
+ mDictionary = new HashMap<>(other.mDictionary);
+ mRevision = other.mRevision;
+ }
+
+ /**
+ * Specify a setting, potentially overriding the template's default choice.
+ *
+ * <p>Providing a {@code null} {@code value} will indicate a forced use of
+ * the template's selection for that {@code key}; the difference here is
+ * that this information will be propagated with unions as documented in
+ * {@link #union}. This method increments the revision identifier if the new
+ * choice is different than the existing selection.</p>
+ *
+ * @param key Which setting to alter.
+ * @param value The new selection for that setting, or {@code null} to force
+ * the use of the template's default selection for this field.
+ * @return Whether the settings were updated, which only occurs if the
+ * {@code value} is different from any already stored.
+ *
+ * @throws NullPointerException If {@code key} is {@code null}.
+ */
+ public <T> boolean set(Key<T> key, T value) {
+ if (key == null) {
+ throw new NullPointerException("Received a null key");
+ }
+
+ Object currentValue = get(key);
+ // Only save the value if it's different from the one we already have
+ if (!mDictionary.containsKey(key) || !Objects.equals(value, currentValue)) {
+ mDictionary.put(key, value);
+ ++mRevision;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Unsets a setting, preventing it from being propagated with unions or from
+ * overriding the default when creating a capture request.
+ *
+ * <p>This method increments the revision identifier if a selection had
+ * previously been made for that parameter.</p>
+ *
+ * @param key Which setting to reset.
+ * @return Whether the settings were updated, which only occurs if the
+ * specified setting already had a value or was forced to default.
+ *
+ * @throws NullPointerException If {@code key} is {@code null}.
+ */
+ public boolean unset(Key<?> key) {
+ if (key == null) {
+ throw new NullPointerException("Received a null key");
+ }
+
+ if (mDictionary.containsKey(key)) {
+ mDictionary.remove(key);
+ ++mRevision;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Interrogate the current specialization of a setting.
+ *
+ * @param key Which setting to check.
+ * @return The current selection for that setting, or {@code null} if the
+ * setting is unset or forced to the template-defined default.
+ *
+ * @throws NullPointerException If {@code key} is {@code null}.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T get(Key<T> key) {
+ if (key == null) {
+ throw new NullPointerException("Received a null key");
+ }
+ return (T) mDictionary.get(key);
+ }
+
+ /**
+ * Query this instance for whether it prefers a particular choice for the
+ * given request parameter.
+ *
+ * <p>This method can be used to detect whether a particular field is forced
+ * to its default value or simply unset. While {@link #get} will return
+ * {@code null} in both these cases, this method will return {@code true}
+ * and {@code false}, respectively.</p>
+
+ * @param key Which setting to look for.
+ * @return Whether that setting has a value that will propagate with unions.
+ *
+ * @throws NullPointerException If {@code key} is {@code null}.
+ */
+ public boolean contains(Key<?> key) {
+ if (key == null) {
+ throw new NullPointerException("Received a null key");
+ }
+ return mDictionary.containsKey(key);
+ }
+
+ /**
+ * Get this set of settings's revision identifier, which can be compared
+ * against cached past values to determine whether it has been modified.
+ * <p>Distinct revisions across the same object do not necessarily indicate
+ * that the object's key/value pairs have changed at all, but the same
+ * revision on the same object does imply that they've stayed the same.</p>
+ *
+ * @return The number of modifications made since the beginning of this
+ * object's heritage.
+ */
+ public long getRevision() {
+ return mRevision;
+ }
+
+ /**
+ * Add all settings choices defined by {@code moreSettings} to this object.
+ *
+ * <p>For any settings defined in both, the choice stored in the argument
+ * to this method take precedence. Unset settings are not propagated, but
+ * those forced to default as described in {@link set} are also forced to
+ * default in {@code this} set. Invoking this method increments {@code this}
+ * object's revision counter, but leaves the argument's unchanged.</p>
+ *
+ * @param moreSettings The source of the additional settings ({@code null}
+ * is allowed here).
+ * @return Whether these settings were updated, which can only fail if the
+ * target itself is also given as the argument.
+ */
+ public boolean union(Camera2RequestSettingsSet moreSettings) {
+ if (moreSettings == null || moreSettings == this) {
+ return false;
+ }
+
+ mDictionary.putAll(moreSettings.mDictionary);
+ ++mRevision;
+ return true;
+ }
+
+ /**
+ * Create a {@link CaptureRequest} specialized for the specified
+ * {@link CameraDevice} and targeting the given {@link Surface}s.
+ *
+ * @param camera The camera from which to capture.
+ * @param template A {@link CaptureRequest} template defined in
+ * {@link CameraDevice}.
+ * @param targets The location(s) to draw the resulting image onto.
+ * @return The request, ready to be passed to the camera framework.
+ *
+ * @throws CameraAccessException Upon an underlying framework API failure.
+ * @throws NullPointerException If any argument is {@code null}.
+ */
+ public CaptureRequest createRequest(CameraDevice camera, int template, Surface... targets)
+ throws CameraAccessException {
+ if (camera == null) {
+ throw new NullPointerException("Tried to create request using null CameraDevice");
+ }
+
+ Builder reqBuilder = camera.createCaptureRequest(template);
+ for (Key<?> key : mDictionary.keySet()) {
+ setRequestFieldIfNonNull(reqBuilder, key);
+ }
+ for (Surface target : targets) {
+ if (target == null) {
+ throw new NullPointerException("Tried to add null Surface as request target");
+ }
+ reqBuilder.addTarget(target);
+ }
+ return reqBuilder.build();
+ }
+
+ private <T> void setRequestFieldIfNonNull(Builder requestBuilder, Key<T> key) {
+ T value = get(key);
+ if (value != null) {
+ requestBuilder.set(key, value);
+ }
+ }
+}