Make vendor keys visible in Camera2 java APIs.
- Add vendor keys to getKeys() calls for CameraCharacteristics,
CaptureRequest, and CaptureResult.
- Vendors can specify whether custom keys show up by listing
visible keys in the REQUEST_AVAILABLE_RESULT_KEYS field.
- Vendor key types are always treated as a primitive (or Rational)
array type corresponding to one of the valid types for
a camera metadata entry.
Bug: 22067625
Change-Id: I6e7dd3db7a8bf533c2ec15ff69ca38824134e971
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index af1367c..c580083 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -173,6 +173,28 @@
}
}
+ ArrayList<TKey> vendorKeys = CameraMetadataNative.getAllVendorKeys(keyClass);
+
+ if (vendorKeys != null) {
+ for (TKey k : vendorKeys) {
+ String keyName;
+ if (k instanceof CaptureRequest.Key<?>) {
+ keyName = ((CaptureRequest.Key<?>) k).getName();
+ } else if (k instanceof CaptureResult.Key<?>) {
+ keyName = ((CaptureResult.Key<?>) k).getName();
+ } else if (k instanceof CameraCharacteristics.Key<?>) {
+ keyName = ((CameraCharacteristics.Key<?>) k).getName();
+ } else {
+ continue;
+ }
+
+ if (filterTags == null || Arrays.binarySearch(filterTags,
+ CameraMetadataNative.getTag(keyName)) >= 0) {
+ keyList.add(k);
+ }
+ }
+ }
+
return keyList;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 7e50fd9..12a2910 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1078,6 +1078,7 @@
private native synchronized void nativeWriteValues(int tag, byte[] src);
private native synchronized void nativeDump() throws IOException; // dump to ALOGD
+ private static native ArrayList nativeGetAllVendorKeys(Class keyClass);
private static native int nativeGetTagFromKey(String keyName)
throws IllegalArgumentException;
private static native int nativeGetTypeFromTag(int tag)
@@ -1113,6 +1114,19 @@
return nativeIsEmpty();
}
+
+ /**
+ * Return a list containing keys of the given key class for all defined vendor tags.
+ *
+ * @hide
+ */
+ public static <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) {
+ if (keyClass == null) {
+ throw new NullPointerException();
+ }
+ return (ArrayList<K>) nativeGetAllVendorKeys(keyClass);
+ }
+
/**
* Convert a key string into the equivalent native tag.
*
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 7c8769d..fb22689 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -23,7 +23,9 @@
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
+#include <stdio.h>
#include <string.h>
+#include <vector>
#include "jni.h"
#include "JNIHelp.h"
@@ -45,9 +47,30 @@
// fully-qualified class name
#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
+#define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
+#define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
+#define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
using namespace android;
+static struct metadata_java_key_offsets_t {
+ jclass mCharacteristicsKey;
+ jclass mResultKey;
+ jclass mRequestKey;
+ jmethodID mCharacteristicsConstr;
+ jmethodID mResultConstr;
+ jmethodID mRequestConstr;
+ jclass mByteArray;
+ jclass mInt32Array;
+ jclass mFloatArray;
+ jclass mInt64Array;
+ jclass mDoubleArray;
+ jclass mRationalArray;
+ jclass mArrayList;
+ jmethodID mArrayListConstr;
+ jmethodID mArrayListAdd;
+} gMetadataOffsets;
+
struct fields_t {
jfieldID metadata_ptr;
};
@@ -141,6 +164,7 @@
extern "C" {
static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
@@ -510,6 +534,9 @@
{ "nativeClassInit",
"()V",
(void *)CameraMetadata_classInit },
+ { "nativeGetAllVendorKeys",
+ "(Ljava/lang/Class;)Ljava/util/ArrayList;",
+ (void *)CameraMetadata_getAllVendorKeys},
{ "nativeGetTagFromKey",
"(Ljava/lang/String;)I",
(void *)CameraMetadata_getTagFromKey },
@@ -588,6 +615,44 @@
// Get all the required offsets in java class and register native functions
int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
{
+
+ // Store global references to Key-related classes and methods used natively
+ jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
+ jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
+ jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
+ gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
+ gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
+ gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
+ gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mCharacteristicsKey, "<init>",
+ "(Ljava/lang/String;Ljava/lang/Class;)V");
+ gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+ gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+
+ // Store global references for primitive array types used by Keys
+ jclass byteClazz = FindClassOrDie(env, "[B");
+ jclass int32Clazz = FindClassOrDie(env, "[I");
+ jclass floatClazz = FindClassOrDie(env, "[F");
+ jclass int64Clazz = FindClassOrDie(env, "[J");
+ jclass doubleClazz = FindClassOrDie(env, "[D");
+ jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
+ gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
+ gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
+ gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
+ gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
+ gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
+ gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
+
+ // Store global references for ArrayList methods used
+ jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
+ gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
+ gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
+ "<init>", "(I)V");
+ gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
+ "add", "(Ljava/lang/Object;)Z");
+
// Register native functions
return RegisterMethodsOrDie(env,
CAMERA_METADATA_CLASS_NAME,
@@ -596,6 +661,7 @@
}
extern "C" {
+
static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
// XX: Why do this separately instead of doing it in the register function?
ALOGV("%s", __FUNCTION__);
@@ -612,6 +678,107 @@
env->FindClass(CAMERA_METADATA_CLASS_NAME);
}
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
+
+ // Get all vendor tags
+ sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ if (vTags.get() == nullptr) {
+ // No vendor tags.
+ return NULL;
+ }
+
+ int count = vTags->getTagCount();
+ if (count <= 0) {
+ // No vendor tags.
+ return NULL;
+ }
+
+ std::vector<uint32_t> tagIds(count, /*initializer value*/0);
+ vTags->getTagArray(&tagIds[0]);
+
+ // Which key class/constructor should we use?
+ jclass keyClazz;
+ jmethodID keyConstr;
+ if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
+ keyClazz = gMetadataOffsets.mCharacteristicsKey;
+ keyConstr = gMetadataOffsets.mCharacteristicsConstr;
+ } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
+ keyClazz = gMetadataOffsets.mResultKey;
+ keyConstr = gMetadataOffsets.mResultConstr;
+ } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
+ keyClazz = gMetadataOffsets.mRequestKey;
+ keyConstr = gMetadataOffsets.mRequestConstr;
+ } else {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid key class given as argument.");
+ return NULL;
+ }
+
+ // Allocate arrayList to return
+ jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
+ gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ for (uint32_t id : tagIds) {
+ const char* section = vTags->getSectionName(id);
+ const char* tag = vTags->getTagName(id);
+ int type = vTags->getTagType(id);
+
+ size_t totalLen = strlen(section) + strlen(tag) + 2;
+ std::vector<char> fullName(totalLen, 0);
+ snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
+
+ jstring name = env->NewStringUTF(&fullName[0]);
+
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ jclass valueClazz;
+ switch (type) {
+ case TYPE_BYTE:
+ valueClazz = gMetadataOffsets.mByteArray;
+ break;
+ case TYPE_INT32:
+ valueClazz = gMetadataOffsets.mInt32Array;
+ break;
+ case TYPE_FLOAT:
+ valueClazz = gMetadataOffsets.mFloatArray;
+ break;
+ case TYPE_INT64:
+ valueClazz = gMetadataOffsets.mInt64Array;
+ break;
+ case TYPE_DOUBLE:
+ valueClazz = gMetadataOffsets.mDoubleArray;
+ break;
+ case TYPE_RATIONAL:
+ valueClazz = gMetadataOffsets.mRationalArray;
+ break;
+ default:
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Invalid type %d given for key %s", type, &fullName[0]);
+ return NULL;
+ }
+
+ jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ env->DeleteLocalRef(name);
+ env->DeleteLocalRef(key);
+ }
+
+ return arrayList;
+}
+
static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
ScopedUtfChars keyScoped(env, keyName);