| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.camera; |
| |
| import static com.android.camera.Util.Assert; |
| |
| import android.hardware.Camera.Parameters; |
| import android.os.Build; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.util.Log; |
| |
| import java.io.IOException; |
| |
| // |
| // 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 mKeepBeforeTime = 0; // Keep the Camera before this time. |
| private final Handler mHandler; |
| private int mUsers = 0; // number of open() - number of release() |
| |
| // We store the camera parameters when we actually open the device, |
| // so we can restore them in the subsequent open() requests by the user. |
| // This prevents the parameters set by the Camera activity used by |
| // the VideoCamera activity inadvertently. |
| private Parameters mParameters; |
| |
| // 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() |
| throws CameraHardwareException { |
| Assert(mUsers == 0); |
| if (mCameraDevice == null) { |
| try { |
| mCameraDevice = android.hardware.Camera.open(); |
| } catch (RuntimeException e) { |
| Log.e(TAG, "fail to connect Camera", e); |
| throw new CameraHardwareException(e); |
| } |
| mParameters = mCameraDevice.getParameters(); |
| } else { |
| try { |
| mCameraDevice.reconnect(); |
| } catch (IOException e) { |
| Log.e(TAG, "reconnect failed."); |
| throw new CameraHardwareException(e); |
| } |
| mCameraDevice.setParameters(mParameters); |
| } |
| ++mUsers; |
| mHandler.removeMessages(RELEASE_CAMERA); |
| mKeepBeforeTime = 0; |
| return mCameraDevice; |
| } |
| |
| /** |
| * Tries to open the hardware camera. If the camera is being used or |
| * unavailable then return {@code null}. |
| */ |
| public synchronized android.hardware.Camera tryOpen() { |
| try { |
| return mUsers == 0 ? open() : null; |
| } catch (CameraHardwareException e) { |
| // In eng build, we throw the exception so that test tool |
| // can detect it and report it |
| if ("eng".equals(Build.TYPE)) { |
| throw new RuntimeException(e); |
| } |
| return null; |
| } |
| } |
| |
| public synchronized void release() { |
| Assert(mUsers == 1); |
| --mUsers; |
| mCameraDevice.stopPreview(); |
| releaseCamera(); |
| } |
| |
| private synchronized void releaseCamera() { |
| Assert(mUsers == 0); |
| Assert(mCameraDevice != null); |
| long now = System.currentTimeMillis(); |
| if (now < mKeepBeforeTime) { |
| mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA, |
| mKeepBeforeTime - now); |
| return; |
| } |
| mCameraDevice.release(); |
| mCameraDevice = null; |
| } |
| |
| public synchronized void keep() { |
| // We allow (mUsers == 0) for the convenience of the calling activity. |
| // The activity may not have a chance to call open() before the user |
| // choose the menu item to switch to another activity. |
| Assert(mUsers == 1 || mUsers == 0); |
| // Keep the camera instance for 3 seconds. |
| mKeepBeforeTime = System.currentTimeMillis() + 3000; |
| } |
| } |