1 /* 2 ** 3 ** Copyright 2008, 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 19 #define LOG_TAG "Camera-JNI" 20 #include <utils/Log.h> 21 22 #include "jni.h" 23 #include "JNIHelp.h" 24 #include "android_runtime/AndroidRuntime.h" 25 26 #include <utils/Vector.h> 27 28 #include <surfaceflinger/Surface.h> 29 #include <camera/Camera.h> 30 #include <binder/IMemory.h> 31 32 using namespace android; 33 34 struct fields_t { 35 jfieldID context; 36 jfieldID surface; 37 jfieldID facing; 38 jfieldID orientation; 39 jmethodID post_event; 40 }; 41 42 static fields_t fields; 43 static Mutex sLock; 44 45 // provides persistent context for calls from native code to Java 46 class JNICameraContext: public CameraListener 47 { 48 public: 49 JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); 50 ~JNICameraContext() { release(); } 51 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); 52 virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); 53 virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); 54 void addCallbackBuffer(JNIEnv *env, jbyteArray cbb); 55 void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); 56 sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } 57 void release(); 58 59 private: 60 void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); 61 void clearCallbackBuffers_l(JNIEnv *env); 62 63 jobject mCameraJObjectWeak; // weak reference to java object 64 jclass mCameraJClass; // strong reference to java class 65 sp<Camera> mCamera; // strong reference to native object 66 Mutex mLock; 67 68 Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] 69 bool mManualBufferMode; // Whether to use application managed buffers. 70 bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback. 71 }; 72 73 sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) 74 { 75 sp<Camera> camera; 76 Mutex::Autolock _l(sLock); 77 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 78 if (context != NULL) { 79 camera = context->getCamera(); 80 } 81 LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); 82 if (camera == 0) { 83 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); 84 } 85 86 if (pContext != NULL) *pContext = context; 87 return camera; 88 } 89 90 JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) 91 { 92 mCameraJObjectWeak = env->NewGlobalRef(weak_this); 93 mCameraJClass = (jclass)env->NewGlobalRef(clazz); 94 mCamera = camera; 95 96 mManualBufferMode = false; 97 mManualCameraCallbackSet = false; 98 } 99 100 void JNICameraContext::release() 101 { 102 LOGV("release"); 103 Mutex::Autolock _l(mLock); 104 JNIEnv *env = AndroidRuntime::getJNIEnv(); 105 106 if (mCameraJObjectWeak != NULL) { 107 env->DeleteGlobalRef(mCameraJObjectWeak); 108 mCameraJObjectWeak = NULL; 109 } 110 if (mCameraJClass != NULL) { 111 env->DeleteGlobalRef(mCameraJClass); 112 mCameraJClass = NULL; 113 } 114 clearCallbackBuffers_l(env); 115 mCamera.clear(); 116 } 117 118 void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) 119 { 120 LOGV("notify"); 121 122 // VM pointer will be NULL if object is released 123 Mutex::Autolock _l(mLock); 124 if (mCameraJObjectWeak == NULL) { 125 LOGW("callback on dead camera object"); 126 return; 127 } 128 JNIEnv *env = AndroidRuntime::getJNIEnv(); 129 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 130 mCameraJObjectWeak, msgType, ext1, ext2, NULL); 131 } 132 133 void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) 134 { 135 jbyteArray obj = NULL; 136 137 // allocate Java byte array and copy data 138 if (dataPtr != NULL) { 139 ssize_t offset; 140 size_t size; 141 sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); 142 LOGV("postData: off=%d, size=%d", offset, size); 143 uint8_t *heapBase = (uint8_t*)heap->base(); 144 145 if (heapBase != NULL) { 146 const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset); 147 148 if (!mManualBufferMode) { 149 LOGV("Allocating callback buffer"); 150 obj = env->NewByteArray(size); 151 } else { 152 // Vector access should be protected by lock in postData() 153 if(!mCallbackBuffers.isEmpty()) { 154 LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size()); 155 jbyteArray globalBuffer = mCallbackBuffers.itemAt(0); 156 mCallbackBuffers.removeAt(0); 157 158 obj = (jbyteArray)env->NewLocalRef(globalBuffer); 159 env->DeleteGlobalRef(globalBuffer); 160 161 if (obj != NULL) { 162 jsize bufferLength = env->GetArrayLength(obj); 163 if ((int)bufferLength < (int)size) { 164 LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!", 165 size, bufferLength); 166 env->DeleteLocalRef(obj); 167 return; 168 } 169 } 170 } 171 172 if(mCallbackBuffers.isEmpty()) { 173 LOGV("Out of buffers, clearing callback!"); 174 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 175 mManualCameraCallbackSet = false; 176 177 if (obj == NULL) { 178 return; 179 } 180 } 181 } 182 183 if (obj == NULL) { 184 LOGE("Couldn't allocate byte array for JPEG data"); 185 env->ExceptionClear(); 186 } else { 187 env->SetByteArrayRegion(obj, 0, size, data); 188 } 189 } else { 190 LOGE("image heap is NULL"); 191 } 192 } 193 194 // post image data to Java 195 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 196 mCameraJObjectWeak, msgType, 0, 0, obj); 197 if (obj) { 198 env->DeleteLocalRef(obj); 199 } 200 } 201 202 void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) 203 { 204 // VM pointer will be NULL if object is released 205 Mutex::Autolock _l(mLock); 206 JNIEnv *env = AndroidRuntime::getJNIEnv(); 207 if (mCameraJObjectWeak == NULL) { 208 LOGW("callback on dead camera object"); 209 return; 210 } 211 212 // return data based on callback type 213 switch(msgType) { 214 case CAMERA_MSG_VIDEO_FRAME: 215 // should never happen 216 break; 217 // don't return raw data to Java 218 case CAMERA_MSG_RAW_IMAGE: 219 LOGV("rawCallback"); 220 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 221 mCameraJObjectWeak, msgType, 0, 0, NULL); 222 break; 223 default: 224 // TODO: Change to LOGV 225 LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); 226 copyAndPost(env, dataPtr, msgType); 227 break; 228 } 229 } 230 231 void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) 232 { 233 // TODO: plumb up to Java. For now, just drop the timestamp 234 postData(msgType, dataPtr); 235 } 236 237 void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) 238 { 239 Mutex::Autolock _l(mLock); 240 mManualBufferMode = manualMode; 241 mManualCameraCallbackSet = false; 242 243 // In order to limit the over usage of binder threads, all non-manual buffer 244 // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. 245 // 246 // Continuous callbacks will have the callback re-registered from handleMessage. 247 // Manual buffer mode will operate as fast as possible, relying on the finite supply 248 // of buffers for throttling. 249 250 if (!installed) { 251 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 252 clearCallbackBuffers_l(env); 253 } else if (mManualBufferMode) { 254 if (!mCallbackBuffers.isEmpty()) { 255 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 256 mManualCameraCallbackSet = true; 257 } 258 } else { 259 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); 260 clearCallbackBuffers_l(env); 261 } 262 } 263 264 void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) 265 { 266 if (cbb != NULL) { 267 Mutex::Autolock _l(mLock); 268 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 269 mCallbackBuffers.push(cbb); 270 271 LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); 272 273 // We want to make sure the camera knows we're ready for the next frame. 274 // This may have come unset had we not had a callbackbuffer ready for it last time. 275 if (mManualBufferMode && !mManualCameraCallbackSet) { 276 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 277 mManualCameraCallbackSet = true; 278 } 279 } else { 280 LOGE("Null byte array!"); 281 } 282 } 283 284 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) 285 { 286 LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size()); 287 while(!mCallbackBuffers.isEmpty()) { 288 env->DeleteGlobalRef(mCallbackBuffers.top()); 289 mCallbackBuffers.pop(); 290 } 291 } 292 293 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) 294 { 295 return Camera::getNumberOfCameras(); 296 } 297 298 static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, 299 jint cameraId, jobject info_obj) 300 { 301 CameraInfo cameraInfo; 302 status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); 303 if (rc != NO_ERROR) { 304 jniThrowException(env, "java/lang/RuntimeException", 305 "Fail to get camera info"); 306 return; 307 } 308 env->SetIntField(info_obj, fields.facing, cameraInfo.facing); 309 env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation); 310 } 311 312 // connect to camera service 313 static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, 314 jobject weak_this, jint cameraId) 315 { 316 sp<Camera> camera = Camera::connect(cameraId); 317 318 if (camera == NULL) { 319 jniThrowException(env, "java/lang/RuntimeException", 320 "Fail to connect to camera service"); 321 return; 322 } 323 324 // make sure camera hardware is alive 325 if (camera->getStatus() != NO_ERROR) { 326 jniThrowException(env, "java/lang/RuntimeException", "Camera initialization failed"); 327 return; 328 } 329 330 jclass clazz = env->GetObjectClass(thiz); 331 if (clazz == NULL) { 332 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/hardware/Camera"); 333 return; 334 } 335 336 // We use a weak reference so the Camera object can be garbage collected. 337 // The reference is only used as a proxy for callbacks. 338 sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); 339 context->incStrong(thiz); 340 camera->setListener(context); 341 342 // save context in opaque field 343 env->SetIntField(thiz, fields.context, (int)context.get()); 344 } 345 346 // disconnect from camera service 347 // It's okay to call this when the native camera context is already null. 348 // This handles the case where the user has called release() and the 349 // finalizer is invoked later. 350 static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 351 { 352 // TODO: Change to LOGV 353 LOGV("release camera"); 354 JNICameraContext* context = NULL; 355 sp<Camera> camera; 356 { 357 Mutex::Autolock _l(sLock); 358 context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 359 360 // Make sure we do not attempt to callback on a deleted Java object. 361 env->SetIntField(thiz, fields.context, 0); 362 } 363 364 // clean up if release has not been called before 365 if (context != NULL) { 366 camera = context->getCamera(); 367 context->release(); 368 LOGV("native_release: context=%p camera=%p", context, camera.get()); 369 370 // clear callbacks 371 if (camera != NULL) { 372 camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 373 camera->disconnect(); 374 } 375 376 // remove context to prevent further Java access 377 context->decStrong(thiz); 378 } 379 } 380 381 static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) 382 { 383 LOGV("setPreviewDisplay"); 384 sp<Camera> camera = get_native_camera(env, thiz, NULL); 385 if (camera == 0) return; 386 387 sp<Surface> surface = NULL; 388 if (jSurface != NULL) { 389 surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface)); 390 } 391 if (camera->setPreviewDisplay(surface) != NO_ERROR) { 392 jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); 393 } 394 } 395 396 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 397 { 398 LOGV("startPreview"); 399 sp<Camera> camera = get_native_camera(env, thiz, NULL); 400 if (camera == 0) return; 401 402 if (camera->startPreview() != NO_ERROR) { 403 jniThrowException(env, "java/lang/RuntimeException", "startPreview failed"); 404 return; 405 } 406 } 407 408 static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 409 { 410 LOGV("stopPreview"); 411 sp<Camera> c = get_native_camera(env, thiz, NULL); 412 if (c == 0) return; 413 414 c->stopPreview(); 415 } 416 417 static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 418 { 419 LOGV("previewEnabled"); 420 sp<Camera> c = get_native_camera(env, thiz, NULL); 421 if (c == 0) return false; 422 423 return c->previewEnabled(); 424 } 425 426 static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) 427 { 428 LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); 429 // Important: Only install preview_callback if the Java code has called 430 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 431 // each preview frame for nothing. 432 JNICameraContext* context; 433 sp<Camera> camera = get_native_camera(env, thiz, &context); 434 if (camera == 0) return; 435 436 // setCallbackMode will take care of setting the context flags and calling 437 // camera->setPreviewCallbackFlags within a mutex for us. 438 context->setCallbackMode(env, installed, manualBuffer); 439 } 440 441 static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) { 442 LOGV("addCallbackBuffer"); 443 444 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 445 446 if (context != NULL) { 447 context->addCallbackBuffer(env, bytes); 448 } 449 } 450 451 static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 452 { 453 LOGV("autoFocus"); 454 JNICameraContext* context; 455 sp<Camera> c = get_native_camera(env, thiz, &context); 456 if (c == 0) return; 457 458 if (c->autoFocus() != NO_ERROR) { 459 jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); 460 } 461 } 462 463 static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) 464 { 465 LOGV("cancelAutoFocus"); 466 JNICameraContext* context; 467 sp<Camera> c = get_native_camera(env, thiz, &context); 468 if (c == 0) return; 469 470 if (c->cancelAutoFocus() != NO_ERROR) { 471 jniThrowException(env, "java/lang/RuntimeException", "cancelAutoFocus failed"); 472 } 473 } 474 475 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) 476 { 477 LOGV("takePicture"); 478 JNICameraContext* context; 479 sp<Camera> camera = get_native_camera(env, thiz, &context); 480 if (camera == 0) return; 481 482 if (camera->takePicture() != NO_ERROR) { 483 jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); 484 return; 485 } 486 } 487 488 static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 489 { 490 LOGV("setParameters"); 491 sp<Camera> camera = get_native_camera(env, thiz, NULL); 492 if (camera == 0) return; 493 494 const jchar* str = env->GetStringCritical(params, 0); 495 String8 params8; 496 if (params) { 497 params8 = String8(str, env->GetStringLength(params)); 498 env->ReleaseStringCritical(params, str); 499 } 500 if (camera->setParameters(params8) != NO_ERROR) { 501 jniThrowException(env, "java/lang/RuntimeException", "setParameters failed"); 502 return; 503 } 504 } 505 506 static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 507 { 508 LOGV("getParameters"); 509 sp<Camera> camera = get_native_camera(env, thiz, NULL); 510 if (camera == 0) return 0; 511 512 return env->NewStringUTF(camera->getParameters().string()); 513 } 514 515 static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 516 { 517 LOGV("reconnect"); 518 sp<Camera> camera = get_native_camera(env, thiz, NULL); 519 if (camera == 0) return; 520 521 if (camera->reconnect() != NO_ERROR) { 522 jniThrowException(env, "java/io/IOException", "reconnect failed"); 523 return; 524 } 525 } 526 527 static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 528 { 529 LOGV("lock"); 530 sp<Camera> camera = get_native_camera(env, thiz, NULL); 531 if (camera == 0) return; 532 533 if (camera->lock() != NO_ERROR) { 534 jniThrowException(env, "java/lang/RuntimeException", "lock failed"); 535 } 536 } 537 538 static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 539 { 540 LOGV("unlock"); 541 sp<Camera> camera = get_native_camera(env, thiz, NULL); 542 if (camera == 0) return; 543 544 if (camera->unlock() != NO_ERROR) { 545 jniThrowException(env, "java/lang/RuntimeException", "unlock failed"); 546 } 547 } 548 549 static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value) 550 { 551 LOGV("startSmoothZoom"); 552 sp<Camera> camera = get_native_camera(env, thiz, NULL); 553 if (camera == 0) return; 554 555 status_t rc = camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0); 556 if (rc == BAD_VALUE) { 557 char msg[64]; 558 sprintf(msg, "invalid zoom value=%d", value); 559 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 560 } else if (rc != NO_ERROR) { 561 jniThrowException(env, "java/lang/RuntimeException", "start smooth zoom failed"); 562 } 563 } 564 565 static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz) 566 { 567 LOGV("stopSmoothZoom"); 568 sp<Camera> camera = get_native_camera(env, thiz, NULL); 569 if (camera == 0) return; 570 571 if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) { 572 jniThrowException(env, "java/lang/RuntimeException", "stop smooth zoom failed"); 573 } 574 } 575 576 static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz, 577 jint value) 578 { 579 LOGV("setDisplayOrientation"); 580 sp<Camera> camera = get_native_camera(env, thiz, NULL); 581 if (camera == 0) return; 582 583 if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) { 584 jniThrowException(env, "java/lang/RuntimeException", "set display orientation failed"); 585 } 586 } 587 588 //------------------------------------------------- 589 590 static JNINativeMethod camMethods[] = { 591 { "getNumberOfCameras", 592 "()I", 593 (void *)android_hardware_Camera_getNumberOfCameras }, 594 { "getCameraInfo", 595 "(ILandroid/hardware/Camera$CameraInfo;)V", 596 (void*)android_hardware_Camera_getCameraInfo }, 597 { "native_setup", 598 "(Ljava/lang/Object;I)V", 599 (void*)android_hardware_Camera_native_setup }, 600 { "native_release", 601 "()V", 602 (void*)android_hardware_Camera_release }, 603 { "setPreviewDisplay", 604 "(Landroid/view/Surface;)V", 605 (void *)android_hardware_Camera_setPreviewDisplay }, 606 { "startPreview", 607 "()V", 608 (void *)android_hardware_Camera_startPreview }, 609 { "stopPreview", 610 "()V", 611 (void *)android_hardware_Camera_stopPreview }, 612 { "previewEnabled", 613 "()Z", 614 (void *)android_hardware_Camera_previewEnabled }, 615 { "setHasPreviewCallback", 616 "(ZZ)V", 617 (void *)android_hardware_Camera_setHasPreviewCallback }, 618 { "addCallbackBuffer", 619 "([B)V", 620 (void *)android_hardware_Camera_addCallbackBuffer }, 621 { "native_autoFocus", 622 "()V", 623 (void *)android_hardware_Camera_autoFocus }, 624 { "native_cancelAutoFocus", 625 "()V", 626 (void *)android_hardware_Camera_cancelAutoFocus }, 627 { "native_takePicture", 628 "()V", 629 (void *)android_hardware_Camera_takePicture }, 630 { "native_setParameters", 631 "(Ljava/lang/String;)V", 632 (void *)android_hardware_Camera_setParameters }, 633 { "native_getParameters", 634 "()Ljava/lang/String;", 635 (void *)android_hardware_Camera_getParameters }, 636 { "reconnect", 637 "()V", 638 (void*)android_hardware_Camera_reconnect }, 639 { "lock", 640 "()V", 641 (void*)android_hardware_Camera_lock }, 642 { "unlock", 643 "()V", 644 (void*)android_hardware_Camera_unlock }, 645 { "startSmoothZoom", 646 "(I)V", 647 (void *)android_hardware_Camera_startSmoothZoom }, 648 { "stopSmoothZoom", 649 "()V", 650 (void *)android_hardware_Camera_stopSmoothZoom }, 651 { "setDisplayOrientation", 652 "(I)V", 653 (void *)android_hardware_Camera_setDisplayOrientation }, 654 }; 655 656 struct field { 657 const char *class_name; 658 const char *field_name; 659 const char *field_type; 660 jfieldID *jfield; 661 }; 662 663 static int find_fields(JNIEnv *env, field *fields, int count) 664 { 665 for (int i = 0; i < count; i++) { 666 field *f = &fields[i]; 667 jclass clazz = env->FindClass(f->class_name); 668 if (clazz == NULL) { 669 LOGE("Can't find %s", f->class_name); 670 return -1; 671 } 672 673 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 674 if (field == NULL) { 675 LOGE("Can't find %s.%s", f->class_name, f->field_name); 676 return -1; 677 } 678 679 *(f->jfield) = field; 680 } 681 682 return 0; 683 } 684 685 // Get all the required offsets in java class and register native functions 686 int register_android_hardware_Camera(JNIEnv *env) 687 { 688 field fields_to_find[] = { 689 { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, 690 { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface }, 691 { "android/hardware/Camera$CameraInfo", "facing", "I", &fields.facing }, 692 { "android/hardware/Camera$CameraInfo", "orientation", "I", &fields.orientation }, 693 }; 694 695 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 696 return -1; 697 698 jclass clazz = env->FindClass("android/hardware/Camera"); 699 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 700 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 701 if (fields.post_event == NULL) { 702 LOGE("Can't find android/hardware/Camera.postEventFromNative"); 703 return -1; 704 } 705 706 707 // Register native functions 708 return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", 709 camMethods, NELEM(camMethods)); 710 } 711 712