Home | History | Annotate | Download | only in portability
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ex.camera2.portability;
     18 
     19 import android.annotation.TargetApi;
     20 import android.graphics.SurfaceTexture;
     21 import android.hardware.Camera;
     22 import android.hardware.Camera.OnZoomChangeListener;
     23 import android.os.Build;
     24 import android.os.Handler;
     25 import android.os.Looper;
     26 import android.os.Message;
     27 import android.view.SurfaceHolder;
     28 
     29 import com.android.ex.camera2.portability.debug.Log;
     30 
     31 /**
     32  * An interface which provides possible camera device operations.
     33  *
     34  * The client should call {@code CameraAgent.openCamera} to get an instance
     35  * of {@link CameraAgent.CameraProxy} to control the camera. Classes
     36  * implementing this interface should have its own one unique {@code Thread}
     37  * other than the main thread for camera operations. Camera device callbacks
     38  * are wrapped since the client should not deal with
     39  * {@code android.hardware.Camera} directly.
     40  *
     41  * TODO: provide callback interfaces for:
     42  * {@code android.hardware.Camera.ErrorCallback},
     43  * {@code android.hardware.Camera.OnZoomChangeListener}, and
     44  */
     45 public abstract class CameraAgent {
     46     public static final long CAMERA_OPERATION_TIMEOUT_MS = 3500;
     47 
     48     private static final Log.Tag TAG = new Log.Tag("CamAgnt");
     49 
     50     public static class CameraStartPreviewCallbackForward
     51             implements CameraStartPreviewCallback {
     52         private final Handler mHandler;
     53         private final CameraStartPreviewCallback mCallback;
     54 
     55         public static CameraStartPreviewCallbackForward getNewInstance(
     56                 Handler handler, CameraStartPreviewCallback cb) {
     57             if (handler == null || cb == null) {
     58                 return null;
     59             }
     60             return new CameraStartPreviewCallbackForward(handler, cb);
     61         }
     62 
     63         private CameraStartPreviewCallbackForward(Handler h,
     64                 CameraStartPreviewCallback cb) {
     65             mHandler = h;
     66             mCallback = cb;
     67         }
     68 
     69         @Override
     70         public void onPreviewStarted() {
     71             mHandler.post(new Runnable() {
     72                 @Override
     73                 public void run() {
     74                     mCallback.onPreviewStarted();
     75                 }});
     76         }
     77     }
     78 
     79     /**
     80      * A callback helps to invoke the original callback on another
     81      * {@link android.os.Handler}.
     82      */
     83     public static class CameraOpenCallbackForward implements CameraOpenCallback {
     84         private final Handler mHandler;
     85         private final CameraOpenCallback mCallback;
     86 
     87         /**
     88          * Returns a new instance of {@link FaceDetectionCallbackForward}.
     89          *
     90          * @param handler The handler in which the callback will be invoked in.
     91          * @param cb The callback to be invoked.
     92          * @return The instance of the {@link FaceDetectionCallbackForward}, or
     93          *         null if any parameter is null.
     94          */
     95         public static CameraOpenCallbackForward getNewInstance(
     96                 Handler handler, CameraOpenCallback cb) {
     97             if (handler == null || cb == null) {
     98                 return null;
     99             }
    100             return new CameraOpenCallbackForward(handler, cb);
    101         }
    102 
    103         private CameraOpenCallbackForward(Handler h, CameraOpenCallback cb) {
    104             // Given that we are using the main thread handler, we can create it
    105             // here instead of holding onto the PhotoModule objects. In this
    106             // way, we can avoid memory leak.
    107             mHandler = new Handler(Looper.getMainLooper());
    108             mCallback = cb;
    109         }
    110 
    111         @Override
    112         public void onCameraOpened(final CameraProxy camera) {
    113             mHandler.post(new Runnable() {
    114                 @Override
    115                 public void run() {
    116                     mCallback.onCameraOpened(camera);
    117                 }});
    118         }
    119 
    120         @Override
    121         public void onCameraDisabled(final int cameraId) {
    122             mHandler.post(new Runnable() {
    123                 @Override
    124                 public void run() {
    125                     mCallback.onCameraDisabled(cameraId);
    126                 }});
    127         }
    128 
    129         @Override
    130         public void onDeviceOpenFailure(final int cameraId, final String info) {
    131             mHandler.post(new Runnable() {
    132                 @Override
    133                 public void run() {
    134                     mCallback.onDeviceOpenFailure(cameraId, info);
    135                 }});
    136         }
    137 
    138         @Override
    139         public void onDeviceOpenedAlready(final int cameraId, final String info) {
    140             mHandler.post(new Runnable() {
    141                 @Override
    142                 public void run() {
    143                     mCallback.onDeviceOpenedAlready(cameraId, info);
    144                 }});
    145         }
    146 
    147         @Override
    148         public void onReconnectionFailure(final CameraAgent mgr, final String info) {
    149             mHandler.post(new Runnable() {
    150                 @Override
    151                 public void run() {
    152                     mCallback.onReconnectionFailure(mgr, info);
    153                 }});
    154         }
    155     }
    156 
    157     /**
    158      * An interface which wraps
    159      * {@link android.hardware.Camera.ErrorCallback}
    160      */
    161     public static interface CameraErrorCallback {
    162         public void onError(int error, CameraProxy camera);
    163     }
    164 
    165     /**
    166      * An interface which wraps
    167      * {@link android.hardware.Camera.AutoFocusCallback}.
    168      */
    169     public static interface CameraAFCallback {
    170         public void onAutoFocus(boolean focused, CameraProxy camera);
    171     }
    172 
    173     /**
    174      * An interface which wraps
    175      * {@link android.hardware.Camera.AutoFocusMoveCallback}.
    176      */
    177     public static interface CameraAFMoveCallback {
    178         public void onAutoFocusMoving(boolean moving, CameraProxy camera);
    179     }
    180 
    181     /**
    182      * An interface which wraps
    183      * {@link android.hardware.Camera.ShutterCallback}.
    184      */
    185     public static interface CameraShutterCallback {
    186         public void onShutter(CameraProxy camera);
    187     }
    188 
    189     /**
    190      * An interface which wraps
    191      * {@link android.hardware.Camera.PictureCallback}.
    192      */
    193     public static interface CameraPictureCallback {
    194         public void onPictureTaken(byte[] data, CameraProxy camera);
    195     }
    196 
    197     /**
    198      * An interface which wraps
    199      * {@link android.hardware.Camera.PreviewCallback}.
    200      */
    201     public static interface CameraPreviewDataCallback {
    202         public void onPreviewFrame(byte[] data, CameraProxy camera);
    203     }
    204 
    205     /**
    206      * An interface which wraps
    207      * {@link android.hardware.Camera.FaceDetectionListener}.
    208      */
    209     public static interface CameraFaceDetectionCallback {
    210         /**
    211          * Callback for face detection.
    212          *
    213          * @param faces   Recognized face in the preview.
    214          * @param camera  The camera which the preview image comes from.
    215          */
    216         public void onFaceDetection(Camera.Face[] faces, CameraProxy camera);
    217     }
    218 
    219     /**
    220      * An interface to be called when the camera preview has started.
    221      */
    222     public static interface CameraStartPreviewCallback {
    223         /**
    224          * Callback when the preview starts.
    225          */
    226         public void onPreviewStarted();
    227     }
    228 
    229     /**
    230      * An interface to be called for any events when opening or closing the
    231      * camera device. This error callback is different from the one defined
    232      * in the framework, {@link android.hardware.Camera.ErrorCallback}, which
    233      * is used after the camera is opened.
    234      */
    235     public static interface CameraOpenCallback {
    236         /**
    237          * Callback when camera open succeeds.
    238          */
    239         public void onCameraOpened(CameraProxy camera);
    240 
    241         /**
    242          * Callback when {@link com.android.camera.CameraDisabledException} is
    243          * caught.
    244          *
    245          * @param cameraId The disabled camera.
    246          */
    247         public void onCameraDisabled(int cameraId);
    248 
    249         /**
    250          * Callback when {@link com.android.camera.CameraHardwareException} is
    251          * caught.
    252          *
    253          * @param cameraId The camera with the hardware failure.
    254          * @param info The extra info regarding this failure.
    255          */
    256         public void onDeviceOpenFailure(int cameraId, String info);
    257 
    258         /**
    259          * Callback when trying to open the camera which is already opened.
    260          *
    261          * @param cameraId The camera which is causing the open error.
    262          */
    263         public void onDeviceOpenedAlready(int cameraId, String info);
    264 
    265         /**
    266          * Callback when {@link java.io.IOException} is caught during
    267          * {@link android.hardware.Camera#reconnect()}.
    268          *
    269          * @param mgr The {@link CameraAgent}
    270          *            with the reconnect failure.
    271          */
    272         public void onReconnectionFailure(CameraAgent mgr, String info);
    273     }
    274 
    275     /**
    276      * Opens the camera of the specified ID asynchronously. The camera device
    277      * will be opened in the camera handler thread and will be returned through
    278      * the {@link CameraAgent.CameraOpenCallback#
    279      * onCameraOpened(com.android.camera.cameradevice.CameraAgent.CameraProxy)}.
    280      *
    281      * @param handler The {@link android.os.Handler} in which the callback
    282      *                was handled.
    283      * @param callback The callback for the result.
    284      * @param cameraId The camera ID to open.
    285      */
    286     public void openCamera(final Handler handler, final int cameraId,
    287                            final CameraOpenCallback callback) {
    288         try {
    289             getDispatchThread().runJob(new Runnable() {
    290                 @Override
    291                 public void run() {
    292                     getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
    293                             CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
    294                 }
    295             });
    296         } catch (final RuntimeException ex) {
    297             getCameraExceptionHandler().onDispatchThreadException(ex);
    298         }
    299     }
    300 
    301     /**
    302      * Closes the camera device.
    303      *
    304      * @param camera The camera to close. {@code null} means all.
    305      * @param synced Whether this call should be synchronous.
    306      */
    307     public void closeCamera(CameraProxy camera, boolean synced) {
    308         try {
    309             if (synced) {
    310                 // Don't bother to wait since camera is in bad state.
    311                 if (getCameraState().isInvalid()) {
    312                     return;
    313                 }
    314                 final WaitDoneBundle bundle = new WaitDoneBundle();
    315 
    316                 getDispatchThread().runJobSync(new Runnable() {
    317                     @Override
    318                     public void run() {
    319                         getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
    320                         getCameraHandler().post(bundle.mUnlockRunnable);
    321                     }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
    322             } else {
    323                 getDispatchThread().runJob(new Runnable() {
    324                     @Override
    325                     public void run() {
    326                         getCameraHandler().removeCallbacksAndMessages(null);
    327                         getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
    328                     }});
    329             }
    330         } catch (final RuntimeException ex) {
    331             getCameraExceptionHandler().onDispatchThreadException(ex);
    332         }
    333     }
    334 
    335     /**
    336      * Sets a callback for handling camera api runtime exceptions on
    337      * a handler.
    338      */
    339     public abstract void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler);
    340 
    341     /**
    342      * Recycles the resources used by this instance. CameraAgent will be in
    343      * an unusable state after calling this.
    344      */
    345     public abstract void recycle();
    346 
    347     /**
    348      * @return The camera devices info.
    349      */
    350     public abstract CameraDeviceInfo getCameraDeviceInfo();
    351 
    352     /**
    353      * @return The handler to which camera tasks should be posted.
    354      */
    355     protected abstract Handler getCameraHandler();
    356 
    357     /**
    358      * @return The thread used on which client callbacks are served.
    359      */
    360     protected abstract DispatchThread getDispatchThread();
    361 
    362     /**
    363      * @return The state machine tracking the camera API's current status.
    364      */
    365     protected abstract CameraStateHolder getCameraState();
    366 
    367     /**
    368      * @return The exception handler.
    369      */
    370     protected abstract CameraExceptionHandler getCameraExceptionHandler();
    371 
    372     /**
    373      * An interface that takes camera operation requests and post messages to the
    374      * camera handler thread. All camera operations made through this interface is
    375      * asynchronous by default except those mentioned specifically.
    376      */
    377     public abstract static class CameraProxy {
    378 
    379         /**
    380          * Returns the underlying {@link android.hardware.Camera} object used
    381          * by this proxy. This method should only be used when handing the
    382          * camera device over to {@link android.media.MediaRecorder} for
    383          * recording.
    384          */
    385         @Deprecated
    386         public abstract android.hardware.Camera getCamera();
    387 
    388         /**
    389          * @return The camera ID associated to by this
    390          * {@link CameraAgent.CameraProxy}.
    391          */
    392         public abstract int getCameraId();
    393 
    394         /**
    395          * @return The camera characteristics.
    396          */
    397         public abstract CameraDeviceInfo.Characteristics getCharacteristics();
    398 
    399         /**
    400          * @return The camera capabilities.
    401          */
    402         public abstract CameraCapabilities getCapabilities();
    403 
    404         /**
    405          * @return The camera agent which creates this proxy.
    406          */
    407         public abstract CameraAgent getAgent();
    408 
    409         /**
    410          * Reconnects to the camera device. On success, the camera device will
    411          * be returned through {@link CameraAgent
    412          * .CameraOpenCallback#onCameraOpened(com.android.camera.cameradevice.CameraAgent
    413          * .CameraProxy)}.
    414          * @see android.hardware.Camera#reconnect()
    415          *
    416          * @param handler The {@link android.os.Handler} in which the callback
    417          *                was handled.
    418          * @param cb The callback when any error happens.
    419          */
    420         public void reconnect(final Handler handler, final CameraOpenCallback cb) {
    421             try {
    422                 getDispatchThread().runJob(new Runnable() {
    423                     @Override
    424                     public void run() {
    425                         getCameraHandler().obtainMessage(CameraActions.RECONNECT, getCameraId(), 0,
    426                                 CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
    427                     }});
    428             } catch (final RuntimeException ex) {
    429                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    430             }
    431         }
    432 
    433         /**
    434          * Unlocks the camera device.
    435          *
    436          * @see android.hardware.Camera#unlock()
    437          */
    438         public void unlock() {
    439             // Don't bother to wait since camera is in bad state.
    440             if (getCameraState().isInvalid()) {
    441                 return;
    442             }
    443             final WaitDoneBundle bundle = new WaitDoneBundle();
    444             try {
    445                 getDispatchThread().runJobSync(new Runnable() {
    446                     @Override
    447                     public void run() {
    448                         getCameraHandler().sendEmptyMessage(CameraActions.UNLOCK);
    449                         getCameraHandler().post(bundle.mUnlockRunnable);
    450                     }
    451                 }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
    452             } catch (final RuntimeException ex) {
    453                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    454             }
    455         }
    456 
    457         /**
    458          * Locks the camera device.
    459          * @see android.hardware.Camera#lock()
    460          */
    461         public void lock() {
    462             try {
    463                 getDispatchThread().runJob(new Runnable() {
    464                     @Override
    465                     public void run() {
    466                         getCameraHandler().sendEmptyMessage(CameraActions.LOCK);
    467                     }});
    468             } catch (final RuntimeException ex) {
    469                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    470             }
    471         }
    472 
    473         /**
    474          * Sets the {@link android.graphics.SurfaceTexture} for preview.
    475          *
    476          * <p>Note that, once this operation has been performed, it is no longer
    477          * possible to change the preview or photo sizes in the
    478          * {@link CameraSettings} instance for this camera, and the mutators for
    479          * these fields are allowed to ignore all further invocations until the
    480          * preview is stopped with {@link #stopPreview}.</p>
    481          *
    482          * @param surfaceTexture The {@link SurfaceTexture} for preview.
    483          *
    484          * @see CameraSettings#setPhotoSize
    485          * @see CameraSettings#setPreviewSize
    486          */
    487         // XXX: Despite the above documentation about locking the sizes, the API
    488         // 1 implementation doesn't currently enforce this at all, although the
    489         // Camera class warns that preview sizes shouldn't be changed while a
    490         // preview is running. Furthermore, the API 2 implementation doesn't yet
    491         // unlock the sizes when stopPreview() is invoked (see related FIXME on
    492         // the STOP_PREVIEW case in its handler; in the meantime, changing API 2
    493         // sizes would require closing and reopening the camera.
    494         public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
    495             try {
    496                 getDispatchThread().runJob(new Runnable() {
    497                     @Override
    498                     public void run() {
    499                         getCameraHandler()
    500                                 .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
    501                                 .sendToTarget();
    502                     }});
    503             } catch (final RuntimeException ex) {
    504                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    505             }
    506         }
    507 
    508         /**
    509          * Blocks until a {@link android.graphics.SurfaceTexture} has been set
    510          * for preview.
    511          *
    512          * <p>Note that, once this operation has been performed, it is no longer
    513          * possible to change the preview or photo sizes in the
    514          * {@link CameraSettings} instance for this camera, and the mutators for
    515          * these fields are allowed to ignore all further invocations.</p>
    516          *
    517          * @param surfaceTexture The {@link SurfaceTexture} for preview.
    518          *
    519          * @see CameraSettings#setPhotoSize
    520          * @see CameraSettings#setPreviewSize
    521          */
    522         public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
    523             // Don't bother to wait since camera is in bad state.
    524             if (getCameraState().isInvalid()) {
    525                 return;
    526             }
    527             final WaitDoneBundle bundle = new WaitDoneBundle();
    528             try {
    529                 getDispatchThread().runJobSync(new Runnable() {
    530                     @Override
    531                     public void run() {
    532                         getCameraHandler()
    533                                 .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
    534                                 .sendToTarget();
    535                         getCameraHandler().post(bundle.mUnlockRunnable);
    536                     }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
    537             } catch (final RuntimeException ex) {
    538                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    539             }
    540         }
    541 
    542         /**
    543          * Sets the {@link android.view.SurfaceHolder} for preview.
    544          *
    545          * @param surfaceHolder The {@link SurfaceHolder} for preview.
    546          */
    547         public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
    548             try {
    549                 getDispatchThread().runJob(new Runnable() {
    550                     @Override
    551                     public void run() {
    552                         getCameraHandler()
    553                                 .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
    554                                 .sendToTarget();
    555                     }});
    556             } catch (final RuntimeException ex) {
    557                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    558             }
    559         }
    560 
    561         /**
    562          * Starts the camera preview.
    563          */
    564         public void startPreview() {
    565             try {
    566             getDispatchThread().runJob(new Runnable() {
    567                 @Override
    568                 public void run() {
    569                     getCameraHandler()
    570                             .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();
    571                 }});
    572             } catch (final RuntimeException ex) {
    573                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    574             }
    575         }
    576 
    577         /**
    578          * Starts the camera preview and executes a callback on a handler once
    579          * the preview starts.
    580          */
    581         public void startPreviewWithCallback(final Handler h, final CameraStartPreviewCallback cb) {
    582             try {
    583             getDispatchThread().runJob(new Runnable() {
    584                 @Override
    585                 public void run() {
    586                     getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC,
    587                             CameraStartPreviewCallbackForward.getNewInstance(h, cb))
    588                                     .sendToTarget();
    589                 }});
    590             } catch (final RuntimeException ex) {
    591                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    592             }
    593         }
    594 
    595         /**
    596          * Stops the camera preview synchronously.
    597          * {@code stopPreview()} must be synchronous to ensure that the caller can
    598          * continues to release resources related to camera preview.
    599          */
    600         public void stopPreview() {
    601             // Don't bother to wait since camera is in bad state.
    602             if (getCameraState().isInvalid()) {
    603                 return;
    604             }
    605             final WaitDoneBundle bundle = new WaitDoneBundle();
    606             try {
    607                 getDispatchThread().runJobSync(new Runnable() {
    608                     @Override
    609                     public void run() {
    610                         getCameraHandler().obtainMessage(CameraActions.STOP_PREVIEW, bundle)
    611                                 .sendToTarget();
    612                     }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
    613             } catch (final RuntimeException ex) {
    614                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    615             }
    616         }
    617 
    618         /**
    619          * Sets the callback for preview data.
    620          *
    621          * @param handler    The {@link android.os.Handler} in which the callback was handled.
    622          * @param cb         The callback to be invoked when the preview data is available.
    623          * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
    624          */
    625         public abstract void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb);
    626 
    627         /**
    628          * Sets the one-time callback for preview data.
    629          *
    630          * @param handler    The {@link android.os.Handler} in which the callback was handled.
    631          * @param cb         The callback to be invoked when the preview data for
    632          *                   next frame is available.
    633          * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
    634          */
    635         public abstract void setOneShotPreviewCallback(Handler handler,
    636                                                        CameraPreviewDataCallback cb);
    637 
    638         /**
    639          * Sets the callback for preview data.
    640          *
    641          * @param handler The handler in which the callback will be invoked.
    642          * @param cb      The callback to be invoked when the preview data is available.
    643          * @see android.hardware.Camera#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)
    644          */
    645         public abstract void setPreviewDataCallbackWithBuffer(Handler handler,
    646                                                               CameraPreviewDataCallback cb);
    647 
    648         /**
    649          * Adds buffer for the preview callback.
    650          *
    651          * @param callbackBuffer The buffer allocated for the preview data.
    652          */
    653         public void addCallbackBuffer(final byte[] callbackBuffer) {
    654             try {
    655                 getDispatchThread().runJob(new Runnable() {
    656                     @Override
    657                     public void run() {
    658                         getCameraHandler()
    659                                 .obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer)
    660                                 .sendToTarget();
    661                         }
    662                     });
    663             } catch (final RuntimeException ex) {
    664                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    665             }
    666         }
    667 
    668         /**
    669          * Starts the auto-focus process. The result will be returned through the callback.
    670          *
    671          * @param handler The handler in which the callback will be invoked.
    672          * @param cb      The auto-focus callback.
    673          */
    674         public abstract void autoFocus(Handler handler, CameraAFCallback cb);
    675 
    676         /**
    677          * Cancels the auto-focus process.
    678          *
    679          * <p>This action has the highest priority and will get processed before anything
    680          * else that is pending. Moreover, any pending auto-focuses that haven't yet
    681          * began will also be ignored.</p>
    682          */
    683         public void cancelAutoFocus() {
    684              // Do not use the dispatch thread since we want to avoid a wait-cycle
    685              // between applySettingsHelper which waits until the state is not FOCUSING.
    686              // cancelAutoFocus should get executed asap, set the state back to idle.
    687             getCameraHandler().sendMessageAtFrontOfQueue(
    688                     getCameraHandler().obtainMessage(CameraActions.CANCEL_AUTO_FOCUS));
    689             getCameraHandler().sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS_FINISH);
    690         }
    691 
    692         /**
    693          * Sets the auto-focus callback
    694          *
    695          * @param handler The handler in which the callback will be invoked.
    696          * @param cb      The callback to be invoked when the preview data is available.
    697          */
    698         @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    699         public abstract void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
    700 
    701         /**
    702          * Instrument the camera to take a picture.
    703          *
    704          * @param handler   The handler in which the callback will be invoked.
    705          * @param shutter   The callback for shutter action, may be null.
    706          * @param raw       The callback for uncompressed data, may be null.
    707          * @param postview  The callback for postview image data, may be null.
    708          * @param jpeg      The callback for jpeg image data, may be null.
    709          * @see android.hardware.Camera#takePicture(
    710          *         android.hardware.Camera.ShutterCallback,
    711          *         android.hardware.Camera.PictureCallback,
    712          *         android.hardware.Camera.PictureCallback)
    713          */
    714         public abstract void takePicture(
    715                 Handler handler,
    716                 CameraShutterCallback shutter,
    717                 CameraPictureCallback raw,
    718                 CameraPictureCallback postview,
    719                 CameraPictureCallback jpeg);
    720 
    721         /**
    722          * Sets the display orientation for camera to adjust the preview and JPEG orientation.
    723          *
    724          * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
    725          *                orientation. Should be 0, 90, 180 or 270.
    726          */
    727         public void setDisplayOrientation(final int degrees) {
    728             setDisplayOrientation(degrees, true);
    729         }
    730 
    731         /**
    732          * Sets the display orientation for camera to adjust the preview&mdash;and, optionally,
    733          * JPEG&mdash;orientations.
    734          * <p>If capture rotation is not requested, future captures will be returned in the sensor's
    735          * physical rotation, which does not necessarily match the device's natural orientation.</p>
    736          *
    737          * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
    738          *                orientation. Should be 0, 90, 180 or 270.
    739          * @param capture Whether to adjust the JPEG capture orientation as well as the preview one.
    740          */
    741         public void setDisplayOrientation(final int degrees, final boolean capture) {
    742             try {
    743                 getDispatchThread().runJob(new Runnable() {
    744                     @Override
    745                     public void run() {
    746                         getCameraHandler()
    747                                 .obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees,
    748                                         capture ? 1 : 0)
    749                                 .sendToTarget();
    750                     }});
    751             } catch (final RuntimeException ex) {
    752                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    753             }
    754         }
    755 
    756         public void setJpegOrientation(final int degrees) {
    757             try {
    758                 getDispatchThread().runJob(new Runnable() {
    759                     @Override
    760                     public void run() {
    761                         getCameraHandler()
    762                                 .obtainMessage(CameraActions.SET_JPEG_ORIENTATION, degrees, 0)
    763                                 .sendToTarget();
    764                     }});
    765             } catch (final RuntimeException ex) {
    766                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    767             }
    768         }
    769 
    770         /**
    771          * Sets the listener for zoom change.
    772          *
    773          * @param listener The listener.
    774          */
    775         public abstract void setZoomChangeListener(OnZoomChangeListener listener);
    776 
    777         /**
    778          * Sets the face detection listener.
    779          *
    780          * @param handler  The handler in which the callback will be invoked.
    781          * @param callback The callback for face detection results.
    782          */
    783         public abstract void setFaceDetectionCallback(Handler handler,
    784                                                       CameraFaceDetectionCallback callback);
    785 
    786         /**
    787          * Starts the face detection.
    788          */
    789         public void startFaceDetection() {
    790             try {
    791                 getDispatchThread().runJob(new Runnable() {
    792                     @Override
    793                     public void run() {
    794                         getCameraHandler().sendEmptyMessage(CameraActions.START_FACE_DETECTION);
    795                     }});
    796             } catch (final RuntimeException ex) {
    797                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    798             }
    799         }
    800 
    801         /**
    802          * Stops the face detection.
    803          */
    804         public void stopFaceDetection() {
    805             try {
    806                 getDispatchThread().runJob(new Runnable() {
    807                     @Override
    808                     public void run() {
    809                         getCameraHandler().sendEmptyMessage(CameraActions.STOP_FACE_DETECTION);
    810                     }});
    811             } catch (final RuntimeException ex) {
    812                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    813             }
    814         }
    815 
    816         /**
    817          * Sets the camera parameters.
    818          *
    819          * @param params The camera parameters to use.
    820          */
    821         @Deprecated
    822         public abstract void setParameters(Camera.Parameters params);
    823 
    824         /**
    825          * Gets the current camera parameters synchronously. This method is
    826          * synchronous since the caller has to wait for the camera to return
    827          * the parameters. If the parameters are already cached, it returns
    828          * immediately.
    829          */
    830         @Deprecated
    831         public abstract Camera.Parameters getParameters();
    832 
    833         /**
    834          * Gets the current camera settings synchronously.
    835          * <p>This method is synchronous since the caller has to wait for the
    836          * camera to return the parameters. If the parameters are already
    837          * cached, it returns immediately.</p>
    838          */
    839         public abstract CameraSettings getSettings();
    840 
    841         /**
    842          * Default implementation of {@link #applySettings(CameraSettings)}
    843          * that is only missing the set of states it needs to wait for
    844          * before applying the settings.
    845          *
    846          * @param settings The settings to use on the device.
    847          * @param statesToAwait Bitwise OR of the required camera states.
    848          * @return Whether the settings can be applied.
    849          */
    850         protected boolean applySettingsHelper(CameraSettings settings,
    851                                               final int statesToAwait) {
    852             if (settings == null) {
    853                 Log.v(TAG, "null argument in applySettings()");
    854                 return false;
    855             }
    856             if (!getCapabilities().supports(settings)) {
    857                 Log.w(TAG, "Unsupported settings in applySettings()");
    858                 return false;
    859             }
    860 
    861             final CameraSettings copyOfSettings = settings.copy();
    862             try {
    863                 getDispatchThread().runJob(new Runnable() {
    864                     @Override
    865                     public void run() {
    866                         CameraStateHolder cameraState = getCameraState();
    867                         // Don't bother to wait since camera is in bad state.
    868                         if (cameraState.isInvalid()) {
    869                             return;
    870                         }
    871                         cameraState.waitForStates(statesToAwait);
    872                         getCameraHandler().obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings)
    873                                 .sendToTarget();
    874                     }});
    875             } catch (final RuntimeException ex) {
    876                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    877             }
    878             return true;
    879         }
    880 
    881         /**
    882          * Applies the settings to the camera device.
    883          *
    884          * <p>If the camera is either focusing or capturing; settings applications
    885          * will be (asynchronously) deferred until those operations complete.</p>
    886          *
    887          * @param settings The settings to use on the device.
    888          * @return Whether the settings can be applied.
    889          */
    890         public abstract boolean applySettings(CameraSettings settings);
    891 
    892         /**
    893          * Forces {@code CameraProxy} to update the cached version of the camera
    894          * settings regardless of the dirty bit.
    895          */
    896         public void refreshSettings() {
    897             try {
    898                 getDispatchThread().runJob(new Runnable() {
    899                     @Override
    900                     public void run() {
    901                         getCameraHandler().sendEmptyMessage(CameraActions.REFRESH_PARAMETERS);
    902                     }});
    903             } catch (final RuntimeException ex) {
    904                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    905             }
    906         }
    907 
    908         /**
    909          * Enables/Disables the camera shutter sound.
    910          *
    911          * @param enable   {@code true} to enable the shutter sound,
    912          *                 {@code false} to disable it.
    913          */
    914         public void enableShutterSound(final boolean enable) {
    915             try {
    916                 getDispatchThread().runJob(new Runnable() {
    917                     @Override
    918                     public void run() {
    919                         getCameraHandler()
    920                                 .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
    921                                 .sendToTarget();
    922                     }});
    923             } catch (final RuntimeException ex) {
    924                 getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
    925             }
    926         }
    927 
    928         /**
    929          * Dumps the current settings of the camera device.
    930          *
    931          * <p>The content varies based on the underlying camera API settings
    932          * implementation.</p>
    933          *
    934          * @return The content of the device settings represented by a string.
    935          */
    936         public abstract String dumpDeviceSettings();
    937 
    938         /**
    939          * @return The handler to which camera tasks should be posted.
    940          */
    941         public abstract Handler getCameraHandler();
    942 
    943         /**
    944          * @return The thread used on which client callbacks are served.
    945          */
    946         public abstract DispatchThread getDispatchThread();
    947 
    948         /**
    949          * @return The state machine tracking the camera API's current mode.
    950          */
    951         public abstract CameraStateHolder getCameraState();
    952     }
    953 
    954     public static class WaitDoneBundle {
    955         public final Runnable mUnlockRunnable;
    956         public final Object mWaitLock;
    957 
    958         WaitDoneBundle() {
    959             mWaitLock = new Object();
    960             mUnlockRunnable = new Runnable() {
    961                 @Override
    962                 public void run() {
    963                     synchronized (mWaitLock) {
    964                         mWaitLock.notifyAll();
    965                     }
    966                 }};
    967         }
    968 
    969         /**
    970          * Notify all synchronous waiters waiting on message completion with {@link #mWaitLock}.
    971          *
    972          * <p>This assumes that the message was sent with {@code this} as the {@code Message#obj}.
    973          * Otherwise the message is ignored.</p>
    974          */
    975         /*package*/ static void unblockSyncWaiters(Message msg) {
    976             if (msg == null) return;
    977 
    978             if (msg.obj instanceof WaitDoneBundle) {
    979                 WaitDoneBundle bundle = (WaitDoneBundle)msg.obj;
    980                 bundle.mUnlockRunnable.run();
    981             }
    982         }
    983     }
    984 }
    985