CameraHolder.java revision ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5
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 31271b3095b9f763421c0547109da9de774795072dChih-Chung Chang/** 32271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * The class is used to hold an {@code android.hardware.Camera} instance. 33271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * 34271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>The {@code open()} and {@code release()} calls are similar to the ones 35271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * in {@code android.hardware.Camera}. The difference is if {@code keep()} is 36271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * called before {@code release()}, CameraHolder will try to hold the {@code 37271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * android.hardware.Camera} instance for a while, so if {@code open()} is 38271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * called soon after, we can avoid the cost of {@code open()} in {@code 39271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * android.hardware.Camera}. 40271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * 41271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>This is used in switching between {@code Camera} and {@code VideoCamera} 42271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * activities. 43271b3095b9f763421c0547109da9de774795072dChih-Chung Chang */ 44cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Changpublic class CameraHolder { 45cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static final String TAG = "CameraHolder"; 46cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private android.hardware.Camera mCameraDevice; 4791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang private long mKeepBeforeTime = 0; // Keep the Camera before this time. 483f3c857e3f34650c15d764810335024654b0fcc3Owen Lin private final Handler mHandler; 4991acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang private int mUsers = 0; // number of open() - number of release() 50ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang private int mNumberOfCameras; 51cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 524c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // We store the camera parameters when we actually open the device, 534c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // so we can restore them in the subsequent open() requests by the user. 544c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // This prevents the parameters set by the Camera activity used by 554c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang // the VideoCamera activity inadvertently. 564c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang private Parameters mParameters; 574c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang 58cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang // Use a singleton. 59cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static CameraHolder sHolder; 60cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public static synchronized CameraHolder instance() { 61cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang if (sHolder == null) { 62cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang sHolder = new CameraHolder(); 63cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 64cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return sHolder; 65cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 66cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 67cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private static final int RELEASE_CAMERA = 1; 68cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private class MyHandler extends Handler { 69cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang MyHandler(Looper looper) { 70cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang super(looper); 71cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 72cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 73cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang @Override 74cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public void handleMessage(Message msg) { 75cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang switch(msg.what) { 76cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang case RELEASE_CAMERA: 77dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin synchronized (CameraHolder.this) { 78dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // In 'CameraHolder.open', the 'RELEASE_CAMERA' message 79dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // will be removed if it is found in the queue. However, 80dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // there is a chance that this message has been handled 81dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // before being removed. So, we need to add a check 82dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin // here: 83dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin if (CameraHolder.this.mUsers == 0) releaseCamera(); 84dd6600e7f0adf322e5a8fcb0ed5389b14655106eOwen Lin } 85cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang break; 86cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 87cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 88cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 89cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 90cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private CameraHolder() { 91cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang HandlerThread ht = new HandlerThread("CameraHolder"); 92cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang ht.start(); 93cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler = new MyHandler(ht.getLooper()); 94ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang mNumberOfCameras = android.hardware.Camera.getNumberOfCameras(); 95ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang 96ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang android.hardware.Camera.CameraInfo info = 97ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang new android.hardware.Camera.CameraInfo(); 98ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "# of cameras:" + mNumberOfCameras); 99ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang for (int i = 0; i < mNumberOfCameras; i++) { 100ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "camera info #" + i); 101ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang android.hardware.Camera.getCameraInfo(i, info); 102ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "facing: " + info.mFacing); 103ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "orientation: " + info.mOrientation); 104ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 105ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 106ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang 107ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public int getNumberOfCameras() { 108ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang return mNumberOfCameras; 109cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 110cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 111ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public synchronized android.hardware.Camera open(int cameraId) 1123f3c857e3f34650c15d764810335024654b0fcc3Owen Lin throws CameraHardwareException { 11391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 0); 114cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang if (mCameraDevice == null) { 1153f3c857e3f34650c15d764810335024654b0fcc3Owen Lin try { 116ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang Log.v(TAG, "open camera " + cameraId); 117ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang mCameraDevice = android.hardware.Camera.open(cameraId); 1183f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } catch (RuntimeException e) { 1193f3c857e3f34650c15d764810335024654b0fcc3Owen Lin Log.e(TAG, "fail to connect Camera", e); 120f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new CameraHardwareException(e); 1213f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 1224c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang mParameters = mCameraDevice.getParameters(); 123cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } else { 124cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang try { 125cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.reconnect(); 126cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } catch (IOException e) { 127cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang Log.e(TAG, "reconnect failed."); 128f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new CameraHardwareException(e); 129cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 1304c9266ef8f43c6b057b6f560645475272c66ff8aChih-Chung Chang mCameraDevice.setParameters(mParameters); 131cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 13291acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang ++mUsers; 133cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler.removeMessages(RELEASE_CAMERA); 13491acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime = 0; 135cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return mCameraDevice; 136cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 137cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 138d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin /** 139d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin * Tries to open the hardware camera. If the camera is being used or 140d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin * unavailable then return {@code null}. 141d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin */ 142ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang public synchronized android.hardware.Camera tryOpen(int cameraId) { 143d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin try { 144ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang return mUsers == 0 ? open(cameraId) : null; 145d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } catch (CameraHardwareException e) { 146f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin // In eng build, we throw the exception so that test tool 147f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin // can detect it and report it 148f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin if ("eng".equals(Build.TYPE)) { 149f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin throw new RuntimeException(e); 150f6ef7b960f610d557f0bab924b9f7928b46f6f0aOwen Lin } 151d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin return null; 152d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } 153d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin } 154d9e32402bbc5ebaac40ccd2c4b734f8e5743343eOwen Lin 155cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public synchronized void release() { 15691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 1); 15791acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang --mUsers; 158cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.stopPreview(); 159cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang releaseCamera(); 160cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 161cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 162cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang private synchronized void releaseCamera() { 16391acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 0); 164cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang Assert(mCameraDevice != null); 165cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang long now = System.currentTimeMillis(); 16691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang if (now < mKeepBeforeTime) { 167cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA, 16891acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime - now); 169cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang return; 170cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 171cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice.release(); 172cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang mCameraDevice = null; 173cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 174cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang 175cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang public synchronized void keep() { 17691acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang // We allow (mUsers == 0) for the convenience of the calling activity. 1775075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang // The activity may not have a chance to call open() before the user 1785075f53df86f3dcb0a46fd6353057260ad480f43Chih-Chung Chang // choose the menu item to switch to another activity. 17991acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang Assert(mUsers == 1 || mUsers == 0); 180cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang // Keep the camera instance for 3 seconds. 18191acfc99279d5ece7ac9cb2d7a2980eb0d3b50daChih-Chung Chang mKeepBeforeTime = System.currentTimeMillis() + 3000; 182cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang } 183cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang} 184