blob: 05a99a36a5602b34bafa7e116d972898fbb46d6b [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
492 SortedVector<String8> vendorSections = vTags->getAllSectionNames();
493 size_t vendorSectionCount = vendorSections.size();
494
Igor Murashkinb519cc52013-07-02 11:23:44 -0700495 // First, find the section by the longest string match
496 const char *section = NULL;
497 size_t sectionIndex = 0;
498 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800499 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
500 for (size_t i = 0; i < totalSectionCount; ++i) {
501
502 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
503 vendorSections[i - ANDROID_SECTION_COUNT].string();
Igor Murashkinb519cc52013-07-02 11:23:44 -0700504 ALOGVV("%s: Trying to match against section '%s'",
505 __FUNCTION__, str);
506 if (strstr(key, str) == key) { // key begins with the section name
507 size_t strLength = strlen(str);
508
509 ALOGVV("%s: Key begins with section name", __FUNCTION__);
510
511 // section name is the longest we've found so far
512 if (section == NULL || sectionLength < strLength) {
513 section = str;
514 sectionIndex = i;
515 sectionLength = strLength;
516
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800517 ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700518 }
519 }
520 }
521
Igor Murashkinb519cc52013-07-02 11:23:44 -0700522 // TODO: Make above get_camera_metadata_section_from_name ?
523
524 if (section == NULL) {
525 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
526 "Could not find section name for key '%s')", key);
527 return 0;
528 } else {
529 ALOGV("%s: Found matched section '%s' (%d)",
530 __FUNCTION__, section, sectionIndex);
531 }
532
533 // Get the tag name component of the key
534 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
535 if (sectionLength + 1 >= keyLength) {
536 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
537 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800538 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700539 }
540
541 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800542 uint32_t tag = 0;
543 if (sectionIndex < ANDROID_SECTION_COUNT) {
544 // Match built-in tags (typically android.*)
545 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
546 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
547 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700548
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800549 for (tag = tagBegin; tag < tagEnd; ++tag) {
550 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700551
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800552 if (strcmp(keyTagName, tagName) == 0) {
553 ALOGV("%s: Found matched tag '%s' (%d)",
554 __FUNCTION__, tagName, tag);
555 break;
556 }
557 }
558
559 if (tag == tagEnd) {
560 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
561 "Could not find tag name for key '%s')", key);
562 return 0;
563 }
564 } else {
565 // Match vendor tags (typically com.*)
566 const String8 sectionName(section);
567 const String8 tagName(keyTagName);
568
569 status_t res = OK;
570 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
571 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
572 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
573 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700574 }
575 }
576
Igor Murashkinb519cc52013-07-02 11:23:44 -0700577 // TODO: Make above get_camera_metadata_tag_from_name ?
578
Igor Murashkinb519cc52013-07-02 11:23:44 -0700579 return tag;
580}
581
582static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
583 int tagType = get_camera_metadata_tag_type(tag);
584 if (tagType == -1) {
585 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
586 "Tag (%d) did not have a type", tag);
587 return -1;
588 }
589
590 return tagType;
591}
592
Ruben Brunk85c43882014-02-21 17:40:51 -0800593static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
594 const String16 NAME("media.camera");
595 sp<ICameraService> cameraService;
596 status_t err = getService(NAME, /*out*/&cameraService);
597
598 if (err != OK) {
599 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
600 strerror(-err), err);
601 return err;
602 }
603
604 sp<VendorTagDescriptor> desc;
605 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
606
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700607 if (err == -EOPNOTSUPP) {
608 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
609 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
610
611 return OK;
612 } else if (err != OK) {
613 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
614 __FUNCTION__, strerror(-err), err);
Ruben Brunk85c43882014-02-21 17:40:51 -0800615 return err;
616 }
617
618 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
619
620 return err;
621}
622
Igor Murashkin70725502013-06-25 20:27:06 +0000623} // extern "C"