All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.ex.camera2.portability.CameraAgent Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ex.camera2.portability;

import android.annotation.TargetApi;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.OnZoomChangeListener;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.SurfaceHolder;

import com.android.ex.camera2.portability.debug.Log;

/**
 * An interface which provides possible camera device operations.
 *
 * The client should call {@code CameraAgent.openCamera} to get an instance
 * of {@link CameraAgent.CameraProxy} to control the camera. Classes
 * implementing this interface should have its own one unique {@code Thread}
 * other than the main thread for camera operations. Camera device callbacks
 * are wrapped since the client should not deal with
 * {@code android.hardware.Camera} directly.
 *
 * TODO: provide callback interfaces for:
 * {@code android.hardware.Camera.ErrorCallback},
 * {@code android.hardware.Camera.OnZoomChangeListener}, and
 */
public abstract class CameraAgent {
    public static final long CAMERA_OPERATION_TIMEOUT_MS = 3500;

    private static final Log.Tag TAG = new Log.Tag("CamAgnt");

    public static class CameraStartPreviewCallbackForward
            implements CameraStartPreviewCallback {
        private final Handler mHandler;
        private final CameraStartPreviewCallback mCallback;

        public static CameraStartPreviewCallbackForward getNewInstance(
                Handler handler, CameraStartPreviewCallback cb) {
            if (handler == null || cb == null) {
                return null;
            }
            return new CameraStartPreviewCallbackForward(handler, cb);
        }

        private CameraStartPreviewCallbackForward(Handler h,
                CameraStartPreviewCallback cb) {
            mHandler = h;
            mCallback = cb;
        }

        @Override
        public void onPreviewStarted() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onPreviewStarted();
                }});
        }
    }

    /**
     * A callback helps to invoke the original callback on another
     * {@link android.os.Handler}.
     */
    public static class CameraOpenCallbackForward implements CameraOpenCallback {
        private final Handler mHandler;
        private final CameraOpenCallback mCallback;

        /**
         * Returns a new instance of {@link FaceDetectionCallbackForward}.
         *
         * @param handler The handler in which the callback will be invoked in.
         * @param cb The callback to be invoked.
         * @return The instance of the {@link FaceDetectionCallbackForward}, or
         *         null if any parameter is null.
         */
        public static CameraOpenCallbackForward getNewInstance(
                Handler handler, CameraOpenCallback cb) {
            if (handler == null || cb == null) {
                return null;
            }
            return new CameraOpenCallbackForward(handler, cb);
        }

        private CameraOpenCallbackForward(Handler h, CameraOpenCallback cb) {
            // Given that we are using the main thread handler, we can create it
            // here instead of holding onto the PhotoModule objects. In this
            // way, we can avoid memory leak.
            mHandler = new Handler(Looper.getMainLooper());
            mCallback = cb;
        }

        @Override
        public void onCameraOpened(final CameraProxy camera) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onCameraOpened(camera);
                }});
        }

        @Override
        public void onCameraDisabled(final int cameraId) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onCameraDisabled(cameraId);
                }});
        }

        @Override
        public void onDeviceOpenFailure(final int cameraId, final String info) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onDeviceOpenFailure(cameraId, info);
                }});
        }

        @Override
        public void onDeviceOpenedAlready(final int cameraId, final String info) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onDeviceOpenedAlready(cameraId, info);
                }});
        }

        @Override
        public void onReconnectionFailure(final CameraAgent mgr, final String info) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onReconnectionFailure(mgr, info);
                }});
        }
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.ErrorCallback}
     */
    public static interface CameraErrorCallback {
        public void onError(int error, CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.AutoFocusCallback}.
     */
    public static interface CameraAFCallback {
        public void onAutoFocus(boolean focused, CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.AutoFocusMoveCallback}.
     */
    public static interface CameraAFMoveCallback {
        public void onAutoFocusMoving(boolean moving, CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.ShutterCallback}.
     */
    public static interface CameraShutterCallback {
        public void onShutter(CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.PictureCallback}.
     */
    public static interface CameraPictureCallback {
        public void onPictureTaken(byte[] data, CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.PreviewCallback}.
     */
    public static interface CameraPreviewDataCallback {
        public void onPreviewFrame(byte[] data, CameraProxy camera);
    }

    /**
     * An interface which wraps
     * {@link android.hardware.Camera.FaceDetectionListener}.
     */
    public static interface CameraFaceDetectionCallback {
        /**
         * Callback for face detection.
         *
         * @param faces   Recognized face in the preview.
         * @param camera  The camera which the preview image comes from.
         */
        public void onFaceDetection(Camera.Face[] faces, CameraProxy camera);
    }

    /**
     * An interface to be called when the camera preview has started.
     */
    public static interface CameraStartPreviewCallback {
        /**
         * Callback when the preview starts.
         */
        public void onPreviewStarted();
    }

    /**
     * An interface to be called for any events when opening or closing the
     * camera device. This error callback is different from the one defined
     * in the framework, {@link android.hardware.Camera.ErrorCallback}, which
     * is used after the camera is opened.
     */
    public static interface CameraOpenCallback {
        /**
         * Callback when camera open succeeds.
         */
        public void onCameraOpened(CameraProxy camera);

        /**
         * Callback when {@link com.android.camera.CameraDisabledException} is
         * caught.
         *
         * @param cameraId The disabled camera.
         */
        public void onCameraDisabled(int cameraId);

        /**
         * Callback when {@link com.android.camera.CameraHardwareException} is
         * caught.
         *
         * @param cameraId The camera with the hardware failure.
         * @param info The extra info regarding this failure.
         */
        public void onDeviceOpenFailure(int cameraId, String info);

        /**
         * Callback when trying to open the camera which is already opened.
         *
         * @param cameraId The camera which is causing the open error.
         */
        public void onDeviceOpenedAlready(int cameraId, String info);

        /**
         * Callback when {@link java.io.IOException} is caught during
         * {@link android.hardware.Camera#reconnect()}.
         *
         * @param mgr The {@link CameraAgent}
         *            with the reconnect failure.
         */
        public void onReconnectionFailure(CameraAgent mgr, String info);
    }

    /**
     * Opens the camera of the specified ID asynchronously. The camera device
     * will be opened in the camera handler thread and will be returned through
     * the {@link CameraAgent.CameraOpenCallback#
     * onCameraOpened(com.android.camera.cameradevice.CameraAgent.CameraProxy)}.
     *
     * @param handler The {@link android.os.Handler} in which the callback
     *                was handled.
     * @param callback The callback for the result.
     * @param cameraId The camera ID to open.
     */
    public void openCamera(final Handler handler, final int cameraId,
                           final CameraOpenCallback callback) {
        try {
            getDispatchThread().runJob(new Runnable() {
                @Override
                public void run() {
                    getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
                            CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
                }
            });
        } catch (final RuntimeException ex) {
            getCameraExceptionHandler().onDispatchThreadException(ex);
        }
    }

    /**
     * Closes the camera device.
     *
     * @param camera The camera to close. {@code null} means all.
     * @param synced Whether this call should be synchronous.
     */
    public void closeCamera(CameraProxy camera, boolean synced) {
        try {
            if (synced) {
                // Don't bother to wait since camera is in bad state.
                if (getCameraState().isInvalid()) {
                    return;
                }
                final WaitDoneBundle bundle = new WaitDoneBundle();

                getDispatchThread().runJobSync(new Runnable() {
                    @Override
                    public void run() {
                        getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
                        getCameraHandler().post(bundle.mUnlockRunnable);
                    }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
            } else {
                getDispatchThread().runJob(new Runnable() {
                    @Override
                    public void run() {
                        getCameraHandler().removeCallbacksAndMessages(null);
                        getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
                    }});
            }
        } catch (final RuntimeException ex) {
            getCameraExceptionHandler().onDispatchThreadException(ex);
        }
    }

    /**
     * Sets a callback for handling camera api runtime exceptions on
     * a handler.
     */
    public abstract void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler);

    /**
     * Recycles the resources used by this instance. CameraAgent will be in
     * an unusable state after calling this.
     */
    public abstract void recycle();

    /**
     * @return The camera devices info.
     */
    public abstract CameraDeviceInfo getCameraDeviceInfo();

    /**
     * @return The handler to which camera tasks should be posted.
     */
    protected abstract Handler getCameraHandler();

    /**
     * @return The thread used on which client callbacks are served.
     */
    protected abstract DispatchThread getDispatchThread();

    /**
     * @return The state machine tracking the camera API's current status.
     */
    protected abstract CameraStateHolder getCameraState();

    /**
     * @return The exception handler.
     */
    protected abstract CameraExceptionHandler getCameraExceptionHandler();

    /**
     * An interface that takes camera operation requests and post messages to the
     * camera handler thread. All camera operations made through this interface is
     * asynchronous by default except those mentioned specifically.
     */
    public abstract static class CameraProxy {

        /**
         * Returns the underlying {@link android.hardware.Camera} object used
         * by this proxy. This method should only be used when handing the
         * camera device over to {@link android.media.MediaRecorder} for
         * recording.
         */
        @Deprecated
        public abstract android.hardware.Camera getCamera();

        /**
         * @return The camera ID associated to by this
         * {@link CameraAgent.CameraProxy}.
         */
        public abstract int getCameraId();

        /**
         * @return The camera characteristics.
         */
        public abstract CameraDeviceInfo.Characteristics getCharacteristics();

        /**
         * @return The camera capabilities.
         */
        public abstract CameraCapabilities getCapabilities();

        /**
         * @return The camera agent which creates this proxy.
         */
        public abstract CameraAgent getAgent();

        /**
         * Reconnects to the camera device. On success, the camera device will
         * be returned through {@link CameraAgent
         * .CameraOpenCallback#onCameraOpened(com.android.camera.cameradevice.CameraAgent
         * .CameraProxy)}.
         * @see android.hardware.Camera#reconnect()
         *
         * @param handler The {@link android.os.Handler} in which the callback
         *                was handled.
         * @param cb The callback when any error happens.
         */
        public void reconnect(final Handler handler, final CameraOpenCallback cb) {
            try {
                getDispatchThread().runJob(new Runnable() {
                    @Override
                    public void run() {
                        getCameraHandler().obtainMessage(CameraActions.RECONNECT, getCameraId(), 0,
                                CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
                    }});
            } catch (final RuntimeException ex) {
                getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
            }
        }

        /**
         * Unlocks the camera device.
         *
         * @see android.hardware.Camera#unlock()
         */
        public void unlock() {
            // Don't bother to wait since camera is in bad state.
            if (getCameraState().isInvalid()) {
                return;
            }
            final WaitDoneBundle bundle = new WaitDoneBundle();
            try {
                getDispatchThread().runJobSync(new Runnable() {
                    @Override
                    public void run() {
                        getCameraHandler().sendEmptyMessage(CameraActions.UNLOCK);
                        getCameraHandler().post(bundle.mUnlockRunnable);
                    }
                }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
            } catch (final RuntimeException ex) {
                getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
            }
        }

        /**
         * Locks the camera device.
         * @see android.hardware.Camera#lock()
         */
        public void lock() {
            try {
                getDispatchThread().runJob(new Runnable() {
                    @Override
                    public void run() {
                        getCameraHandler().sendEmptyMessage(CameraActions.LOCK);
                    }});
            } catch (final RuntimeException ex) {
                getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);
            }
        }

        /**
         * Sets the {@link android.graphics.SurfaceTexture} for preview.
         *
         * 

Note that, once this operation has been performed, it is no longer * possible to change the preview or photo sizes in the * {@link CameraSettings} instance for this camera, and the mutators for * these fields are allowed to ignore all further invocations until the * preview is stopped with {@link #stopPreview}.

* * @param surfaceTexture The {@link SurfaceTexture} for preview. * * @see CameraSettings#setPhotoSize * @see CameraSettings#setPreviewSize */ // XXX: Despite the above documentation about locking the sizes, the API // 1 implementation doesn't currently enforce this at all, although the // Camera class warns that preview sizes shouldn't be changed while a // preview is running. Furthermore, the API 2 implementation doesn't yet // unlock the sizes when stopPreview() is invoked (see related FIXME on // the STOP_PREVIEW case in its handler; in the meantime, changing API 2 // sizes would require closing and reopening the camera. public void setPreviewTexture(final SurfaceTexture surfaceTexture) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Blocks until a {@link android.graphics.SurfaceTexture} has been set * for preview. * *

Note that, once this operation has been performed, it is no longer * possible to change the preview or photo sizes in the * {@link CameraSettings} instance for this camera, and the mutators for * these fields are allowed to ignore all further invocations.

* * @param surfaceTexture The {@link SurfaceTexture} for preview. * * @see CameraSettings#setPhotoSize * @see CameraSettings#setPreviewSize */ public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) { // Don't bother to wait since camera is in bad state. if (getCameraState().isInvalid()) { return; } final WaitDoneBundle bundle = new WaitDoneBundle(); try { getDispatchThread().runJobSync(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture) .sendToTarget(); getCameraHandler().post(bundle.mUnlockRunnable); }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture"); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Sets the {@link android.view.SurfaceHolder} for preview. * * @param surfaceHolder The {@link SurfaceHolder} for preview. */ public void setPreviewDisplay(final SurfaceHolder surfaceHolder) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Starts the camera preview. */ public void startPreview() { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Starts the camera preview and executes a callback on a handler once * the preview starts. */ public void startPreviewWithCallback(final Handler h, final CameraStartPreviewCallback cb) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC, CameraStartPreviewCallbackForward.getNewInstance(h, cb)) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Stops the camera preview synchronously. * {@code stopPreview()} must be synchronous to ensure that the caller can * continues to release resources related to camera preview. */ public void stopPreview() { // Don't bother to wait since camera is in bad state. if (getCameraState().isInvalid()) { return; } final WaitDoneBundle bundle = new WaitDoneBundle(); try { getDispatchThread().runJobSync(new Runnable() { @Override public void run() { getCameraHandler().obtainMessage(CameraActions.STOP_PREVIEW, bundle) .sendToTarget(); }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview"); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Sets the callback for preview data. * * @param handler The {@link android.os.Handler} in which the callback was handled. * @param cb The callback to be invoked when the preview data is available. * @see android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback) */ public abstract void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb); /** * Sets the one-time callback for preview data. * * @param handler The {@link android.os.Handler} in which the callback was handled. * @param cb The callback to be invoked when the preview data for * next frame is available. * @see android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback) */ public abstract void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb); /** * Sets the callback for preview data. * * @param handler The handler in which the callback will be invoked. * @param cb The callback to be invoked when the preview data is available. * @see android.hardware.Camera#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback) */ public abstract void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb); /** * Adds buffer for the preview callback. * * @param callbackBuffer The buffer allocated for the preview data. */ public void addCallbackBuffer(final byte[] callbackBuffer) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer) .sendToTarget(); } }); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Starts the auto-focus process. The result will be returned through the callback. * * @param handler The handler in which the callback will be invoked. * @param cb The auto-focus callback. */ public abstract void autoFocus(Handler handler, CameraAFCallback cb); /** * Cancels the auto-focus process. * *

This action has the highest priority and will get processed before anything * else that is pending. Moreover, any pending auto-focuses that haven't yet * began will also be ignored.

*/ public void cancelAutoFocus() { // Do not use the dispatch thread since we want to avoid a wait-cycle // between applySettingsHelper which waits until the state is not FOCUSING. // cancelAutoFocus should get executed asap, set the state back to idle. getCameraHandler().sendMessageAtFrontOfQueue( getCameraHandler().obtainMessage(CameraActions.CANCEL_AUTO_FOCUS)); getCameraHandler().sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS_FINISH); } /** * Sets the auto-focus callback * * @param handler The handler in which the callback will be invoked. * @param cb The callback to be invoked when the preview data is available. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public abstract void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb); /** * Instrument the camera to take a picture. * * @param handler The handler in which the callback will be invoked. * @param shutter The callback for shutter action, may be null. * @param raw The callback for uncompressed data, may be null. * @param postview The callback for postview image data, may be null. * @param jpeg The callback for jpeg image data, may be null. * @see android.hardware.Camera#takePicture( * android.hardware.Camera.ShutterCallback, * android.hardware.Camera.PictureCallback, * android.hardware.Camera.PictureCallback) */ public abstract void takePicture( Handler handler, CameraShutterCallback shutter, CameraPictureCallback raw, CameraPictureCallback postview, CameraPictureCallback jpeg); /** * Sets the display orientation for camera to adjust the preview and JPEG orientation. * * @param degrees The counterclockwise rotation in degrees, relative to the device's natural * orientation. Should be 0, 90, 180 or 270. */ public void setDisplayOrientation(final int degrees) { setDisplayOrientation(degrees, true); } /** * Sets the display orientation for camera to adjust the preview—and, optionally, * JPEG—orientations. *

If capture rotation is not requested, future captures will be returned in the sensor's * physical rotation, which does not necessarily match the device's natural orientation.

* * @param degrees The counterclockwise rotation in degrees, relative to the device's natural * orientation. Should be 0, 90, 180 or 270. * @param capture Whether to adjust the JPEG capture orientation as well as the preview one. */ public void setDisplayOrientation(final int degrees, final boolean capture) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees, capture ? 1 : 0) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } public void setJpegOrientation(final int degrees) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.SET_JPEG_ORIENTATION, degrees, 0) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Sets the listener for zoom change. * * @param listener The listener. */ public abstract void setZoomChangeListener(OnZoomChangeListener listener); /** * Sets the face detection listener. * * @param handler The handler in which the callback will be invoked. * @param callback The callback for face detection results. */ public abstract void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback); /** * Starts the face detection. */ public void startFaceDetection() { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler().sendEmptyMessage(CameraActions.START_FACE_DETECTION); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Stops the face detection. */ public void stopFaceDetection() { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler().sendEmptyMessage(CameraActions.STOP_FACE_DETECTION); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Sets the camera parameters. * * @param params The camera parameters to use. */ @Deprecated public abstract void setParameters(Camera.Parameters params); /** * Gets the current camera parameters synchronously. This method is * synchronous since the caller has to wait for the camera to return * the parameters. If the parameters are already cached, it returns * immediately. */ @Deprecated public abstract Camera.Parameters getParameters(); /** * Gets the current camera settings synchronously. *

This method is synchronous since the caller has to wait for the * camera to return the parameters. If the parameters are already * cached, it returns immediately.

*/ public abstract CameraSettings getSettings(); /** * Default implementation of {@link #applySettings(CameraSettings)} * that is only missing the set of states it needs to wait for * before applying the settings. * * @param settings The settings to use on the device. * @param statesToAwait Bitwise OR of the required camera states. * @return Whether the settings can be applied. */ protected boolean applySettingsHelper(CameraSettings settings, final int statesToAwait) { if (settings == null) { Log.v(TAG, "null argument in applySettings()"); return false; } if (!getCapabilities().supports(settings)) { Log.w(TAG, "Unsupported settings in applySettings()"); return false; } final CameraSettings copyOfSettings = settings.copy(); try { getDispatchThread().runJob(new Runnable() { @Override public void run() { CameraStateHolder cameraState = getCameraState(); // Don't bother to wait since camera is in bad state. if (cameraState.isInvalid()) { return; } cameraState.waitForStates(statesToAwait); getCameraHandler().obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } return true; } /** * Applies the settings to the camera device. * *

If the camera is either focusing or capturing; settings applications * will be (asynchronously) deferred until those operations complete.

* * @param settings The settings to use on the device. * @return Whether the settings can be applied. */ public abstract boolean applySettings(CameraSettings settings); /** * Forces {@code CameraProxy} to update the cached version of the camera * settings regardless of the dirty bit. */ public void refreshSettings() { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler().sendEmptyMessage(CameraActions.REFRESH_PARAMETERS); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Enables/Disables the camera shutter sound. * * @param enable {@code true} to enable the shutter sound, * {@code false} to disable it. */ public void enableShutterSound(final boolean enable) { try { getDispatchThread().runJob(new Runnable() { @Override public void run() { getCameraHandler() .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0) .sendToTarget(); }}); } catch (final RuntimeException ex) { getAgent().getCameraExceptionHandler().onDispatchThreadException(ex); } } /** * Dumps the current settings of the camera device. * *

The content varies based on the underlying camera API settings * implementation.

* * @return The content of the device settings represented by a string. */ public abstract String dumpDeviceSettings(); /** * @return The handler to which camera tasks should be posted. */ public abstract Handler getCameraHandler(); /** * @return The thread used on which client callbacks are served. */ public abstract DispatchThread getDispatchThread(); /** * @return The state machine tracking the camera API's current mode. */ public abstract CameraStateHolder getCameraState(); } public static class WaitDoneBundle { public final Runnable mUnlockRunnable; public final Object mWaitLock; WaitDoneBundle() { mWaitLock = new Object(); mUnlockRunnable = new Runnable() { @Override public void run() { synchronized (mWaitLock) { mWaitLock.notifyAll(); } }}; } /** * Notify all synchronous waiters waiting on message completion with {@link #mWaitLock}. * *

This assumes that the message was sent with {@code this} as the {@code Message#obj}. * Otherwise the message is ignored.

*/ /*package*/ static void unblockSyncWaiters(Message msg) { if (msg == null) return; if (msg.obj instanceof WaitDoneBundle) { WaitDoneBundle bundle = (WaitDoneBundle)msg.obj; bundle.mUnlockRunnable.run(); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy