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