Camera.java revision 3dec7d563a2f3e1eb967ce2054a00b6620e3558c
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 enum in libs/android_runtime/android_hardware_Camera.cpp
43    private static final int SHUTTER_CALLBACK = 0;
44    private static final int RAW_PICTURE_CALLBACK = 1;
45    private static final int JPEG_PICTURE_CALLBACK = 2;
46    private static final int PREVIEW_CALLBACK = 3;
47    private static final int AUTOFOCUS_CALLBACK = 4;
48    private static final int ERROR_CALLBACK = 5;
49
50    private int mNativeContext; // accessed by native methods
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
498            StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
499            while (tokenizer.hasMoreElements()) {
500                String kv = tokenizer.nextToken();
501                int pos = kv.indexOf('=');
502                if (pos == -1) {
503                    continue;
504                }
505                String k = kv.substring(0, pos);
506                String v = kv.substring(pos + 1);
507                mMap.put(k, v);
508            }
509        }
510
511        public void remove(String key) {
512            mMap.remove(key);
513        }
514
515        /**
516         * Sets a String parameter.
517         *
518         * @param key   the key name for the parameter
519         * @param value the String value of the parameter
520         */
521        public void set(String key, String value) {
522            if (key.indexOf('=') != -1 || key.indexOf(';') != -1) {
523                Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)");
524                return;
525            }
526            if (value.indexOf('=') != -1 || value.indexOf(';') != -1) {
527                Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)");
528                return;
529            }
530
531            mMap.put(key, value);
532        }
533
534        /**
535         * Sets an integer parameter.
536         *
537         * @param key   the key name for the parameter
538         * @param value the int value of the parameter
539         */
540        public void set(String key, int value) {
541            mMap.put(key, Integer.toString(value));
542        }
543
544        /**
545         * Returns the value of a String parameter.
546         *
547         * @param key the key name for the parameter
548         * @return the String value of the parameter
549         */
550        public String get(String key) {
551            return mMap.get(key);
552        }
553
554        /**
555         * Returns the value of an integer parameter.
556         *
557         * @param key the key name for the parameter
558         * @return the int value of the parameter
559         */
560        public int getInt(String key) {
561            return Integer.parseInt(mMap.get(key));
562        }
563
564        /**
565         * Sets the dimensions for preview pictures.
566         *
567         * @param width  the width of the pictures, in pixels
568         * @param height the height of the pictures, in pixels
569         */
570        public void setPreviewSize(int width, int height) {
571            String v = Integer.toString(width) + "x" + Integer.toString(height);
572            set("preview-size", v);
573        }
574
575        /**
576         * Returns the dimensions setting for preview pictures.
577         *
578         * @return a Size object with the height and width setting
579         *          for the preview picture
580         */
581        public Size getPreviewSize() {
582            String pair = get("preview-size");
583            if (pair == null)
584                return null;
585            String[] dims = pair.split("x");
586            if (dims.length != 2)
587                return null;
588
589            return new Size(Integer.parseInt(dims[0]),
590                            Integer.parseInt(dims[1]));
591
592        }
593
594        /**
595         * Sets the dimensions for EXIF thumbnails.
596         *
597         * @param width  the width of the thumbnail, in pixels
598         * @param height the height of the thumbnail, in pixels
599         *
600         * FIXME: unhide before release
601         * @hide
602         */
603        public void setThumbnailSize(int width, int height) {
604            set("jpeg-thumbnail-width", width);
605            set("jpeg-thumbnail-height", height);
606        }
607
608        /**
609         * Returns the dimensions for EXIF thumbnail
610         *
611         * @return a Size object with the height and width setting
612         *          for the EXIF thumbnails
613         *
614         * FIXME: unhide before release
615         * @hide
616         */
617        public Size getThumbnailSize() {
618            return new Size(getInt("jpeg-thumbnail-width"),
619                            getInt("jpeg-thumbnail-height"));
620        }
621
622        /**
623         * Sets the quality of the EXIF thumbnail
624         *
625         * @param quality the JPEG quality of the EXIT thumbnail
626         *
627         * FIXME: unhide before release
628         * @hide
629         */
630        public void setThumbnailQuality(int quality) {
631            set("jpeg-thumbnail-quality", quality);
632        }
633
634        /**
635         * Returns the quality setting for the EXIF thumbnail
636         *
637         * @return the JPEG quality setting of the EXIF thumbnail
638         *
639         * FIXME: unhide before release
640         * @hide
641         */
642        public int getThumbnailQuality() {
643            return getInt("jpeg-thumbnail-quality");
644        }
645
646        /**
647         * Sets the rate at which preview frames are received.
648         *
649         * @param fps the frame rate (frames per second)
650         */
651        public void setPreviewFrameRate(int fps) {
652            set("preview-frame-rate", fps);
653        }
654
655        /**
656         * Returns the setting for the rate at which preview frames
657         * are received.
658         *
659         * @return the frame rate setting (frames per second)
660         */
661        public int getPreviewFrameRate() {
662            return getInt("preview-frame-rate");
663        }
664
665        /**
666         * Sets the image format for preview pictures.
667         *
668         * @param pixel_format the desired preview picture format
669         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
670         *                      <var>PixelFormat.RGB_565</var>, or
671         *                      <var>PixelFormat.JPEG</var>)
672         * @see android.graphics.PixelFormat
673         */
674        public void setPreviewFormat(int pixel_format) {
675            String s = cameraFormatForPixelFormat(pixel_format);
676            if (s == null) {
677                throw new IllegalArgumentException();
678            }
679
680            set("preview-format", s);
681        }
682
683        /**
684         * Returns the image format for preview pictures.
685         *
686         * @return the PixelFormat int representing the preview picture format
687         */
688        public int getPreviewFormat() {
689            return pixelFormatForCameraFormat(get("preview-format"));
690        }
691
692        /**
693         * Sets the dimensions for pictures.
694         *
695         * @param width  the width for pictures, in pixels
696         * @param height the height for pictures, in pixels
697         */
698        public void setPictureSize(int width, int height) {
699            String v = Integer.toString(width) + "x" + Integer.toString(height);
700            set("picture-size", v);
701        }
702
703        /**
704         * Returns the dimension setting for pictures.
705         *
706         * @return a Size object with the height and width setting
707         *          for pictures
708         */
709        public Size getPictureSize() {
710            String pair = get("picture-size");
711            if (pair == null)
712                return null;
713            String[] dims = pair.split("x");
714            if (dims.length != 2)
715                return null;
716
717            return new Size(Integer.parseInt(dims[0]),
718                            Integer.parseInt(dims[1]));
719
720        }
721
722        /**
723         * Sets the image format for pictures.
724         *
725         * @param pixel_format the desired picture format
726         *                     (<var>PixelFormat.YCbCr_420_SP</var>,
727         *                      <var>PixelFormat.RGB_565</var>, or
728         *                      <var>PixelFormat.JPEG</var>)
729         * @see android.graphics.PixelFormat
730         */
731        public void setPictureFormat(int pixel_format) {
732            String s = cameraFormatForPixelFormat(pixel_format);
733            if (s == null) {
734                throw new IllegalArgumentException();
735            }
736
737            set("picture-format", s);
738        }
739
740        /**
741         * Returns the image format for pictures.
742         *
743         * @return the PixelFormat int representing the picture format
744         */
745        public int getPictureFormat() {
746            return pixelFormatForCameraFormat(get("picture-format"));
747        }
748
749        private String cameraFormatForPixelFormat(int pixel_format) {
750            switch(pixel_format) {
751            case PixelFormat.YCbCr_422_SP: return "yuv422sp";
752            case PixelFormat.YCbCr_420_SP: return "yuv420sp";
753            case PixelFormat.RGB_565:      return "rgb565";
754            case PixelFormat.JPEG:         return "jpeg";
755            default:                       return null;
756            }
757        }
758
759        private int pixelFormatForCameraFormat(String format) {
760            if (format == null)
761                return PixelFormat.UNKNOWN;
762
763            if (format.equals("yuv422sp"))
764                return PixelFormat.YCbCr_422_SP;
765
766            if (format.equals("yuv420sp"))
767                return PixelFormat.YCbCr_420_SP;
768
769            if (format.equals("rgb565"))
770                return PixelFormat.RGB_565;
771
772            if (format.equals("jpeg"))
773                return PixelFormat.JPEG;
774
775            return PixelFormat.UNKNOWN;
776        }
777
778    };
779}
780
781
782