CameraHolder.java revision 7add00693c1ec910bc8700fe046ee18cbe4e1148
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 217add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Liimport android.hardware.Camera.CameraInfo; 224c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Changimport android.hardware.Camera.Parameters; 23f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Linimport android.os.Build; 24cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Handler; 25cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.HandlerThread; 26cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Looper; 27cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.os.Message; 28cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport android.util.Log; 29cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 30cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changimport java.io.IOException; 31cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 32271b3095b9f763421c0547109da9de774795072dChih-Chung Chang/** 33271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * The class is used to hold an {@code android.hardware.Camera} instance. 34271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * 35271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>The {@code open()} and {@code release()} calls are similar to the ones 36271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * in {@code android.hardware.Camera}. The difference is if {@code keep()} is 37271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * called before {@code release()}, CameraHolder will try to hold the {@code 38271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * android.hardware.Camera} instance for a while, so if {@code open()} is 39271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * called soon after, we can avoid the cost of {@code open()} in {@code 40271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * android.hardware.Camera}. 41271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * 42271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>This is used in switching between {@code Camera} and {@code VideoCamera} 43271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * activities. 44271b3095b9f763421c0547109da9de774795072dChih-Chung Chang */ 45cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changpublic class CameraHolder { 46cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static final String TAG = "CameraHolder"; 47cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private android.hardware.Camera mCameraDevice; 4891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang private long mKeepBeforeTime = 0; // Keep the Camera before this time. 493f3c857e3f34650c15d764810335024654b0fcc3Owen Lin private final Handler mHandler; 5091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang private int mUsers = 0; // number of open() - number of release() 51ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang private int mNumberOfCameras; 527add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li private CameraInfo[] mInfo; 53cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 544c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // We store the camera parameters when we actually open the device, 554c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // so we can restore them in the subsequent open() requests by the user. 564c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // This prevents the parameters set by the Camera activity used by 574c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // the VideoCamera activity inadvertently. 584c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang private Parameters mParameters; 594c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang 60cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang // Use a singleton. 61cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static CameraHolder sHolder; 62cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public static synchronized CameraHolder instance() { 63cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang if (sHolder == null) { 64cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang sHolder = new CameraHolder(); 65cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 66cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return sHolder; 67cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 68cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 69cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static final int RELEASE_CAMERA = 1; 70cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private class MyHandler extends Handler { 71cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang MyHandler(Looper looper) { 72cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang super(looper); 73cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 74cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 75cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang @Override 76cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public void handleMessage(Message msg) { 77cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang switch(msg.what) { 78cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang case RELEASE_CAMERA: 79dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin synchronized (CameraHolder.this) { 80dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // In 'CameraHolder.open', the 'RELEASE_CAMERA' message 81dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // will be removed if it is found in the queue. However, 82dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // there is a chance that this message has been handled 83dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // before being removed. So, we need to add a check 84dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // here: 85dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin if (CameraHolder.this.mUsers == 0) releaseCamera(); 86dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin } 87cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang break; 88cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 89cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 90cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 91cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 92cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private CameraHolder() { 93cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang HandlerThread ht = new HandlerThread("CameraHolder"); 94cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang ht.start(); 95cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler = new MyHandler(ht.getLooper()); 96ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang mNumberOfCameras = android.hardware.Camera.getNumberOfCameras(); 977add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li mInfo = new CameraInfo[mNumberOfCameras]; 98ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang for (int i = 0; i < mNumberOfCameras; i++) { 997add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li mInfo[i] = new CameraInfo(); 1007add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li android.hardware.Camera.getCameraInfo(i, mInfo[i]); 101ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 102ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 103ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang 104ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public int getNumberOfCameras() { 105ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang return mNumberOfCameras; 106cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 107cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 1087add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li public CameraInfo[] getCameraInfo() { 1097add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li return mInfo; 1107add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li } 1117add00693c1ec910bc8700fe046ee18cbe4e1148Wu-cheng Li 112ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public synchronized android.hardware.Camera open(int cameraId) 1133f3c857e3f34650c15d764810335024654b0fcc3Owen Lin throws CameraHardwareException { 11491acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 0); 115cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang if (mCameraDevice == null) { 1163f3c857e3f34650c15d764810335024654b0fcc3Owen Lin try { 117ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "open camera " + cameraId); 118ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang mCameraDevice = android.hardware.Camera.open(cameraId); 1193f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } catch (RuntimeException e) { 1203f3c857e3f34650c15d764810335024654b0fcc3Owen Lin Log.e(TAG, "fail to connect Camera", e); 121f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new CameraHardwareException(e); 1223f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 1234c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang mParameters = mCameraDevice.getParameters(); 124cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } else { 125cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang try { 126cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.reconnect(); 127cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } catch (IOException e) { 128cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang Log.e(TAG, "reconnect failed."); 129f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new CameraHardwareException(e); 130cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 1314c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang mCameraDevice.setParameters(mParameters); 132cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 13391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang ++mUsers; 134cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler.removeMessages(RELEASE_CAMERA); 13591acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime = 0; 136cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return mCameraDevice; 137cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 138cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 139d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin /** 140d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin * Tries to open the hardware camera. If the camera is being used or 141d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin * unavailable then return {@code null}. 142d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin */ 143ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public synchronized android.hardware.Camera tryOpen(int cameraId) { 144d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin try { 145ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang return mUsers == 0 ? open(cameraId) : null; 146d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } catch (CameraHardwareException e) { 147f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin // In eng build, we throw the exception so that test tool 148f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin // can detect it and report it 149f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin if ("eng".equals(Build.TYPE)) { 150f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new RuntimeException(e); 151f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin } 152d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin return null; 153d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } 154d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } 155d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin 156cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public synchronized void release() { 15791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 1); 15891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang --mUsers; 159cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.stopPreview(); 160cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang releaseCamera(); 161cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 162cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 163cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private synchronized void releaseCamera() { 16491acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 0); 165cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang Assert(mCameraDevice != null); 166cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang long now = System.currentTimeMillis(); 16791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang if (now < mKeepBeforeTime) { 168cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA, 16991acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime - now); 170cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return; 171cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 172cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.release(); 173cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice = null; 174cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 175cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 176cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public synchronized void keep() { 17791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang // We allow (mUsers == 0) for the convenience of the calling activity. 1785075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang // The activity may not have a chance to call open() before the user 1795075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang // choose the menu item to switch to another activity. 18091acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 1 || mUsers == 0); 181cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang // Keep the camera instance for 3 seconds. 18291acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime = System.currentTimeMillis() + 3000; 183cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 184cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang} 185