Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c620eb7e authored by Ruben Brunk's avatar Ruben Brunk
Browse files

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
parent eec3d9e3
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -173,6 +173,28 @@ public abstract class CameraMetadata<TKey> {
            }
        }

        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;
    }

+14 −0
Original line number Diff line number Diff line
@@ -1078,6 +1078,7 @@ public class CameraMetadataNative implements Parcelable {
    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 @@ public class CameraMetadataNative implements Parcelable {
        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.
     *
+167 −0
Original line number Diff line number Diff line
@@ -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 @@ static const bool kIsDebug = false;

// 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 @@ struct Helpers {
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 @@ static JNINativeMethod gCameraMetadataMethods[] = {
  { "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 @@ static int find_fields(JNIEnv *env, field *fields, int count)
// 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 @@ int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
}

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 @@ static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
    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);