Share Camera between Camera and VideoCamera.
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index b3bbbf1..0cf2cd2 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -865,7 +865,7 @@
          */
         Thread openCameraThread = new Thread(new Runnable() {
             public void run() {
-                mCameraDevice = android.hardware.Camera.open();
+                mCameraDevice = CameraHolder.instance().open();
             }
         });
         openCameraThread.start();
@@ -1435,7 +1435,7 @@
 
     private void closeCamera() {
         if (mCameraDevice != null) {
-            mCameraDevice.release();
+            CameraHolder.instance().release();
             mCameraDevice = null;
             mPreviewing = false;
         }
@@ -1443,7 +1443,7 @@
 
     private boolean ensureCameraDevice() {
         if (mCameraDevice == null) {
-            mCameraDevice = android.hardware.Camera.open();
+            mCameraDevice = CameraHolder.instance().open();
         }
         return mCameraDevice != null;
     }
@@ -1519,7 +1519,7 @@
         try {
             mCameraDevice.setPreviewDisplay(mSurfaceHolder);
         } catch (IOException exception) {
-            mCameraDevice.release();
+            CameraHolder.instance().release();
             mCameraDevice = null;
             // TODO: add more exception handling logic here
             return;
diff --git a/src/com/android/camera/CameraHolder.java b/src/com/android/camera/CameraHolder.java
new file mode 100644
index 0000000..09b6b55
--- /dev/null
+++ b/src/com/android/camera/CameraHolder.java
@@ -0,0 +1,104 @@
+package com.android.camera;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.IOException;
+
+import static com.android.camera.Util.Assert;
+
+//
+// CameraHolder is used to hold an android.hardware.Camera instance.
+//
+// The open() and release() calls are similar to the ones in
+// android.hardware.Camera. The difference is if keep() is called before
+// release(), CameraHolder will try to hold the android.hardware.Camera
+// instance for a while, so if open() call called soon after, we can avoid
+// the cost of open() in android.hardware.Camera.
+//
+// This is used in switching between Camera and VideoCamera activities.
+//
+public class CameraHolder {
+    private static final String TAG = "CameraHolder";
+    private android.hardware.Camera mCameraDevice;
+    private long keepBeforeTime = 0;  // Keep the Camera before this time.
+    private Handler mHandler;
+    private int users = 0;  // number of open() - number of release()
+
+    // Use a singleton.
+    private static CameraHolder sHolder;
+    public static synchronized CameraHolder instance() {
+        if (sHolder == null) {
+            sHolder = new CameraHolder();
+        }
+        return sHolder;
+    }
+
+    private static final int RELEASE_CAMERA = 1;
+    private class MyHandler extends Handler {
+        MyHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case RELEASE_CAMERA:
+                    releaseCamera();
+                    break;
+            }
+        }
+    }
+
+    private CameraHolder() {
+        HandlerThread ht = new HandlerThread("CameraHolder");
+        ht.start();
+        mHandler = new MyHandler(ht.getLooper());
+    }
+
+    public synchronized android.hardware.Camera open() {
+        Assert(users == 0);
+        if (mCameraDevice == null) {
+            mCameraDevice = android.hardware.Camera.open();
+        } else {
+            try {
+                mCameraDevice.reconnect();
+            } catch (IOException e) {
+                Log.e(TAG, "reconnect failed.");
+            }
+        }
+        ++users;
+        mHandler.removeMessages(RELEASE_CAMERA);
+        keepBeforeTime = 0;
+        return mCameraDevice;
+    }
+
+    public synchronized void release() {
+        Assert(users == 1);
+        --users;
+        mCameraDevice.stopPreview();
+        releaseCamera();
+    }
+
+    private synchronized void releaseCamera() {
+        Assert(users == 0);
+        Assert(mCameraDevice != null);
+        long now = System.currentTimeMillis();
+        if (now < keepBeforeTime) {
+            mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA,
+                    keepBeforeTime - now);
+            return;
+        }
+        mCameraDevice.release();
+        mCameraDevice = null;
+    }
+
+    public synchronized void keep() {
+        Assert(users == 1);
+        // Keep the camera instance for 3 seconds.
+        keepBeforeTime = System.currentTimeMillis() + 3000;
+    }
+}
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index aae30ba..7464d55 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -95,9 +95,9 @@
                 registerOnSharedPreferenceChangeListener(this);
 
         // Get parameters.
-        android.hardware.Camera device = android.hardware.Camera.open();
+        android.hardware.Camera device = CameraHolder.instance().open();
         mParameters = device.getParameters();
-        device.release();
+        CameraHolder.instance().release();
 
         // Create white balance settings.
         createSettings(mWhiteBalance, Camera.SUPPORTED_WHITE_BALANCE,
diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java
index 2a9254f..1a92057 100644
--- a/src/com/android/camera/MenuHelper.java
+++ b/src/com/android/camera/MenuHelper.java
@@ -869,6 +869,11 @@
         Intent intent = new Intent(action);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+
+        // Keep the camera instance for a while.
+        // This avoids re-opening the camera and saves time.
+        CameraHolder.instance().keep();
+
         activity.startActivity(intent);
         return true;
     }
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 547c4b5..943ea6d 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -215,7 +215,7 @@
          */
         Thread openCameraThread = new Thread(new Runnable() {
             public void run() {
-                mCameraDevice = android.hardware.Camera.open();
+                mCameraDevice = CameraHolder.instance().open();
             }
         });
         openCameraThread.start();
@@ -491,14 +491,14 @@
         if (mCameraDevice == null) {
             // If the activity is paused and resumed, camera device has been
             // released and we need to open the camera.
-            mCameraDevice = android.hardware.Camera.open();
+            mCameraDevice = CameraHolder.instance().open();
         }
 
         setCameraParameters();
         try {
             mCameraDevice.setPreviewDisplay(mSurfaceHolder);
         } catch (IOException ex) {
-            mCameraDevice.release();
+            CameraHolder.instance().release();
             mCameraDevice = null;
             Log.e(TAG, "failed to set preview display");
             return false;
@@ -511,7 +511,7 @@
             // TODO: change Throwable to IOException once
             //      android.hardware.Camera.startPreview properly declares
             //      that it throws IOException.
-            mCameraDevice.release();
+            CameraHolder.instance().release();
             mCameraDevice = null;
             Log.e(TAG, "failed to start preview");
             return false;
@@ -528,7 +528,7 @@
         }
         // If we don't lock the camera, release() will fail.
         mCameraDevice.lock();
-        mCameraDevice.release();
+        CameraHolder.instance().release();
         mCameraDevice = null;
         mPreviewing = false;
     }