CameraHolder.java revision 4c9266ef8f43c6b057b6f560645475272c66ff8a
191acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang/*
291acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * Copyright (C) 2009 The Android Open Source Project
391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang *
491acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License");
591acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * you may not use this file except in compliance with the License.
691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * You may obtain a copy of the License at
791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang *
891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang *      http://www.apache.org/licenses/LICENSE-2.0
991acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang *
1091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * Unless required by applicable law or agreed to in writing, software
1191acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS,
1291acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * See the License for the specific language governing permissions and
1491acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang * limitations under the License.
1591acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang */
1691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang
17cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changpackage com.android.camera;
18cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
193f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport static com.android.camera.Util.Assert;
203f3c857e3f34650c15d764810335024654b0fcc3Owen Lin
214c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Changimport android.hardware.Camera.Parameters;
22f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Linimport android.os.Build;
23cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Handler;
24cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.HandlerThread;
25cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Looper;
26cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Message;
27cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.util.Log;
28cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
29cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport java.io.IOException;
30cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
31cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang//
32cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// CameraHolder is used to hold an android.hardware.Camera instance.
33cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang//
34cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// The open() and release() calls are similar to the ones in
35cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// android.hardware.Camera. The difference is if keep() is called before
36cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// release(), CameraHolder will try to hold the android.hardware.Camera
37cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// instance for a while, so if open() call called soon after, we can avoid
38cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// the cost of open() in android.hardware.Camera.
39cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang//
40cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang// This is used in switching between Camera and VideoCamera activities.
41cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang//
42cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changpublic class CameraHolder {
43cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private static final String TAG = "CameraHolder";
44cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private android.hardware.Camera mCameraDevice;
4591acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang    private long mKeepBeforeTime = 0;  // Keep the Camera before this time.
463f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    private final Handler mHandler;
4791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang    private int mUsers = 0;  // number of open() - number of release()
48cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
494c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang    // We store the camera parameters when we actually open the device,
504c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang    // so we can restore them in the subsequent open() requests by the user.
514c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang    // This prevents the parameters set by the Camera activity used by
524c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang    // the VideoCamera activity inadvertently.
534c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang    private Parameters mParameters;
544c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang
55cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    // Use a singleton.
56cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private static CameraHolder sHolder;
57cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    public static synchronized CameraHolder instance() {
58cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        if (sHolder == null) {
59cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            sHolder = new CameraHolder();
60cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        }
61cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        return sHolder;
62cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
63cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
64cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private static final int RELEASE_CAMERA = 1;
65cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private class MyHandler extends Handler {
66cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        MyHandler(Looper looper) {
67cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            super(looper);
68cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        }
69cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
70cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        @Override
71cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        public void handleMessage(Message msg) {
72cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            switch(msg.what) {
73cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                case RELEASE_CAMERA:
74cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                    releaseCamera();
75cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                    break;
76cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            }
77cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        }
78cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
79cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
80cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private CameraHolder() {
81cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        HandlerThread ht = new HandlerThread("CameraHolder");
82cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        ht.start();
83cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        mHandler = new MyHandler(ht.getLooper());
84cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
85cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
863f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    public synchronized android.hardware.Camera open()
873f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            throws CameraHardwareException {
8891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        Assert(mUsers == 0);
89cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        if (mCameraDevice == null) {
903f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            try {
913f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                mCameraDevice = android.hardware.Camera.open();
923f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            } catch (RuntimeException e) {
933f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                Log.e(TAG, "fail to connect Camera", e);
94f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin                throw new CameraHardwareException(e);
953f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            }
964c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang            mParameters = mCameraDevice.getParameters();
97cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        } else {
98cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            try {
99cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                mCameraDevice.reconnect();
100cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            } catch (IOException e) {
101cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                Log.e(TAG, "reconnect failed.");
102f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin                throw new CameraHardwareException(e);
103cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            }
1044c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang            mCameraDevice.setParameters(mParameters);
105cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        }
10691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        ++mUsers;
107cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        mHandler.removeMessages(RELEASE_CAMERA);
10891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        mKeepBeforeTime = 0;
109cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        return mCameraDevice;
110cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
111cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
112d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin    /**
113d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin     * Tries to open the hardware camera. If the camera is being used or
114d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin     * unavailable then return {@code null}.
115d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin     */
116d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin    public synchronized android.hardware.Camera tryOpen() {
117d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin        try {
118d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin            return mUsers == 0 ? open() : null;
119d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin        } catch (CameraHardwareException e) {
120f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin            // In eng build, we throw the exception so that test tool
121f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin            // can detect it and report it
122f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin            if ("eng".equals(Build.TYPE)) {
123f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin                throw new RuntimeException(e);
124f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin            }
125d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin            return null;
126d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin        }
127d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin    }
128d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin
129cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    public synchronized void release() {
13091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        Assert(mUsers == 1);
13191acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        --mUsers;
132cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        mCameraDevice.stopPreview();
133cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        releaseCamera();
134cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
135cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
136cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    private synchronized void releaseCamera() {
13791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        Assert(mUsers == 0);
138cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        Assert(mCameraDevice != null);
139cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        long now = System.currentTimeMillis();
14091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        if (now < mKeepBeforeTime) {
141cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA,
14291acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang                    mKeepBeforeTime - now);
143cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            return;
144cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        }
145cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        mCameraDevice.release();
146cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        mCameraDevice = null;
147cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
148cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang
149cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    public synchronized void keep() {
15091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        // We allow (mUsers == 0) for the convenience of the calling activity.
1515075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang        // The activity may not have a chance to call open() before the user
1525075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang        // choose the menu item to switch to another activity.
15391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        Assert(mUsers == 1 || mUsers == 0);
154cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        // Keep the camera instance for 3 seconds.
15591acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang        mKeepBeforeTime = System.currentTimeMillis() + 3000;
156cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang    }
157cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang}
158