Camera.java revision c62f9bd13327937aa2d2f20b44215397120634c1
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        setPreviewDisplay(holder.getSurface());
159    }
160
161    private native final void setPreviewDisplay(Surface surface);
162
163    /**
164     * Used to get a copy of each preview frame.
165     */
166    public interface PreviewCallback
167    {
168        /**
169         * The callback that delivers the preview frames.
170         *
171         * @param data The contents of the preview frame in getPreviewFormat()
172         *             format.
173         * @param camera The Camera service object.
174         */
175        void onPreviewFrame(byte[] data, Camera camera);
176    };
177
178    /**
179     * Start drawing preview frames to the surface.
180     */
181    public native final void startPreview();
182
183    /**
184     * Stop drawing preview frames to the surface.
185     */
186    public native final void stopPreview();
187
188    /**
189     * Return current preview state.
190     *
191     * FIXME: Unhide before release
192     * @hide
193     */
194    public native final boolean previewEnabled();
195
196    /**
197     * Can be called at any time to instruct the camera to use a callback for
198     * each preview frame in addition to displaying it.
199     *
200     * @param cb A callback object that receives a copy of each preview frame.
201     *           Pass null to stop receiving callbacks at any time.
202     */
203    public final void setPreviewCallback(PreviewCallback cb) {
204        mPreviewCallback = cb;
205        mOneShot = false;
206        setHasPreviewCallback(cb != null, false);
207    }
208
209    /**
210     * Installs a callback to retrieve a single preview frame, after which the
211     * callback is cleared.
212     *
213     * @param cb A callback object that receives a copy of the preview frame.
214     */
215    public final void setOneShotPreviewCallback(PreviewCallback cb) {
216        if (cb != null) {
217            mPreviewCallback = cb;
218            mOneShot = true;
219            setHasPreviewCallback(true, true);
220        }
221    }
222
223    private native final void setHasPreviewCallback(boolean installed, boolean oneshot);
224
225    private class EventHandler extends Handler
226    {
227        private Camera mCamera;
228
229        public EventHandler(Camera c, Looper looper) {
230            super(looper);
231            mCamera = c;
232        }
233
234        @Override
235        public void handleMessage(Message msg) {
236            switch(msg.what) {
237            case CAMERA_MSG_SHUTTER:
238                if (mShutterCallback != null) {
239                    mShutterCallback.onShutter();
240                }
241                return;
242
243            case CAMERA_MSG_RAW_IMAGE:
244                if (mRawImageCallback != null)
245                    mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
246                return;
247
248            case CAMERA_MSG_COMPRESSED_IMAGE:
249                if (mJpegCallback != null)
250                    mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
251                return;
252
253            case CAMERA_MSG_PREVIEW_FRAME:
254                if (mPreviewCallback != null) {
255                    mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera);
256                    if (mOneShot) {
257                        mPreviewCallback = null;
258                    }
259                }
260                return;
261
262            case CAMERA_MSG_FOCUS:
263                if (mAutoFocusCallback != null)
264                    mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
265                return;
266
267            case CAMERA_MSG_ERROR :
268                Log.e(TAG, "Error " + msg.arg1);
269                if (mErrorCallback != null)
270                    mErrorCallback.onError(msg.arg1, mCamera);
271                return;
272
273            default:
274                Log.e(TAG, "Unknown message type " + msg.what);
275                return;
276            }
277        }
278    }
279
280    private static void postEventFromNative(Object camera_ref,
281                                            int what, int arg1, int arg2, Object obj)
282    {
283        Camera c = (Camera)((WeakReference)camera_ref).get();
284        if (c == null)
285            return;
286
287        if (c.mEventHandler != null) {
288            Message m = c.mEventHandler.obtainMessage(what, arg1, arg2, obj);
289            c.mEventHandler.sendMessage(m);
290        }
291    }
292
293    /**
294     * Handles the callback for the camera auto focus.
295     */
296    public interface AutoFocusCallback
297    {
298        /**
299         * Callback for the camera auto focus.
300         *
301         * @param success true if focus was successful, false if otherwise
302         * @param camera  the Camera service object
303         */
304        void onAutoFocus(boolean success, Camera camera);
305    };
306
307    /**
308     * Starts auto-focus function and registers a callback function to
309     * run when camera is focused. Only valid after startPreview() has
310     * been called.
311     *
312     * @param cb the callback to run
313     */
314    public final void autoFocus(AutoFocusCallback cb)
315    {
316        mAutoFocusCallback = cb;
317        native_autoFocus();
318    }
319    private native final void native_autoFocus();
320
321    /**
322     * An interface which contains a callback for the shutter closing after taking a picture.
323     */
324    public interface ShutterCallback
325    {
326        /**
327         * Can be used to play a shutter sound as soon as the image has been captured, but before
328         * the data is available.
329         */
330        void onShutter();
331    }
332
333    /**
334     * Handles the callback for when a picture is taken.
335     */
336    public interface PictureCallback {
337        /**
338         * Callback for when a picture is taken.
339         *
340         * @param data   a byte array of the picture data
341         * @param camera the Camera service object
342         */
343        void onPictureTaken(byte[] data, Camera camera);
344    };
345
346    /**
347     * Triggers an asynchronous image capture. The camera service
348     * will initiate a series of callbacks to the application as the
349     * image capture progresses. The shutter callback occurs after
350     * the image is captured. This can be used to trigger a sound
351     * to let the user know that image has been captured. The raw
352     * callback occurs when the raw image data is available. The jpeg
353     * callback occurs when the compressed image is available. If the
354     * application does not need a particular callback, a null can be
355     * passed instead of a callback method.
356     *
357     * @param shutter   callback after the image is captured, may be null
358     * @param raw       callback with raw image data, may be null
359     * @param jpeg      callback with jpeg image data, may be null
360     */
361    public final void takePicture(ShutterCallback shutter, PictureCallback raw,
362            PictureCallback jpeg) {
363        mShutterCallback = shutter;
364        mRawImageCallback = raw;
365        mJpegCallback = jpeg;
366        native_takePicture();
367    }
368    private native final void native_takePicture();
369
370    // These match the enum in libs/android_runtime/android_hardware_Camera.cpp
371    /** Unspecified camerar error.  @see #ErrorCallback */
372    public static final int CAMERA_ERROR_UNKNOWN = 1;
373    /** Media server died. In this case, the application must release the
374     * Camera object and instantiate a new one. @see #ErrorCallback */
375    public static final int CAMERA_ERROR_SERVER_DIED = 100;
376
377    /**
378     * Handles the camera error callback.
379     */
380    public interface ErrorCallback
381    {
382        /**
383         * Callback for camera errors.
384         * @param error   error code:
385         * <ul>
386         * <li>{@link #CAMERA_ERROR_UNKNOWN}
387         * <li>{@link #CAMERA_ERROR_SERVER_DIED}
388         * </ul>
389         * @param camera  the Camera service object
390         */
391        void onError(int error, Camera camera);
392    };
393
394    /**
395     * Registers a callback to be invoked when an error occurs.
396     * @param cb the callback to run
397     */
398    public final void setErrorCallback(ErrorCallback cb)
399    {
400        mErrorCallback = cb;
401    }
402
403    private native final void native_setParameters(String params);
404    private native final String native_getParameters();
405
406    /**
407     * Sets the Parameters for pictures from this Camera service.
408     *
409     * @param params the Parameters to use for this Camera service
410     */
411    public void setParameters(Parameters params) {
412        native_setParameters(params.flatten());
413    }
414
415    /**
416     * Returns the picture Parameters for this Camera service.
417     */
418    public Parameters getParameters() {
419        Parameters p = new Parameters();
420        String s = native_getParameters();
421        p.unflatten(s);
422        return p;
423    }
424
425    /**
426     * Handles the picture size (dimensions).
427     */
428    public class Size {
429        /**
430         * Sets the dimensions for pictures.
431         *
432         * @param w the photo width (pixels)
433         * @param h the photo height (pixels)
434         */
435        public Size(int w, int h) {
436            width = w;
437            height = h;
438        }
439        /** width of the picture */
440        public int width;
441        /** height of the picture */
442        public int height;
443    };
444
445    /**
446     * Handles the parameters for pictures created by a Camera service.
447     */
448    public class Parameters {
449        private HashMap<String, String> mMap;
450
451        private Parameters() {
452            mMap = new HashMap<String, String>();
453        }
454
455        /**
456         * Writes the current Parameters to the log.
457         * @hide
458         * @deprecated
459         */
460        public void dump() {
461            Log.e(TAG, "dump: size=" + mMap.size());
462            for (String k : mMap.keySet()) {
463                Log.e(TAG, "dump: " + k + "=" + mMap.get(k));
464            }
465        }
466
467        /**
468         * Creates a single string with all the parameters set in
469         * this Parameters object.
470         * <p>The {@link #unflatten(String)} method does the reverse.</p>
471         *
472         * @return a String with all values from this Parameters object, in
473         *         semi-colon delimited key-value pairs
474         */
475        public String flatten() {
476            StringBuilder flattened = new StringBuilder();
477            for (String k : mMap.keySet()) {
478                flattened.append(k);
479                flattened.append("=");
480                flattened.append(mMap.get(k));
481                flattened.append(";");
482            }
483            // chop off the extra semicolon at the end
484            flattened.deleteCharAt(flattened.length()-1);
485            return flattened.toString();
486        }
487
488        /**
489         * Takes a flattened string of parameters and adds each one to
490         * this Parameters object.
491         * <p>The {@link #flatten()} method does the reverse.</p>
492         *
493         * @param flattened a String of parameters (key-value paired) that
494         *                  are semi-colon delimited
495         */
496        public void unflatten(String flattened) {
497            mMap.clear();
498
499            StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
500            while (tokenizer.hasMoreElements()) {
501                String kv = tokenizer.nextToken();
502                int pos = kv.indexOf('=');
503                if (pos == -1) {
504                    continue;
505                }
506                String k = kv.substring(0, pos);
507                String v = kv.substring(pos + 1);
508                mMap.put(k, v);
509            }
510        }
511
512        public void remove(String key) {
513            mMap.remove(key);
514        }
515
516        /**
517         * Sets a String parameter.
518         *
519         * @param key   the key name for the parameter
520         * @param value the String value of the parameter
521         */
522        public void set(String key, String value) {
523            if (key.indexOf('=') != -1 || key.indexOf(';') != -1) {
524                Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)");
525                return;
526            }
527            if (value.indexOf('=') != -1 || value.indexOf(';') != -1) {
528                Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)");
529                return;
530            }
531
532            mMap.put(key, value);
533        }
534
535        /**
536         * Sets an integer parameter.
537         *
538         * @param key   the key name for the parameter
539         * @param value the int value of the parameter
540         */
541        public void set(String key, int value) {
542            mMap.put(key, Integer.toString(value));
543        }
544
545        /**
546         * Returns the value of a String parameter.
547         *
548         * @param key the key name for the parameter
549         * @return the String value of the parameter
550         */
551        public String get(String key) {
552            return mMap.get(key);
553        }
554
555        /**
556         * Returns the value of an integer parameter.
557         *
558         * @param key the key name for the parameter
559         * @return the int value of the parameter
560         */
561        public int getInt(String key) {
562            return Integer.parseInt(mMap.get(key));
563        }
564
565        /**
566         * Sets the dimensions for preview pictures.
567         *
568         * @param width  the width of the pictures, in pixels
569         * @param height the height of the pictures, in pixels
570         */
571        public void setPreviewSize(int width, int height) {
572            String v = Integer.toString(width) + "x" + Integer.toString(height);
573            set("preview-size", v);
574        }
575
576        /**
577         * Returns the dimensions setting for preview pictures.
578         *
579         * @return a Size object with the height and width setting
580         *          for the preview picture
581         */
582        public Size getPreviewSize() {
583            String pair = get("preview-size");
584            if (pair == null)
585                return null;
586            String[] dims = pair.split("x");
587            if (dims.length != 2)
588                return null;
589
590            return new Size(Integer.parseInt(dims[0]),
591                            Integer.parseInt(dims[1]));
592
593        }
594
595        /**
596         * Sets the dimensions for EXIF thumbnails.
597         *
598         * @param width  the width of the thumbnail, in pixels
599         * @param height the height of the thumbnail, in pixels
600         *
601         * FIXME: unhide before release
602         * @hide
603         */
604        public void setThumbnailSize(int width, int height) {
605            set("jpeg-thumbnail-width", width);
606            set("jpeg-thumbnail-height", height);
607        }
608
609        /**
610         * Returns the dimensions for EXIF thumbnail
611         *
612         * @return a Size object with the height and width setting
613         *          for the EXIF thumbnails
614         *
615         * FIXME: unhide before release
616         * @hide
617         */
618        public Size getThumbnailSize() {
619            return new Size(getInt("jpeg-thumbnail-width"),
620                            getInt("jpeg-thumbnail-height"));
621        }
622
623        /**
624         * Sets the quality of the EXIF thumbnail
625         *
626         * @param quality the JPEG quality of the EXIT thumbnail
627         *
628         * FIXME: unhide before release
629         * @hide
630         */
631        public void setThumbnailQuality(int quality) {
632            set("jpeg-thumbnail-quality", quality);
633        }
634
635        /**
636         * Returns the quality setting for the EXIF thumbnail
637         *
638         * @return the JPEG quality setting of the EXIF thumbnail
639         *
640         * FIXME: unhide before release
641         * @hide
642         */
643        public int getThumbnailQuality() {
644            return getInt("jpeg-thumbnail-quality");
645        }
646
647        /**
648         * Sets the rate at which preview frames are received.
649         *
650         * @param fps the frame rate (frames per second)
651         */
652        public void setPreviewFrameRate(int fps) {
653            set("preview-frame-rate", fps);
654        }
655
656        /**
657         * Returns the setting for the rate at which preview frames
658         * are received.
659         *
660         * @return the frame rate setting (frames per second)
661         */
662        public int getPreviewFrameRate() {
663            return getInt("preview-frame-rate");
664        }
665
666        /**
667         * Sets the image format for preview pictures.
668         *
669         * @param pixel_format the desired preview picture format
670         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
671         *                      <var>PixelFormat.RGB_565</var>, or
672         *                      <var>PixelFormat.JPEG</var>)
673         * @see android.graphics.PixelFormat
674         */
675        public void setPreviewFormat(int pixel_format) {
676            String s = cameraFormatForPixelFormat(pixel_format);
677            if (s == null) {
678                throw new IllegalArgumentException();
679            }
680
681            set("preview-format", s);
682        }
683
684        /**
685         * Returns the image format for preview pictures.
686         *
687         * @return the PixelFormat int representing the preview picture format
688         */
689        public int getPreviewFormat() {
690            return pixelFormatForCameraFormat(get("preview-format"));
691        }
692
693        /**
694         * Sets the dimensions for pictures.
695         *
696         * @param width  the width for pictures, in pixels
697         * @param height the height for pictures, in pixels
698         */
699        public void setPictureSize(int width, int height) {
700            String v = Integer.toString(width) + "x" + Integer.toString(height);
701            set("picture-size", v);
702        }
703
704        /**
705         * Returns the dimension setting for pictures.
706         *
707         * @return a Size object with the height and width setting
708         *          for pictures
709         */
710        public Size getPictureSize() {
711            String pair = get("picture-size");
712            if (pair == null)
713                return null;
714            String[] dims = pair.split("x");
715            if (dims.length != 2)
716                return null;
717
718            return new Size(Integer.parseInt(dims[0]),
719                            Integer.parseInt(dims[1]));
720
721        }
722
723        /**
724         * Sets the image format for pictures.
725         *
726         * @param pixel_format the desired picture format
727         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
728         *                      <var>PixelFormat.RGB_565</var>, or
729         *                      <var>PixelFormat.JPEG</var>)
730         * @see android.graphics.PixelFormat
731         */
732        public void setPictureFormat(int pixel_format) {
733            String s = cameraFormatForPixelFormat(pixel_format);
734            if (s == null) {
735                throw new IllegalArgumentException();
736            }
737
738            set("picture-format", s);
739        }
740
741        /**
742         * Returns the image format for pictures.
743         *
744         * @return the PixelFormat int representing the picture format
745         */
746        public int getPictureFormat() {
747            return pixelFormatForCameraFormat(get("picture-format"));
748        }
749
750        private String cameraFormatForPixelFormat(int pixel_format) {
751            switch(pixel_format) {
752            case PixelFormat.YCbCr_422_SP: return "yuv422sp";
753            case PixelFormat.YCbCr_420_SP: return "yuv420sp";
754            case PixelFormat.RGB_565:      return "rgb565";
755            case PixelFormat.JPEG:         return "jpeg";
756            default:                       return null;
757            }
758        }
759
760        private int pixelFormatForCameraFormat(String format) {
761            if (format == null)
762                return PixelFormat.UNKNOWN;
763
764            if (format.equals("yuv422sp"))
765                return PixelFormat.YCbCr_422_SP;
766
767            if (format.equals("yuv420sp"))
768                return PixelFormat.YCbCr_420_SP;
769
770            if (format.equals("rgb565"))
771                return PixelFormat.RGB_565;
772
773            if (format.equals("jpeg"))
774                return PixelFormat.JPEG;
775
776            return PixelFormat.UNKNOWN;
777        }
778
779    };
780}
781
782
783