Home | History | Annotate | Download | only in jni
      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 <gui/SurfaceTexture.h>
     29 #include <surfaceflinger/Surface.h>
     30 #include <camera/Camera.h>
     31 #include <binder/IMemory.h>
     32 
     33 using namespace android;
     34 
     35 struct fields_t {
     36     jfieldID    context;
     37     jfieldID    surface;
     38     jfieldID    surfaceTexture;
     39     jfieldID    facing;
     40     jfieldID    orientation;
     41     jfieldID    face_rect;
     42     jfieldID    face_score;
     43     jfieldID    rect_left;
     44     jfieldID    rect_top;
     45     jfieldID    rect_right;
     46     jfieldID    rect_bottom;
     47     jmethodID   post_event;
     48     jmethodID   rect_constructor;
     49     jmethodID   face_constructor;
     50 };
     51 
     52 static fields_t fields;
     53 static Mutex sLock;
     54 
     55 // provides persistent context for calls from native code to Java
     56 class JNICameraContext: public CameraListener
     57 {
     58 public:
     59     JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera);
     60     ~JNICameraContext() { release(); }
     61     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
     62     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
     63                           camera_frame_metadata_t *metadata);
     64     virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
     65     void postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata);
     66     void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType);
     67     void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
     68     sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
     69     bool isRawImageCallbackBufferAvailable() const;
     70     void release();
     71 
     72 private:
     73     void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
     74     void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers);
     75     void clearCallbackBuffers_l(JNIEnv *env);
     76     jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize);
     77 
     78     jobject     mCameraJObjectWeak;     // weak reference to java object
     79     jclass      mCameraJClass;          // strong reference to java class
     80     sp<Camera>  mCamera;                // strong reference to native object
     81     jclass      mFaceClass;  // strong reference to Face class
     82     jclass      mRectClass;  // strong reference to Rect class
     83     Mutex       mLock;
     84 
     85     /*
     86      * Global reference application-managed raw image buffer queue.
     87      *
     88      * Manual-only mode is supported for raw image callbacks, which is
     89      * set whenever method addCallbackBuffer() with msgType =
     90      * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned
     91      * with raw image callbacks.
     92      */
     93     Vector<jbyteArray> mRawImageCallbackBuffers;
     94 
     95     /*
     96      * Application-managed preview buffer queue and the flags
     97      * associated with the usage of the preview buffer callback.
     98      */
     99     Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
    100     bool mManualBufferMode;              // Whether to use application managed buffers.
    101     bool mManualCameraCallbackSet;       // Whether the callback has been set, used to
    102                                          // reduce unnecessary calls to set the callback.
    103 };
    104 
    105 bool JNICameraContext::isRawImageCallbackBufferAvailable() const
    106 {
    107     return !mRawImageCallbackBuffers.isEmpty();
    108 }
    109 
    110 sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
    111 {
    112     sp<Camera> camera;
    113     Mutex::Autolock _l(sLock);
    114     JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
    115     if (context != NULL) {
    116         camera = context->getCamera();
    117     }
    118     LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
    119     if (camera == 0) {
    120         jniThrowRuntimeException(env, "Method called after release()");
    121     }
    122 
    123     if (pContext != NULL) *pContext = context;
    124     return camera;
    125 }
    126 
    127 JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera)
    128 {
    129     mCameraJObjectWeak = env->NewGlobalRef(weak_this);
    130     mCameraJClass = (jclass)env->NewGlobalRef(clazz);
    131     mCamera = camera;
    132 
    133     jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
    134     mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
    135 
    136     jclass rectClazz = env->FindClass("android/graphics/Rect");
    137     mRectClass = (jclass) env->NewGlobalRef(rectClazz);
    138 
    139     mManualBufferMode = false;
    140     mManualCameraCallbackSet = false;
    141 }
    142 
    143 void JNICameraContext::release()
    144 {
    145     LOGV("release");
    146     Mutex::Autolock _l(mLock);
    147     JNIEnv *env = AndroidRuntime::getJNIEnv();
    148 
    149     if (mCameraJObjectWeak != NULL) {
    150         env->DeleteGlobalRef(mCameraJObjectWeak);
    151         mCameraJObjectWeak = NULL;
    152     }
    153     if (mCameraJClass != NULL) {
    154         env->DeleteGlobalRef(mCameraJClass);
    155         mCameraJClass = NULL;
    156     }
    157     if (mFaceClass != NULL) {
    158         env->DeleteGlobalRef(mFaceClass);
    159         mFaceClass = NULL;
    160     }
    161     if (mRectClass != NULL) {
    162         env->DeleteGlobalRef(mRectClass);
    163         mRectClass = NULL;
    164     }
    165     clearCallbackBuffers_l(env);
    166     mCamera.clear();
    167 }
    168 
    169 void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
    170 {
    171     LOGV("notify");
    172 
    173     // VM pointer will be NULL if object is released
    174     Mutex::Autolock _l(mLock);
    175     if (mCameraJObjectWeak == NULL) {
    176         LOGW("callback on dead camera object");
    177         return;
    178     }
    179     JNIEnv *env = AndroidRuntime::getJNIEnv();
    180 
    181     /*
    182      * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it
    183      * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed
    184      * to the Java app.
    185      */
    186     if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) {
    187         msgType = CAMERA_MSG_RAW_IMAGE;
    188     }
    189 
    190     env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
    191             mCameraJObjectWeak, msgType, ext1, ext2, NULL);
    192 }
    193 
    194 jbyteArray JNICameraContext::getCallbackBuffer(
    195         JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize)
    196 {
    197     jbyteArray obj = NULL;
    198 
    199     // Vector access should be protected by lock in postData()
    200     if (!buffers->isEmpty()) {
    201         LOGV("Using callback buffer from queue of length %d", buffers->size());
    202         jbyteArray globalBuffer = buffers->itemAt(0);
    203         buffers->removeAt(0);
    204 
    205         obj = (jbyteArray)env->NewLocalRef(globalBuffer);
    206         env->DeleteGlobalRef(globalBuffer);
    207 
    208         if (obj != NULL) {
    209             jsize bufferLength = env->GetArrayLength(obj);
    210             if ((int)bufferLength < (int)bufferSize) {
    211                 LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!",
    212                     bufferSize, bufferLength);
    213                 env->DeleteLocalRef(obj);
    214                 return NULL;
    215             }
    216         }
    217     }
    218 
    219     return obj;
    220 }
    221 
    222 void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
    223 {
    224     jbyteArray obj = NULL;
    225 
    226     // allocate Java byte array and copy data
    227     if (dataPtr != NULL) {
    228         ssize_t offset;
    229         size_t size;
    230         sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
    231         LOGV("copyAndPost: off=%ld, size=%d", offset, size);
    232         uint8_t *heapBase = (uint8_t*)heap->base();
    233 
    234         if (heapBase != NULL) {
    235             const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset);
    236 
    237             if (msgType == CAMERA_MSG_RAW_IMAGE) {
    238                 obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size);
    239             } else if (msgType == CAMERA_MSG_PREVIEW_FRAME && mManualBufferMode) {
    240                 obj = getCallbackBuffer(env, &mCallbackBuffers, size);
    241 
    242                 if (mCallbackBuffers.isEmpty()) {
    243                     LOGV("Out of buffers, clearing callback!");
    244                     mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
    245                     mManualCameraCallbackSet = false;
    246 
    247                     if (obj == NULL) {
    248                         return;
    249                     }
    250                 }
    251             } else {
    252                 LOGV("Allocating callback buffer");
    253                 obj = env->NewByteArray(size);
    254             }
    255 
    256             if (obj == NULL) {
    257                 LOGE("Couldn't allocate byte array for JPEG data");
    258                 env->ExceptionClear();
    259             } else {
    260                 env->SetByteArrayRegion(obj, 0, size, data);
    261             }
    262         } else {
    263             LOGE("image heap is NULL");
    264         }
    265     }
    266 
    267     // post image data to Java
    268     env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
    269             mCameraJObjectWeak, msgType, 0, 0, obj);
    270     if (obj) {
    271         env->DeleteLocalRef(obj);
    272     }
    273 }
    274 
    275 void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr,
    276                                 camera_frame_metadata_t *metadata)
    277 {
    278     // VM pointer will be NULL if object is released
    279     Mutex::Autolock _l(mLock);
    280     JNIEnv *env = AndroidRuntime::getJNIEnv();
    281     if (mCameraJObjectWeak == NULL) {
    282         LOGW("callback on dead camera object");
    283         return;
    284     }
    285 
    286     int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA;
    287 
    288     // return data based on callback type
    289     switch (dataMsgType) {
    290         case CAMERA_MSG_VIDEO_FRAME:
    291             // should never happen
    292             break;
    293 
    294         // For backward-compatibility purpose, if there is no callback
    295         // buffer for raw image, the callback returns null.
    296         case CAMERA_MSG_RAW_IMAGE:
    297             LOGV("rawCallback");
    298             if (mRawImageCallbackBuffers.isEmpty()) {
    299                 env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
    300                         mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
    301             } else {
    302                 copyAndPost(env, dataPtr, dataMsgType);
    303             }
    304             break;
    305 
    306         // There is no data.
    307         case 0:
    308             break;
    309 
    310         default:
    311             LOGV("dataCallback(%d, %p)", dataMsgType, dataPtr.get());
    312             copyAndPost(env, dataPtr, dataMsgType);
    313             break;
    314     }
    315 
    316     // post frame metadata to Java
    317     if (metadata && (msgType & CAMERA_MSG_PREVIEW_METADATA)) {
    318         postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata);
    319     }
    320 }
    321 
    322 void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
    323 {
    324     // TODO: plumb up to Java. For now, just drop the timestamp
    325     postData(msgType, dataPtr, NULL);
    326 }
    327 
    328 void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
    329 {
    330     jobjectArray obj = NULL;
    331     obj = (jobjectArray) env->NewObjectArray(metadata->number_of_faces,
    332                                              mFaceClass, NULL);
    333     if (obj == NULL) {
    334         LOGE("Couldn't allocate face metadata array");
    335         return;
    336     }
    337 
    338     for (int i = 0; i < metadata->number_of_faces; i++) {
    339         jobject face = env->NewObject(mFaceClass, fields.face_constructor);
    340         env->SetObjectArrayElement(obj, i, face);
    341 
    342         jobject rect = env->NewObject(mRectClass, fields.rect_constructor);
    343         env->SetIntField(rect, fields.rect_left, metadata->faces[i].rect[0]);
    344         env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]);
    345         env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]);
    346         env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]);
    347 
    348         env->SetObjectField(face, fields.face_rect, rect);
    349         env->SetIntField(face, fields.face_score, metadata->faces[i].score);
    350 
    351         env->DeleteLocalRef(face);
    352         env->DeleteLocalRef(rect);
    353     }
    354     env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
    355             mCameraJObjectWeak, msgType, 0, 0, obj);
    356     env->DeleteLocalRef(obj);
    357 }
    358 
    359 void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode)
    360 {
    361     Mutex::Autolock _l(mLock);
    362     mManualBufferMode = manualMode;
    363     mManualCameraCallbackSet = false;
    364 
    365     // In order to limit the over usage of binder threads, all non-manual buffer
    366     // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
    367     //
    368     // Continuous callbacks will have the callback re-registered from handleMessage.
    369     // Manual buffer mode will operate as fast as possible, relying on the finite supply
    370     // of buffers for throttling.
    371 
    372     if (!installed) {
    373         mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
    374         clearCallbackBuffers_l(env, &mCallbackBuffers);
    375     } else if (mManualBufferMode) {
    376         if (!mCallbackBuffers.isEmpty()) {
    377             mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
    378             mManualCameraCallbackSet = true;
    379         }
    380     } else {
    381         mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
    382         clearCallbackBuffers_l(env, &mCallbackBuffers);
    383     }
    384 }
    385 
    386 void JNICameraContext::addCallbackBuffer(
    387         JNIEnv *env, jbyteArray cbb, int msgType)
    388 {
    389     LOGV("addCallbackBuffer: 0x%x", msgType);
    390     if (cbb != NULL) {
    391         Mutex::Autolock _l(mLock);
    392         switch (msgType) {
    393             case CAMERA_MSG_PREVIEW_FRAME: {
    394                 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
    395                 mCallbackBuffers.push(callbackBuffer);
    396 
    397                 LOGV("Adding callback buffer to queue, %d total",
    398                         mCallbackBuffers.size());
    399 
    400                 // We want to make sure the camera knows we're ready for the
    401                 // next frame. This may have come unset had we not had a
    402                 // callbackbuffer ready for it last time.
    403                 if (mManualBufferMode && !mManualCameraCallbackSet) {
    404                     mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
    405                     mManualCameraCallbackSet = true;
    406                 }
    407                 break;
    408             }
    409             case CAMERA_MSG_RAW_IMAGE: {
    410                 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
    411                 mRawImageCallbackBuffers.push(callbackBuffer);
    412                 break;
    413             }
    414             default: {
    415                 jniThrowException(env,
    416                         "java/lang/IllegalArgumentException",
    417                         "Unsupported message type");
    418                 return;
    419             }
    420         }
    421     } else {
    422        LOGE("Null byte array!");
    423     }
    424 }
    425 
    426 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env)
    427 {
    428     clearCallbackBuffers_l(env, &mCallbackBuffers);
    429     clearCallbackBuffers_l(env, &mRawImageCallbackBuffers);
    430 }
    431 
    432 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) {
    433     LOGV("Clearing callback buffers, %d remained", buffers->size());
    434     while (!buffers->isEmpty()) {
    435         env->DeleteGlobalRef(buffers->top());
    436         buffers->pop();
    437     }
    438 }
    439 
    440 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz)
    441 {
    442     return Camera::getNumberOfCameras();
    443 }
    444 
    445 static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz,
    446     jint cameraId, jobject info_obj)
    447 {
    448     CameraInfo cameraInfo;
    449     status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
    450     if (rc != NO_ERROR) {
    451         jniThrowRuntimeException(env, "Fail to get camera info");
    452         return;
    453     }
    454     env->SetIntField(info_obj, fields.facing, cameraInfo.facing);
    455     env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation);
    456 }
    457 
    458 // connect to camera service
    459 static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    460     jobject weak_this, jint cameraId)
    461 {
    462     sp<Camera> camera = Camera::connect(cameraId);
    463 
    464     if (camera == NULL) {
    465         jniThrowRuntimeException(env, "Fail to connect to camera service");
    466         return;
    467     }
    468 
    469     // make sure camera hardware is alive
    470     if (camera->getStatus() != NO_ERROR) {
    471         jniThrowRuntimeException(env, "Camera initialization failed");
    472         return;
    473     }
    474 
    475     jclass clazz = env->GetObjectClass(thiz);
    476     if (clazz == NULL) {
    477         jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
    478         return;
    479     }
    480 
    481     // We use a weak reference so the Camera object can be garbage collected.
    482     // The reference is only used as a proxy for callbacks.
    483     sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    484     context->incStrong(thiz);
    485     camera->setListener(context);
    486 
    487     // save context in opaque field
    488     env->SetIntField(thiz, fields.context, (int)context.get());
    489 }
    490 
    491 // disconnect from camera service
    492 // It's okay to call this when the native camera context is already null.
    493 // This handles the case where the user has called release() and the
    494 // finalizer is invoked later.
    495 static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
    496 {
    497     // TODO: Change to LOGV
    498     LOGV("release camera");
    499     JNICameraContext* context = NULL;
    500     sp<Camera> camera;
    501     {
    502         Mutex::Autolock _l(sLock);
    503         context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
    504 
    505         // Make sure we do not attempt to callback on a deleted Java object.
    506         env->SetIntField(thiz, fields.context, 0);
    507     }
    508 
    509     // clean up if release has not been called before
    510     if (context != NULL) {
    511         camera = context->getCamera();
    512         context->release();
    513         LOGV("native_release: context=%p camera=%p", context, camera.get());
    514 
    515         // clear callbacks
    516         if (camera != NULL) {
    517             camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
    518             camera->disconnect();
    519         }
    520 
    521         // remove context to prevent further Java access
    522         context->decStrong(thiz);
    523     }
    524 }
    525 
    526 static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
    527 {
    528     LOGV("setPreviewDisplay");
    529     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    530     if (camera == 0) return;
    531 
    532     sp<Surface> surface = NULL;
    533     if (jSurface != NULL) {
    534         surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));
    535     }
    536     if (camera->setPreviewDisplay(surface) != NO_ERROR) {
    537         jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
    538     }
    539 }
    540 
    541 static void android_hardware_Camera_setPreviewTexture(JNIEnv *env,
    542         jobject thiz, jobject jSurfaceTexture)
    543 {
    544     LOGV("setPreviewTexture");
    545     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    546     if (camera == 0) return;
    547 
    548     sp<SurfaceTexture> surfaceTexture = NULL;
    549     if (jSurfaceTexture != NULL) {
    550         surfaceTexture = reinterpret_cast<SurfaceTexture*>(env->GetIntField(
    551                 jSurfaceTexture, fields.surfaceTexture));
    552     }
    553     if (camera->setPreviewTexture(surfaceTexture) != NO_ERROR) {
    554         jniThrowException(env, "java/io/IOException",
    555                 "setPreviewTexture failed");
    556     }
    557 }
    558 
    559 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
    560 {
    561     LOGV("startPreview");
    562     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    563     if (camera == 0) return;
    564 
    565     if (camera->startPreview() != NO_ERROR) {
    566         jniThrowRuntimeException(env, "startPreview failed");
    567         return;
    568     }
    569 }
    570 
    571 static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
    572 {
    573     LOGV("stopPreview");
    574     sp<Camera> c = get_native_camera(env, thiz, NULL);
    575     if (c == 0) return;
    576 
    577     c->stopPreview();
    578 }
    579 
    580 static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz)
    581 {
    582     LOGV("previewEnabled");
    583     sp<Camera> c = get_native_camera(env, thiz, NULL);
    584     if (c == 0) return false;
    585 
    586     return c->previewEnabled();
    587 }
    588 
    589 static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer)
    590 {
    591     LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer);
    592     // Important: Only install preview_callback if the Java code has called
    593     // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
    594     // each preview frame for nothing.
    595     JNICameraContext* context;
    596     sp<Camera> camera = get_native_camera(env, thiz, &context);
    597     if (camera == 0) return;
    598 
    599     // setCallbackMode will take care of setting the context flags and calling
    600     // camera->setPreviewCallbackFlags within a mutex for us.
    601     context->setCallbackMode(env, installed, manualBuffer);
    602 }
    603 
    604 static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) {
    605     LOGV("addCallbackBuffer: 0x%x", msgType);
    606 
    607     JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
    608 
    609     if (context != NULL) {
    610         context->addCallbackBuffer(env, bytes, msgType);
    611     }
    612 }
    613 
    614 static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
    615 {
    616     LOGV("autoFocus");
    617     JNICameraContext* context;
    618     sp<Camera> c = get_native_camera(env, thiz, &context);
    619     if (c == 0) return;
    620 
    621     if (c->autoFocus() != NO_ERROR) {
    622         jniThrowRuntimeException(env, "autoFocus failed");
    623     }
    624 }
    625 
    626 static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz)
    627 {
    628     LOGV("cancelAutoFocus");
    629     JNICameraContext* context;
    630     sp<Camera> c = get_native_camera(env, thiz, &context);
    631     if (c == 0) return;
    632 
    633     if (c->cancelAutoFocus() != NO_ERROR) {
    634         jniThrowRuntimeException(env, "cancelAutoFocus failed");
    635     }
    636 }
    637 
    638 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType)
    639 {
    640     LOGV("takePicture");
    641     JNICameraContext* context;
    642     sp<Camera> camera = get_native_camera(env, thiz, &context);
    643     if (camera == 0) return;
    644 
    645     /*
    646      * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback
    647      * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the
    648      * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY
    649      * is enabled to receive the callback notification but no data.
    650      *
    651      * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the
    652      * Java application.
    653      */
    654     if (msgType & CAMERA_MSG_RAW_IMAGE) {
    655         LOGV("Enable raw image callback buffer");
    656         if (!context->isRawImageCallbackBufferAvailable()) {
    657             LOGV("Enable raw image notification, since no callback buffer exists");
    658             msgType &= ~CAMERA_MSG_RAW_IMAGE;
    659             msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY;
    660         }
    661     }
    662 
    663     if (camera->takePicture(msgType) != NO_ERROR) {
    664         jniThrowRuntimeException(env, "takePicture failed");
    665         return;
    666     }
    667 }
    668 
    669 static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
    670 {
    671     LOGV("setParameters");
    672     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    673     if (camera == 0) return;
    674 
    675     const jchar* str = env->GetStringCritical(params, 0);
    676     String8 params8;
    677     if (params) {
    678         params8 = String8(str, env->GetStringLength(params));
    679         env->ReleaseStringCritical(params, str);
    680     }
    681     if (camera->setParameters(params8) != NO_ERROR) {
    682         jniThrowRuntimeException(env, "setParameters failed");
    683         return;
    684     }
    685 }
    686 
    687 static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
    688 {
    689     LOGV("getParameters");
    690     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    691     if (camera == 0) return 0;
    692 
    693     return env->NewStringUTF(camera->getParameters().string());
    694 }
    695 
    696 static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
    697 {
    698     LOGV("reconnect");
    699     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    700     if (camera == 0) return;
    701 
    702     if (camera->reconnect() != NO_ERROR) {
    703         jniThrowException(env, "java/io/IOException", "reconnect failed");
    704         return;
    705     }
    706 }
    707 
    708 static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
    709 {
    710     LOGV("lock");
    711     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    712     if (camera == 0) return;
    713 
    714     if (camera->lock() != NO_ERROR) {
    715         jniThrowRuntimeException(env, "lock failed");
    716     }
    717 }
    718 
    719 static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
    720 {
    721     LOGV("unlock");
    722     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    723     if (camera == 0) return;
    724 
    725     if (camera->unlock() != NO_ERROR) {
    726         jniThrowRuntimeException(env, "unlock failed");
    727     }
    728 }
    729 
    730 static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value)
    731 {
    732     LOGV("startSmoothZoom");
    733     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    734     if (camera == 0) return;
    735 
    736     status_t rc = camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0);
    737     if (rc == BAD_VALUE) {
    738         char msg[64];
    739         sprintf(msg, "invalid zoom value=%d", value);
    740         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
    741     } else if (rc != NO_ERROR) {
    742         jniThrowRuntimeException(env, "start smooth zoom failed");
    743     }
    744 }
    745 
    746 static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz)
    747 {
    748     LOGV("stopSmoothZoom");
    749     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    750     if (camera == 0) return;
    751 
    752     if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) {
    753         jniThrowRuntimeException(env, "stop smooth zoom failed");
    754     }
    755 }
    756 
    757 static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz,
    758         jint value)
    759 {
    760     LOGV("setDisplayOrientation");
    761     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    762     if (camera == 0) return;
    763 
    764     if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) {
    765         jniThrowRuntimeException(env, "set display orientation failed");
    766     }
    767 }
    768 
    769 static void android_hardware_Camera_startFaceDetection(JNIEnv *env, jobject thiz,
    770         jint type)
    771 {
    772     LOGV("startFaceDetection");
    773     JNICameraContext* context;
    774     sp<Camera> camera = get_native_camera(env, thiz, &context);
    775     if (camera == 0) return;
    776 
    777     status_t rc = camera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, type, 0);
    778     if (rc == BAD_VALUE) {
    779         char msg[64];
    780         snprintf(msg, sizeof(msg), "invalid face detection type=%d", type);
    781         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
    782     } else if (rc != NO_ERROR) {
    783         jniThrowRuntimeException(env, "start face detection failed");
    784     }
    785 }
    786 
    787 static void android_hardware_Camera_stopFaceDetection(JNIEnv *env, jobject thiz)
    788 {
    789     LOGV("stopFaceDetection");
    790     sp<Camera> camera = get_native_camera(env, thiz, NULL);
    791     if (camera == 0) return;
    792 
    793     if (camera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0) != NO_ERROR) {
    794         jniThrowRuntimeException(env, "stop face detection failed");
    795     }
    796 }
    797 
    798 //-------------------------------------------------
    799 
    800 static JNINativeMethod camMethods[] = {
    801   { "getNumberOfCameras",
    802     "()I",
    803     (void *)android_hardware_Camera_getNumberOfCameras },
    804   { "getCameraInfo",
    805     "(ILandroid/hardware/Camera$CameraInfo;)V",
    806     (void*)android_hardware_Camera_getCameraInfo },
    807   { "native_setup",
    808     "(Ljava/lang/Object;I)V",
    809     (void*)android_hardware_Camera_native_setup },
    810   { "native_release",
    811     "()V",
    812     (void*)android_hardware_Camera_release },
    813   { "setPreviewDisplay",
    814     "(Landroid/view/Surface;)V",
    815     (void *)android_hardware_Camera_setPreviewDisplay },
    816   { "setPreviewTexture",
    817     "(Landroid/graphics/SurfaceTexture;)V",
    818     (void *)android_hardware_Camera_setPreviewTexture },
    819   { "startPreview",
    820     "()V",
    821     (void *)android_hardware_Camera_startPreview },
    822   { "_stopPreview",
    823     "()V",
    824     (void *)android_hardware_Camera_stopPreview },
    825   { "previewEnabled",
    826     "()Z",
    827     (void *)android_hardware_Camera_previewEnabled },
    828   { "setHasPreviewCallback",
    829     "(ZZ)V",
    830     (void *)android_hardware_Camera_setHasPreviewCallback },
    831   { "_addCallbackBuffer",
    832     "([BI)V",
    833     (void *)android_hardware_Camera_addCallbackBuffer },
    834   { "native_autoFocus",
    835     "()V",
    836     (void *)android_hardware_Camera_autoFocus },
    837   { "native_cancelAutoFocus",
    838     "()V",
    839     (void *)android_hardware_Camera_cancelAutoFocus },
    840   { "native_takePicture",
    841     "(I)V",
    842     (void *)android_hardware_Camera_takePicture },
    843   { "native_setParameters",
    844     "(Ljava/lang/String;)V",
    845     (void *)android_hardware_Camera_setParameters },
    846   { "native_getParameters",
    847     "()Ljava/lang/String;",
    848     (void *)android_hardware_Camera_getParameters },
    849   { "reconnect",
    850     "()V",
    851     (void*)android_hardware_Camera_reconnect },
    852   { "lock",
    853     "()V",
    854     (void*)android_hardware_Camera_lock },
    855   { "unlock",
    856     "()V",
    857     (void*)android_hardware_Camera_unlock },
    858   { "startSmoothZoom",
    859     "(I)V",
    860     (void *)android_hardware_Camera_startSmoothZoom },
    861   { "stopSmoothZoom",
    862     "()V",
    863     (void *)android_hardware_Camera_stopSmoothZoom },
    864   { "setDisplayOrientation",
    865     "(I)V",
    866     (void *)android_hardware_Camera_setDisplayOrientation },
    867   { "_startFaceDetection",
    868     "(I)V",
    869     (void *)android_hardware_Camera_startFaceDetection },
    870   { "_stopFaceDetection",
    871     "()V",
    872     (void *)android_hardware_Camera_stopFaceDetection},
    873 };
    874 
    875 struct field {
    876     const char *class_name;
    877     const char *field_name;
    878     const char *field_type;
    879     jfieldID   *jfield;
    880 };
    881 
    882 static int find_fields(JNIEnv *env, field *fields, int count)
    883 {
    884     for (int i = 0; i < count; i++) {
    885         field *f = &fields[i];
    886         jclass clazz = env->FindClass(f->class_name);
    887         if (clazz == NULL) {
    888             LOGE("Can't find %s", f->class_name);
    889             return -1;
    890         }
    891 
    892         jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
    893         if (field == NULL) {
    894             LOGE("Can't find %s.%s", f->class_name, f->field_name);
    895             return -1;
    896         }
    897 
    898         *(f->jfield) = field;
    899     }
    900 
    901     return 0;
    902 }
    903 
    904 // Get all the required offsets in java class and register native functions
    905 int register_android_hardware_Camera(JNIEnv *env)
    906 {
    907     field fields_to_find[] = {
    908         { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },
    909         { "android/view/Surface",    ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface },
    910         { "android/graphics/SurfaceTexture",
    911           ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture },
    912         { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
    913         { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
    914         { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect },
    915         { "android/hardware/Camera$Face", "score", "I", &fields.face_score },
    916         { "android/graphics/Rect", "left", "I", &fields.rect_left },
    917         { "android/graphics/Rect", "top", "I", &fields.rect_top },
    918         { "android/graphics/Rect", "right", "I", &fields.rect_right },
    919         { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom },
    920     };
    921 
    922     if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
    923         return -1;
    924 
    925     jclass clazz = env->FindClass("android/hardware/Camera");
    926     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
    927                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    928     if (fields.post_event == NULL) {
    929         LOGE("Can't find android/hardware/Camera.postEventFromNative");
    930         return -1;
    931     }
    932 
    933     clazz = env->FindClass("android/graphics/Rect");
    934     fields.rect_constructor = env->GetMethodID(clazz, "<init>", "()V");
    935     if (fields.rect_constructor == NULL) {
    936         LOGE("Can't find android/graphics/Rect.Rect()");
    937         return -1;
    938     }
    939 
    940     clazz = env->FindClass("android/hardware/Camera$Face");
    941     fields.face_constructor = env->GetMethodID(clazz, "<init>", "()V");
    942     if (fields.face_constructor == NULL) {
    943         LOGE("Can't find android/hardware/Camera$Face.Face()");
    944         return -1;
    945     }
    946 
    947     // Register native functions
    948     return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
    949                                               camMethods, NELEM(camMethods));
    950 }
    951