/* * 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. */ /* * Modified by Nilesh Patel */ package com.lightbox.android.camera.device; import static com.lightbox.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 com.lightbox.android.camera.CameraHardwareException; import com.lightbox.android.camera.device.CameraHolder; import com.lightbox.android.camera.device.GingerbreadCameraHolder; import com.lightbox.android.camera.device.HTCFrontFacingFixGingerbreadCameraHolder; import com.lightbox.android.camera.device.LGOptimus2XCameraHolder; import com.lightbox.android.camera.device.PreGingerbreadCameraHolder; /** * The class is used to hold an {@code android.hardware.Camera} instance. * * <p>The {@code open()} and {@code release()} calls are similar to the ones * in {@code android.hardware.Camera}. The difference is if {@code keep()} is * called before {@code release()}, CameraHolder will try to hold the {@code * android.hardware.Camera} instance for a while, so if {@code open()} is * called soon after, we can avoid the cost of {@code open()} in {@code * android.hardware.Camera}. * * <p>This is used in switching between {@code Camera} and {@code VideoCamera} * activities. */ public abstract class CameraHolder { protected static final String TAG = "CameraHolder"; protected android.hardware.Camera mCameraDevice; protected long mKeepBeforeTime = 0; // Keep the Camera before this time. protected final Handler mHandler; protected int mUsers = 0; // number of open() - number of release() protected int mNumberOfCameras; protected int mCameraId = -1; // 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. protected Parameters mParameters; // Use a singleton. private static CameraHolder sHolder; public static synchronized CameraHolder instance() { if (sHolder == null) { if (Build.VERSION.SDK_INT >= 0x00000009 /*Build.VERSION_CODES.GINGERBREAD*/) { if (Build.MODEL.equals("PC36100") || Build.MODEL.equals("HTC Desire S")) { //TODO add HTC Sensation 4G sHolder = new HTCFrontFacingFixGingerbreadCameraHolder(); } else if (Build.MODEL.equals("SAMSUNG-SGH-I897")) { sHolder = new SamsungCaptivateGingerbreadCameraHolder(); } else { sHolder = new GingerbreadCameraHolder(); } } else { if (Build.DEVICE.equals("p990") || Build.DEVICE.equals("p999")) { sHolder = new LGOptimus2XCameraHolder(); } else { sHolder = new PreGingerbreadCameraHolder(); } } } return sHolder; } protected CameraHolder() { HandlerThread ht = new HandlerThread("CameraHolder"); ht.start(); mHandler = new MyHandler(ht.getLooper()); } protected static final int RELEASE_CAMERA = 1; protected class MyHandler extends Handler { MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch(msg.what) { case RELEASE_CAMERA: synchronized (CameraHolder.this) { // In 'CameraHolder.open', the 'RELEASE_CAMERA' message // will be removed if it is found in the queue. However, // there is a chance that this message has been handled // before being removed. So, we need to add a check // here: if (CameraHolder.this.mUsers == 0) releaseCamera(); } break; } } } public abstract int getNumberOfCameras(); public abstract int getFrontFacingCameraId(); public abstract int getRearFacingCameraId(); public abstract boolean isFrontFacing(int cameraId); public abstract int getCameraOrientation(int cameraId, int orientationSensorValue); public abstract android.hardware.Camera open(int cameraId) throws CameraHardwareException; public abstract double getAspectRatio(); /** * Tries to open the hardware camera. If the camera is being used or * unavailable then return {@code null}. */ public synchronized android.hardware.Camera tryOpen(int cameraId) { try { return mUsers == 0 ? open(cameraId) : 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(); } protected 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; mCameraId = -1; } 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; } }