blob: fa2cfe3d350d691780cc661a42d88bce6f4c64c7 [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
2**
3** Copyright 2013, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18// #define LOG_NDEBUG 0
Igor Murashkinb519cc52013-07-02 11:23:44 -070019// #define LOG_NNDEBUG 0
Igor Murashkin70725502013-06-25 20:27:06 +000020#define LOG_TAG "CameraMetadata-JNI"
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080021#include <utils/Errors.h>
Igor Murashkin70725502013-06-25 20:27:06 +000022#include <utils/Log.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080023#include <utils/RefBase.h>
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080024#include <utils/Vector.h>
25#include <utils/SortedVector.h>
26#include <utils/KeyedVector.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080027#include <string.h>
Igor Murashkin70725502013-06-25 20:27:06 +000028
29#include "jni.h"
30#include "JNIHelp.h"
31#include "android_os_Parcel.h"
32#include "android_runtime/AndroidRuntime.h"
33
Ruben Brunk85c43882014-02-21 17:40:51 -080034#include <binder/IServiceManager.h>
Igor Murashkin70725502013-06-25 20:27:06 +000035#include <camera/CameraMetadata.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080036#include <camera/ICameraService.h>
37#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070038#include <nativehelper/ScopedUtfChars.h>
39#include <nativehelper/ScopedPrimitiveArray.h>
40
41#if defined(LOG_NNDEBUG)
42#if !LOG_NNDEBUG
43#define ALOGVV ALOGV
44#endif
45#else
46#define ALOGVV(...)
47#endif
Igor Murashkin70725502013-06-25 20:27:06 +000048
49// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070050#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Igor Murashkin70725502013-06-25 20:27:06 +000051
52using namespace android;
53
54struct fields_t {
55 jfieldID metadata_ptr;
56};
57
58static fields_t fields;
59
Igor Murashkinb519cc52013-07-02 11:23:44 -070060namespace {
61struct Helpers {
62 static size_t getTypeSize(uint8_t type) {
63 if (type >= NUM_TYPES) {
64 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
65 return static_cast<size_t>(-1);
66 }
67
68 return camera_metadata_type_size[type];
69 }
70
71 static status_t updateAny(CameraMetadata *metadata,
72 uint32_t tag,
73 uint32_t type,
74 const void *data,
75 size_t dataBytes) {
76
77 if (type >= NUM_TYPES) {
78 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
79 return INVALID_OPERATION;
80 }
81
82 size_t typeSize = getTypeSize(type);
83
84 if (dataBytes % typeSize != 0) {
85 ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize "
86 "(%ud)", __FUNCTION__, dataBytes, typeSize);
87 return BAD_VALUE;
88 }
89
90 size_t dataCount = dataBytes / typeSize;
91
92 switch(type) {
93#define METADATA_UPDATE(runtime_type, compile_type) \
94 case runtime_type: { \
95 const compile_type *dataPtr = \
96 static_cast<const compile_type*>(data); \
97 return metadata->update(tag, dataPtr, dataCount); \
98 } \
99
100 METADATA_UPDATE(TYPE_BYTE, uint8_t);
101 METADATA_UPDATE(TYPE_INT32, int32_t);
102 METADATA_UPDATE(TYPE_FLOAT, float);
103 METADATA_UPDATE(TYPE_INT64, int64_t);
104 METADATA_UPDATE(TYPE_DOUBLE, double);
105 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
106
107 default: {
108 // unreachable
109 ALOGE("%s: Unreachable", __FUNCTION__);
110 return INVALID_OPERATION;
111 }
112 }
113
114#undef METADATA_UPDATE
115 }
116};
117} // namespace {}
118
Igor Murashkin70725502013-06-25 20:27:06 +0000119extern "C" {
120
121static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700122static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
123static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800124static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000125
126// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
127static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
128
129 if (thiz == NULL) {
130 return NULL;
131 }
132
133 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
134}
135
136// Safe access to native pointer from object. Throws if not possible to access.
137static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
138 const char* argName = "this") {
139
140 if (thiz == NULL) {
141 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
142 __FUNCTION__);
143 jniThrowNullPointerException(env, argName);
144 return NULL;
145 }
146
147 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
148 if (metadata == NULL) {
149 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
150 __FUNCTION__);
151 jniThrowException(env, "java/lang/IllegalStateException",
152 "Metadata object was already closed");
153 return NULL;
154 }
155
156 return metadata;
157}
158
159static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
160 ALOGV("%s", __FUNCTION__);
161
162 return reinterpret_cast<jlong>(new CameraMetadata());
163}
164
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700165static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
166 jobject other) {
167 ALOGV("%s", __FUNCTION__);
168
169 CameraMetadata* otherMetadata =
170 CameraMetadata_getPointerThrow(env, other, "other");
171
172 // In case of exception, return
173 if (otherMetadata == NULL) return NULL;
174
175 // Clone native metadata and return new pointer
176 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
177}
178
179
Igor Murashkin70725502013-06-25 20:27:06 +0000180static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
181 ALOGV("%s", __FUNCTION__);
182
183 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
184
185 if (metadata == NULL) {
186 ALOGW("%s: Returning early due to exception being thrown",
187 __FUNCTION__);
188 return JNI_TRUE; // actually throws java exc.
189 }
190
191 jboolean empty = metadata->isEmpty();
192
193 ALOGV("%s: Empty returned %d, entry count was %d",
194 __FUNCTION__, empty, metadata->entryCount());
195
196 return empty;
197}
198
199static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
200 ALOGV("%s", __FUNCTION__);
201
202 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
203
204 if (metadata == NULL) return 0; // actually throws java exc.
205
206 return metadata->entryCount();
207}
208
209// idempotent. calling more than once has no effect.
210static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
211 ALOGV("%s", __FUNCTION__);
212
213 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
214
215 if (metadata != NULL) {
216 delete metadata;
217 env->SetLongField(thiz, fields.metadata_ptr, 0);
218 }
219
220 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
221 "Expected the native ptr to be 0 after #close");
222}
223
224static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
225 ALOGV("%s", __FUNCTION__);
226
227 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
228
229 // order is important: we can't call another JNI method
230 // if there is an exception pending
231 if (metadata == NULL) return;
232
233 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
234
235 if (otherMetadata == NULL) return;
236
237 metadata->swap(*otherMetadata);
238}
239
Igor Murashkinb519cc52013-07-02 11:23:44 -0700240static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
241 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
242
243 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
244 if (metadata == NULL) return NULL;
245
246 int tagType = get_camera_metadata_tag_type(tag);
247 if (tagType == -1) {
248 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
249 "Tag (%d) did not have a type", tag);
250 return NULL;
251 }
252 size_t tagSize = Helpers::getTypeSize(tagType);
253
254 camera_metadata_entry entry = metadata->find(tag);
255 if (entry.count == 0) {
256 if (!metadata->exists(tag)) {
257 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
258 return NULL;
259 } else {
260 // OK: we will return a 0-sized array.
261 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
262 tag);
263 }
264 }
265
266 jsize byteCount = entry.count * tagSize;
267 jbyteArray byteArray = env->NewByteArray(byteCount);
268 if (env->ExceptionCheck()) return NULL;
269
270 // Copy into java array from native array
271 ScopedByteArrayRW arrayWriter(env, byteArray);
272 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
273
274 return byteArray;
275}
276
277static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
278 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
279
280 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
281 if (metadata == NULL) return;
282
283 int tagType = get_camera_metadata_tag_type(tag);
284 if (tagType == -1) {
285 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
286 "Tag (%d) did not have a type", tag);
287 return;
288 }
289 size_t tagSize = Helpers::getTypeSize(tagType);
290
291 status_t res;
292
293 if (src == NULL) {
294 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700295 if (metadata->exists(tag)) {
296 res = metadata->erase(tag);
297 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
298 } else {
299 res = OK;
300 ALOGV("%s: Don't need to erase", __FUNCTION__);
301 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700302 } else {
303 // Copy from java array into native array
304 ScopedByteArrayRO arrayReader(env, src);
305 if (arrayReader.get() == NULL) return;
306
307 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
308 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700309
310 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700311 }
312
313 if (res == OK) {
314 return;
315 } else if (res == BAD_VALUE) {
316 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
317 "Src byte array was poorly formed");
318 } else if (res == INVALID_OPERATION) {
319 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
320 "Internal error while trying to update metadata");
321 } else {
322 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
323 "Unknown error (%d) while trying to update "
324 "metadata", res);
325 }
326}
327
Igor Murashkin70725502013-06-25 20:27:06 +0000328static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
329 ALOGV("%s", __FUNCTION__);
330 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
331 if (metadata == NULL) {
332 return;
333 }
334
335 Parcel* parcelNative = parcelForJavaObject(env, parcel);
336 if (parcelNative == NULL) {
337 jniThrowNullPointerException(env, "parcel");
338 return;
339 }
340
341 status_t err;
342 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
343 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
344 "Failed to read from parcel (error code %d)", err);
345 return;
346 }
347}
348
349static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
350 ALOGV("%s", __FUNCTION__);
351 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
352 if (metadata == NULL) {
353 return;
354 }
355
356 Parcel* parcelNative = parcelForJavaObject(env, parcel);
357 if (parcelNative == NULL) {
358 jniThrowNullPointerException(env, "parcel");
359 return;
360 }
361
362 status_t err;
363 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
364 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
365 "Failed to write to parcel (error code %d)", err);
366 return;
367 }
368}
369
370} // extern "C"
371
372//-------------------------------------------------
373
374static JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700375// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000376 { "nativeClassInit",
377 "()V",
378 (void *)CameraMetadata_classInit },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700379 { "nativeGetTagFromKey",
380 "(Ljava/lang/String;)I",
381 (void *)CameraMetadata_getTagFromKey },
382 { "nativeGetTypeFromTag",
383 "(I)I",
384 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800385 { "nativeSetupGlobalVendorTagDescriptor",
386 "()I",
387 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700388// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000389 { "nativeAllocate",
390 "()J",
391 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700392 { "nativeAllocateCopy",
393 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
394 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000395 { "nativeIsEmpty",
396 "()Z",
397 (void*)CameraMetadata_isEmpty },
398 { "nativeGetEntryCount",
399 "()I",
400 (void*)CameraMetadata_getEntryCount },
401 { "nativeClose",
402 "()V",
403 (void*)CameraMetadata_close },
404 { "nativeSwap",
405 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
406 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700407 { "nativeReadValues",
408 "(I)[B",
409 (void *)CameraMetadata_readValues },
410 { "nativeWriteValues",
411 "(I[B)V",
412 (void *)CameraMetadata_writeValues },
413// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000414 { "nativeReadFromParcel",
415 "(Landroid/os/Parcel;)V",
416 (void *)CameraMetadata_readFromParcel },
417 { "nativeWriteToParcel",
418 "(Landroid/os/Parcel;)V",
419 (void *)CameraMetadata_writeToParcel },
420};
421
422struct field {
423 const char *class_name;
424 const char *field_name;
425 const char *field_type;
426 jfieldID *jfield;
427};
428
429static int find_fields(JNIEnv *env, field *fields, int count)
430{
431 for (int i = 0; i < count; i++) {
432 field *f = &fields[i];
433 jclass clazz = env->FindClass(f->class_name);
434 if (clazz == NULL) {
435 ALOGE("Can't find %s", f->class_name);
436 return -1;
437 }
438
439 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
440 if (field == NULL) {
441 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
442 return -1;
443 }
444
445 *(f->jfield) = field;
446 }
447
448 return 0;
449}
450
451// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700452int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000453{
454 // Register native functions
455 return AndroidRuntime::registerNativeMethods(env,
456 CAMERA_METADATA_CLASS_NAME,
457 gCameraMetadataMethods,
458 NELEM(gCameraMetadataMethods));
459}
460
461extern "C" {
462static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
463 // XX: Why do this separately instead of doing it in the register function?
464 ALOGV("%s", __FUNCTION__);
465
466 field fields_to_find[] = {
467 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
468 };
469
470 // Do this here instead of in register_native_methods,
471 // since otherwise it will fail to find the fields.
472 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
473 return;
474
475 jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME);
476}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700477
478static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
479
480 ScopedUtfChars keyScoped(env, keyName);
481 const char *key = keyScoped.c_str();
482 if (key == NULL) {
483 // exception thrown by ScopedUtfChars
484 return 0;
485 }
486 size_t keyLength = strlen(key);
487
488 ALOGV("%s (key = '%s')", __FUNCTION__, key);
489
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800490 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
491
Igor Murashkin3c40a042014-04-22 15:05:50 -0700492 SortedVector<String8> vendorSections;
493 size_t vendorSectionCount = 0;
494
495 if (vTags != 0) {
496 vendorSections = vTags->getAllSectionNames();
497 vendorSectionCount = vendorSections.size();
498 }
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800499
Igor Murashkinb519cc52013-07-02 11:23:44 -0700500 // First, find the section by the longest string match
501 const char *section = NULL;
502 size_t sectionIndex = 0;
503 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800504 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
505 for (size_t i = 0; i < totalSectionCount; ++i) {
506
507 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
508 vendorSections[i - ANDROID_SECTION_COUNT].string();
Igor Murashkinb519cc52013-07-02 11:23:44 -0700509 ALOGVV("%s: Trying to match against section '%s'",
510 __FUNCTION__, str);
511 if (strstr(key, str) == key) { // key begins with the section name
512 size_t strLength = strlen(str);
513
514 ALOGVV("%s: Key begins with section name", __FUNCTION__);
515
516 // section name is the longest we've found so far
517 if (section == NULL || sectionLength < strLength) {
518 section = str;
519 sectionIndex = i;
520 sectionLength = strLength;
521
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800522 ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700523 }
524 }
525 }
526
Igor Murashkinb519cc52013-07-02 11:23:44 -0700527 // TODO: Make above get_camera_metadata_section_from_name ?
528
529 if (section == NULL) {
530 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
531 "Could not find section name for key '%s')", key);
532 return 0;
533 } else {
534 ALOGV("%s: Found matched section '%s' (%d)",
535 __FUNCTION__, section, sectionIndex);
536 }
537
538 // Get the tag name component of the key
539 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
540 if (sectionLength + 1 >= keyLength) {
541 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
542 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800543 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700544 }
545
546 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800547 uint32_t tag = 0;
548 if (sectionIndex < ANDROID_SECTION_COUNT) {
549 // Match built-in tags (typically android.*)
550 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
551 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
552 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700553
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800554 for (tag = tagBegin; tag < tagEnd; ++tag) {
555 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700556
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800557 if (strcmp(keyTagName, tagName) == 0) {
558 ALOGV("%s: Found matched tag '%s' (%d)",
559 __FUNCTION__, tagName, tag);
560 break;
561 }
562 }
563
564 if (tag == tagEnd) {
565 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
566 "Could not find tag name for key '%s')", key);
567 return 0;
568 }
Igor Murashkin3c40a042014-04-22 15:05:50 -0700569 } else if (vTags != 0) {
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800570 // Match vendor tags (typically com.*)
571 const String8 sectionName(section);
572 const String8 tagName(keyTagName);
573
574 status_t res = OK;
575 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
576 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
577 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
578 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700579 }
580 }
581
Igor Murashkinb519cc52013-07-02 11:23:44 -0700582 // TODO: Make above get_camera_metadata_tag_from_name ?
583
Igor Murashkinb519cc52013-07-02 11:23:44 -0700584 return tag;
585}
586
587static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
588 int tagType = get_camera_metadata_tag_type(tag);
589 if (tagType == -1) {
590 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
591 "Tag (%d) did not have a type", tag);
592 return -1;
593 }
594
595 return tagType;
596}
597
Ruben Brunk85c43882014-02-21 17:40:51 -0800598static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
599 const String16 NAME("media.camera");
600 sp<ICameraService> cameraService;
601 status_t err = getService(NAME, /*out*/&cameraService);
602
603 if (err != OK) {
604 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
605 strerror(-err), err);
606 return err;
607 }
608
609 sp<VendorTagDescriptor> desc;
610 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
611
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700612 if (err == -EOPNOTSUPP) {
613 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
614 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
615
616 return OK;
617 } else if (err != OK) {
618 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
619 __FUNCTION__, strerror(-err), err);
Ruben Brunk85c43882014-02-21 17:40:51 -0800620 return err;
621 }
622
623 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
624
625 return err;
626}
627
Igor Murashkin70725502013-06-25 20:27:06 +0000628} // extern "C"