Camera.java revision a1b653d41df9a7999e1dba2a508295671ff6771d
1/*
2 * Copyright (C) 2008 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
17package android.hardware;
18
19import java.lang.ref.WeakReference;
20import java.util.HashMap;
21import java.util.StringTokenizer;
22import java.io.IOException;
23
24import android.util.Log;
25import android.view.Surface;
26import android.view.SurfaceHolder;
27import android.graphics.PixelFormat;
28import android.os.Handler;
29import android.os.Looper;
30import android.os.Message;
31
32/**
33 * The Camera class is used to connect/disconnect with the camera service,
34 * set capture settings, start/stop preview, snap a picture, and retrieve
35 * frames for encoding for video.
36 * <p>There is no default constructor for this class. Use {@link #open()} to
37 * get a Camera object.</p>
38 */
39public class Camera {
40    private static final String TAG = "Camera";
41
42    // These match the enums in frameworks/base/include/ui/Camera.h
43    private static final int CAMERA_MSG_ERROR = 0;
44    private static final int CAMERA_MSG_SHUTTER = 1;
45    private static final int CAMERA_MSG_FOCUS = 2;
46    private static final int CAMERA_MSG_ZOOM = 3;
47    private static final int CAMERA_MSG_PREVIEW_FRAME = 4;
48    private static final int CAMERA_MSG_VIDEO_FRAME = 5;
49    private static final int CAMERA_MSG_POSTVIEW_FRAME = 6;
50    private static final int CAMERA_MSG_RAW_IMAGE = 7;
51    private static final int CAMERA_MSG_COMPRESSED_IMAGE = 8;
52
53    private int mNativeContext; // accessed by native methods
54    private EventHandler mEventHandler;
55    private ShutterCallback mShutterCallback;
56    private PictureCallback mRawImageCallback;
57    private PictureCallback mJpegCallback;
58    private PreviewCallback mPreviewCallback;
59    private AutoFocusCallback mAutoFocusCallback;
60    private ErrorCallback mErrorCallback;
61    private boolean mOneShot;
62
63    /**
64     * Returns a new Camera object.
65     */
66    public static Camera open() {
67        return new Camera();
68    }
69
70    Camera() {
71        mShutterCallback = null;
72        mRawImageCallback = null;
73        mJpegCallback = null;
74        mPreviewCallback = null;
75
76        Looper looper;
77        if ((looper = Looper.myLooper()) != null) {
78            mEventHandler = new EventHandler(this, looper);
79        } else if ((looper = Looper.getMainLooper()) != null) {
80            mEventHandler = new EventHandler(this, looper);
81        } else {
82            mEventHandler = null;
83        }
84
85        native_setup(new WeakReference<Camera>(this));
86    }
87
88    protected void finalize() {
89        native_release();
90    }
91
92    private native final void native_setup(Object camera_this);
93    private native final void native_release();
94
95
96    /**
97     * Disconnects and releases the Camera object resources.
98     * <p>It is recommended that you call this as soon as you're done with the
99     * Camera object.</p>
100     */
101    public final void release() {
102        native_release();
103    }
104
105    /**
106     * Reconnect to the camera after passing it to MediaRecorder. To save
107     * setup/teardown time, a client of Camera can pass an initialized Camera
108     * object to a MediaRecorder to use for video recording. Once the
109     * MediaRecorder is done with the Camera, this method can be used to
110     * re-establish a connection with the camera hardware. NOTE: The Camera
111     * object must first be unlocked by the process that owns it before it
112     * can be connected to another proces.
113     *
114     * @throws IOException if the method fails.
115     *
116     * FIXME: Unhide after approval
117     * @hide
118     */
119    public native final void reconnect() throws IOException;
120
121    /**
122     * Lock the camera to prevent other processes from accessing it. To save
123     * setup/teardown time, a client of Camera can pass an initialized Camera
124     * object to another process. This method is used to re-lock the Camera
125     * object prevent other processes from accessing it. By default, the
126     * Camera object is locked. Locking it again from the same process will
127     * have no effect. Attempting to lock it from another process if it has
128     * not been unlocked will fail.
129     * Returns 0 if lock was successful.
130     *
131     * FIXME: Unhide after approval
132     * @hide
133     */
134    public native final int lock();
135
136    /**
137     * Unlock the camera to allow aother process to access it. To save
138     * setup/teardown time, a client of Camera can pass an initialized Camera
139     * object to another process. This method is used to unlock the Camera
140     * object before handing off the Camera object to the other process.
141
142     * Returns 0 if unlock was successful.
143     *
144     * FIXME: Unhide after approval
145     * @hide
146     */
147    public native final int unlock();
148
149    /**
150     * Sets the SurfaceHolder to be used for a picture preview. If the surface
151     * changed since the last call, the screen will blank. Nothing happens
152     * if the same surface is re-set.
153     *
154     * @param holder the SurfaceHolder upon which to place the picture preview
155     * @throws IOException if the method fails.
156     */
157    public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
158        if (holder != null) {
159            setPreviewDisplay(holder.getSurface());
160        } else {
161            setPreviewDisplay((Surface)null);
162        }
163    }
164
165    private native final void setPreviewDisplay(Surface surface);
166
167    /**
168     * Used to get a copy of each preview frame.
169     */
170    public interface PreviewCallback
171    {
172        /**
173         * The callback that delivers the preview frames.
174         *
175         * @param data The contents of the preview frame in getPreviewFormat()
176         *             format.
177         * @param camera The Camera service object.
178         */
179        void onPreviewFrame(byte[] data, Camera camera);
180    };
181
182    /**
183     * Start drawing preview frames to the surface.
184     */
185    public native final void startPreview();
186
187    /**
188     * Stop drawing preview frames to the surface.
189     */
190    public native final void stopPreview();
191
192    /**
193     * Return current preview state.
194     *
195     * FIXME: Unhide before release
196     * @hide
197     */
198    public native final boolean previewEnabled();
199
200    /**
201     * Can be called at any time to instruct the camera to use a callback for
202     * each preview frame in addition to displaying it.
203     *
204     * @param cb A callback object that receives a copy of each preview frame.
205     *           Pass null to stop receiving callbacks at any time.
206     */
207    public final void setPreviewCallback(PreviewCallback cb) {
208        mPreviewCallback = cb;
209        mOneShot = false;
210        setHasPreviewCallback(cb != null, false);
211    }
212
213    /**
214     * Installs a callback to retrieve a single preview frame, after which the
215     * callback is cleared.
216     *
217     * @param cb A callback object that receives a copy of the preview frame.
218     */
219    public final void setOneShotPreviewCallback(PreviewCallback cb) {
220        if (cb != null) {
221            mPreviewCallback = cb;
222            mOneShot = true;
223            setHasPreviewCallback(true, true);
224        }
225    }
226
227    private native final void setHasPreviewCallback(boolean installed, boolean oneshot);
228
229    private class EventHandler extends Handler
230    {
231        private Camera mCamera;
232
233        public EventHandler(Camera c, Looper looper) {
234            super(looper);
235            mCamera = c;
236        }
237
238        @Override
239        public void handleMessage(Message msg) {
240            switch(msg.what) {
241            case CAMERA_MSG_SHUTTER:
242                if (mShutterCallback != null) {
243                    mShutterCallback.onShutter();
244                }
245                return;
246
247            case CAMERA_MSG_RAW_IMAGE:
248                if (mRawImageCallback != null)
249                    mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
250                return;
251
252            case CAMERA_MSG_COMPRESSED_IMAGE:
253                if (mJpegCallback != null)
254                    mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
255                return;
256
257            case CAMERA_MSG_PREVIEW_FRAME:
258                if (mPreviewCallback != null) {
259                    mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera);
260                    if (mOneShot) {
261                        mPreviewCallback = null;
262                    }
263                }
264                return;
265
266            case CAMERA_MSG_FOCUS:
267                if (mAutoFocusCallback != null)
268                    mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
269                return;
270
271            case CAMERA_MSG_ERROR :
272                Log.e(TAG, "Error " + msg.arg1);
273                if (mErrorCallback != null)
274                    mErrorCallback.onError(msg.arg1, mCamera);
275                return;
276
277            default:
278                Log.e(TAG, "Unknown message type " + msg.what);
279                return;
280            }
281        }
282    }
283
284    private static void postEventFromNative(Object camera_ref,
285                                            int what, int arg1, int arg2, Object obj)
286    {
287        Camera c = (Camera)((WeakReference)camera_ref).get();
288        if (c == null)
289            return;
290
291        if (c.mEventHandler != null) {
292            Message m = c.mEventHandler.obtainMessage(what, arg1, arg2, obj);
293            c.mEventHandler.sendMessage(m);
294        }
295    }
296
297    /**
298     * Handles the callback for the camera auto focus.
299     */
300    public interface AutoFocusCallback
301    {
302        /**
303         * Callback for the camera auto focus.
304         *
305         * @param success true if focus was successful, false if otherwise
306         * @param camera  the Camera service object
307         */
308        void onAutoFocus(boolean success, Camera camera);
309    };
310
311    /**
312     * Starts auto-focus function and registers a callback function to
313     * run when camera is focused. Only valid after startPreview() has
314     * been called.
315     *
316     * @param cb the callback to run
317     */
318    public final void autoFocus(AutoFocusCallback cb)
319    {
320        mAutoFocusCallback = cb;
321        native_autoFocus();
322    }
323    private native final void native_autoFocus();
324
325    /**
326     * An interface which contains a callback for the shutter closing after taking a picture.
327     */
328    public interface ShutterCallback
329    {
330        /**
331         * Can be used to play a shutter sound as soon as the image has been captured, but before
332         * the data is available.
333         */
334        void onShutter();
335    }
336
337    /**
338     * Handles the callback for when a picture is taken.
339     */
340    public interface PictureCallback {
341        /**
342         * Callback for when a picture is taken.
343         *
344         * @param data   a byte array of the picture data
345         * @param camera the Camera service object
346         */
347        void onPictureTaken(byte[] data, Camera camera);
348    };
349
350    /**
351     * Triggers an asynchronous image capture. The camera service
352     * will initiate a series of callbacks to the application as the
353     * image capture progresses. The shutter callback occurs after
354     * the image is captured. This can be used to trigger a sound
355     * to let the user know that image has been captured. The raw
356     * callback occurs when the raw image data is available. The jpeg
357     * callback occurs when the compressed image is available. If the
358     * application does not need a particular callback, a null can be
359     * passed instead of a callback method.
360     *
361     * @param shutter   callback after the image is captured, may be null
362     * @param raw       callback with raw image data, may be null
363     * @param jpeg      callback with jpeg image data, may be null
364     */
365    public final void takePicture(ShutterCallback shutter, PictureCallback raw,
366            PictureCallback jpeg) {
367        mShutterCallback = shutter;
368        mRawImageCallback = raw;
369        mJpegCallback = jpeg;
370        native_takePicture();
371    }
372    private native final void native_takePicture();
373
374    // These match the enum in include/ui/Camera.h
375    /** Unspecified camerar error.  @see #ErrorCallback */
376    public static final int CAMERA_ERROR_UNKNOWN = 1;
377    /** Media server died. In this case, the application must release the
378     * Camera object and instantiate a new one. @see #ErrorCallback */
379    public static final int CAMERA_ERROR_SERVER_DIED = 100;
380
381    /**
382     * Handles the camera error callback.
383     */
384    public interface ErrorCallback
385    {
386        /**
387         * Callback for camera errors.
388         * @param error   error code:
389         * <ul>
390         * <li>{@link #CAMERA_ERROR_UNKNOWN}
391         * <li>{@link #CAMERA_ERROR_SERVER_DIED}
392         * </ul>
393         * @param camera  the Camera service object
394         */
395        void onError(int error, Camera camera);
396    };
397
398    /**
399     * Registers a callback to be invoked when an error occurs.
400     * @param cb the callback to run
401     */
402    public final void setErrorCallback(ErrorCallback cb)
403    {
404        mErrorCallback = cb;
405    }
406
407    private native final void native_setParameters(String params);
408    private native final String native_getParameters();
409
410    /**
411     * Sets the Parameters for pictures from this Camera service.
412     *
413     * @param params the Parameters to use for this Camera service
414     */
415    public void setParameters(Parameters params) {
416        native_setParameters(params.flatten());
417    }
418
419    /**
420     * Returns the picture Parameters for this Camera service.
421     */
422    public Parameters getParameters() {
423        Parameters p = new Parameters();
424        String s = native_getParameters();
425        p.unflatten(s);
426        return p;
427    }
428
429    /**
430     * Handles the picture size (dimensions).
431     */
432    public class Size {
433        /**
434         * Sets the dimensions for pictures.
435         *
436         * @param w the photo width (pixels)
437         * @param h the photo height (pixels)
438         */
439        public Size(int w, int h) {
440            width = w;
441            height = h;
442        }
443        /** width of the picture */
444        public int width;
445        /** height of the picture */
446        public int height;
447    };
448
449    /**
450     * Handles the parameters for pictures created by a Camera service.
451     */
452    public class Parameters {
453        private HashMap<String, String> mMap;
454
455        private Parameters() {
456            mMap = new HashMap<String, String>();
457        }
458
459        /**
460         * Writes the current Parameters to the log.
461         * @hide
462         * @deprecated
463         */
464        public void dump() {
465            Log.e(TAG, "dump: size=" + mMap.size());
466            for (String k : mMap.keySet()) {
467                Log.e(TAG, "dump: " + k + "=" + mMap.get(k));
468            }
469        }
470
471        /**
472         * Creates a single string with all the parameters set in
473         * this Parameters object.
474         * <p>The {@link #unflatten(String)} method does the reverse.</p>
475         *
476         * @return a String with all values from this Parameters object, in
477         *         semi-colon delimited key-value pairs
478         */
479        public String flatten() {
480            StringBuilder flattened = new StringBuilder();
481            for (String k : mMap.keySet()) {
482                flattened.append(k);
483                flattened.append("=");
484                flattened.append(mMap.get(k));
485                flattened.append(";");
486            }
487            // chop off the extra semicolon at the end
488            flattened.deleteCharAt(flattened.length()-1);
489            return flattened.toString();
490        }
491
492        /**
493         * Takes a flattened string of parameters and adds each one to
494         * this Parameters object.
495         * <p>The {@link #flatten()} method does the reverse.</p>
496         *
497         * @param flattened a String of parameters (key-value paired) that
498         *                  are semi-colon delimited
499         */
500        public void unflatten(String flattened) {
501            mMap.clear();
502
503            StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
504            while (tokenizer.hasMoreElements()) {
505                String kv = tokenizer.nextToken();
506                int pos = kv.indexOf('=');
507                if (pos == -1) {
508                    continue;
509                }
510                String k = kv.substring(0, pos);
511                String v = kv.substring(pos + 1);
512                mMap.put(k, v);
513            }
514        }
515
516        public void remove(String key) {
517            mMap.remove(key);
518        }
519
520        /**
521         * Sets a String parameter.
522         *
523         * @param key   the key name for the parameter
524         * @param value the String value of the parameter
525         */
526        public void set(String key, String value) {
527            if (key.indexOf('=') != -1 || key.indexOf(';') != -1) {
528                Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)");
529                return;
530            }
531            if (value.indexOf('=') != -1 || value.indexOf(';') != -1) {
532                Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)");
533                return;
534            }
535
536            mMap.put(key, value);
537        }
538
539        /**
540         * Sets an integer parameter.
541         *
542         * @param key   the key name for the parameter
543         * @param value the int value of the parameter
544         */
545        public void set(String key, int value) {
546            mMap.put(key, Integer.toString(value));
547        }
548
549        /**
550         * Returns the value of a String parameter.
551         *
552         * @param key the key name for the parameter
553         * @return the String value of the parameter
554         */
555        public String get(String key) {
556            return mMap.get(key);
557        }
558
559        /**
560         * Returns the value of an integer parameter.
561         *
562         * @param key the key name for the parameter
563         * @return the int value of the parameter
564         */
565        public int getInt(String key) {
566            return Integer.parseInt(mMap.get(key));
567        }
568
569        /**
570         * Sets the dimensions for preview pictures.
571         *
572         * @param width  the width of the pictures, in pixels
573         * @param height the height of the pictures, in pixels
574         */
575        public void setPreviewSize(int width, int height) {
576            String v = Integer.toString(width) + "x" + Integer.toString(height);
577            set("preview-size", v);
578        }
579
580        /**
581         * Returns the dimensions setting for preview pictures.
582         *
583         * @return a Size object with the height and width setting
584         *          for the preview picture
585         */
586        public Size getPreviewSize() {
587            String pair = get("preview-size");
588            if (pair == null)
589                return null;
590            String[] dims = pair.split("x");
591            if (dims.length != 2)
592                return null;
593
594            return new Size(Integer.parseInt(dims[0]),
595                            Integer.parseInt(dims[1]));
596
597        }
598
599        /**
600         * Sets the dimensions for EXIF thumbnails.
601         *
602         * @param width  the width of the thumbnail, in pixels
603         * @param height the height of the thumbnail, in pixels
604         *
605         * FIXME: unhide before release
606         * @hide
607         */
608        public void setThumbnailSize(int width, int height) {
609            set("jpeg-thumbnail-width", width);
610            set("jpeg-thumbnail-height", height);
611        }
612
613        /**
614         * Returns the dimensions for EXIF thumbnail
615         *
616         * @return a Size object with the height and width setting
617         *          for the EXIF thumbnails
618         *
619         * FIXME: unhide before release
620         * @hide
621         */
622        public Size getThumbnailSize() {
623            return new Size(getInt("jpeg-thumbnail-width"),
624                            getInt("jpeg-thumbnail-height"));
625        }
626
627        /**
628         * Sets the quality of the EXIF thumbnail
629         *
630         * @param quality the JPEG quality of the EXIT thumbnail
631         *
632         * FIXME: unhide before release
633         * @hide
634         */
635        public void setThumbnailQuality(int quality) {
636            set("jpeg-thumbnail-quality", quality);
637        }
638
639        /**
640         * Returns the quality setting for the EXIF thumbnail
641         *
642         * @return the JPEG quality setting of the EXIF thumbnail
643         *
644         * FIXME: unhide before release
645         * @hide
646         */
647        public int getThumbnailQuality() {
648            return getInt("jpeg-thumbnail-quality");
649        }
650
651        /**
652         * Sets the rate at which preview frames are received.
653         *
654         * @param fps the frame rate (frames per second)
655         */
656        public void setPreviewFrameRate(int fps) {
657            set("preview-frame-rate", fps);
658        }
659
660        /**
661         * Returns the setting for the rate at which preview frames
662         * are received.
663         *
664         * @return the frame rate setting (frames per second)
665         */
666        public int getPreviewFrameRate() {
667            return getInt("preview-frame-rate");
668        }
669
670        /**
671         * Sets the image format for preview pictures.
672         *
673         * @param pixel_format the desired preview picture format
674         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
675         *                      <var>PixelFormat.RGB_565</var>, or
676         *                      <var>PixelFormat.JPEG</var>)
677         * @see android.graphics.PixelFormat
678         */
679        public void setPreviewFormat(int pixel_format) {
680            String s = cameraFormatForPixelFormat(pixel_format);
681            if (s == null) {
682                throw new IllegalArgumentException();
683            }
684
685            set("preview-format", s);
686        }
687
688        /**
689         * Returns the image format for preview pictures.
690         *
691         * @return the PixelFormat int representing the preview picture format
692         */
693        public int getPreviewFormat() {
694            return pixelFormatForCameraFormat(get("preview-format"));
695        }
696
697        /**
698         * Sets the dimensions for pictures.
699         *
700         * @param width  the width for pictures, in pixels
701         * @param height the height for pictures, in pixels
702         */
703        public void setPictureSize(int width, int height) {
704            String v = Integer.toString(width) + "x" + Integer.toString(height);
705            set("picture-size", v);
706        }
707
708        /**
709         * Returns the dimension setting for pictures.
710         *
711         * @return a Size object with the height and width setting
712         *          for pictures
713         */
714        public Size getPictureSize() {
715            String pair = get("picture-size");
716            if (pair == null)
717                return null;
718            String[] dims = pair.split("x");
719            if (dims.length != 2)
720                return null;
721
722            return new Size(Integer.parseInt(dims[0]),
723                            Integer.parseInt(dims[1]));
724
725        }
726
727        /**
728         * Sets the image format for pictures.
729         *
730         * @param pixel_format the desired picture format
731         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
732         *                      <var>PixelFormat.RGB_565</var>, or
733         *                      <var>PixelFormat.JPEG</var>)
734         * @see android.graphics.PixelFormat
735         */
736        public void setPictureFormat(int pixel_format) {
737            String s = cameraFormatForPixelFormat(pixel_format);
738            if (s == null) {
739                throw new IllegalArgumentException();
740            }
741
742            set("picture-format", s);
743        }
744
745        /**
746         * Returns the image format for pictures.
747         *
748         * @return the PixelFormat int representing the picture format
749         */
750        public int getPictureFormat() {
751            return pixelFormatForCameraFormat(get("picture-format"));
752        }
753
754        private String cameraFormatForPixelFormat(int pixel_format) {
755            switch(pixel_format) {
756            case PixelFormat.YCbCr_422_SP: return "yuv422sp";
757            case PixelFormat.YCbCr_420_SP: return "yuv420sp";
758            case PixelFormat.RGB_565:      return "rgb565";
759            case PixelFormat.JPEG:         return "jpeg";
760            default:                       return null;
761            }
762        }
763
764        private int pixelFormatForCameraFormat(String format) {
765            if (format == null)
766                return PixelFormat.UNKNOWN;
767
768            if (format.equals("yuv422sp"))
769                return PixelFormat.YCbCr_422_SP;
770
771            if (format.equals("yuv420sp"))
772                return PixelFormat.YCbCr_420_SP;
773
774            if (format.equals("rgb565"))
775                return PixelFormat.RGB_565;
776
777            if (format.equals("jpeg"))
778                return PixelFormat.JPEG;
779
780            return PixelFormat.UNKNOWN;
781        }
782
783    };
784}
785
786
787