blob: cbd10f86ed8d7f8345a79410a32f945e6e7ce798 [file] [log] [blame]
/*
* Copyright (C) 2013 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.app;
import android.content.Context;
import android.hardware.Camera;
import android.os.Handler;
import android.util.Log;
import com.android.camera.CameraDisabledException;
import com.android.camera.util.CameraUtil;
/**
* A class which implements {@link com.android.camera.app.CameraProvider} used
* by {@link com.android.camera.CameraActivity}.
* TODO: Make this class package private.
*/
public class CameraController implements CameraManager.CameraOpenCallback, CameraProvider {
private final String TAG = "CameraController";
private final Context mContext;
private CameraManager.CameraOpenCallback mCallbackReceiver;
private final Handler mCallbackHandler;
private final CameraManager mCameraManager;
private final Camera.CameraInfo[] mCameraInfos;
private final int mNumberOfCameras;
private final int mFirstBackCameraId;
private final int mFirstFrontCameraId;
private CameraManager.CameraProxy mCameraProxy;
private int mRequestingCameraId = -1;
/**
* Constructor.
*
* @param context The {@link android.content.Context} used to check if the
* camera is disabled.
* @param handler The {@link android.os.Handler} to post the camera
* callbacks to.
* @param cameraManager Used for camera open/close.
*/
public CameraController(Context context, CameraManager.CameraOpenCallback callbackReceiver,
Handler handler, CameraManager cameraManager) {
mContext = context;
mCallbackReceiver = callbackReceiver;
mCallbackHandler = handler;
mCameraManager = cameraManager;
mNumberOfCameras = Camera.getNumberOfCameras();
mCameraInfos = new Camera.CameraInfo[mNumberOfCameras];
for (int i = 0; i < mNumberOfCameras; i++) {
mCameraInfos[i] = new Camera.CameraInfo();
Camera.getCameraInfo(i, mCameraInfos[i]);
}
int firstFront = -1;
int firstBack = -1;
// Get the first (smallest) back and first front camera id.
for (int i = mNumberOfCameras - 1; i >= 0; i--) {
if (mCameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
firstBack = i;
} else {
if (mCameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
firstFront = i;
}
}
}
mFirstBackCameraId = firstBack;
mFirstFrontCameraId = firstFront;
}
@Override
public Camera.CameraInfo[] getCameraInfo() {
return mCameraInfos;
}
@Override
public int getNumberOfCameras() {
return mNumberOfCameras;
}
@Override
public int getFirstBackCameraId() {
return mFirstBackCameraId;
}
@Override
public int getFirstFrontCameraId() {
return mFirstFrontCameraId;
}
@Override
public boolean isFrontFacingCamera(int id) {
if (id >= mCameraInfos.length || mCameraInfos[id] == null) {
Log.e(TAG, "Camera info not available:" + id);
return false;
}
return (mCameraInfos[id].facing == Camera.CameraInfo.CAMERA_FACING_FRONT);
}
@Override
public boolean isBackFacingCamera(int id) {
if (id >= mCameraInfos.length || mCameraInfos[id] == null) {
Log.e(TAG, "Camera info not available:" + id);
return false;
}
return (mCameraInfos[id].facing == Camera.CameraInfo.CAMERA_FACING_BACK);
}
@Override
public void onCameraOpened(CameraManager.CameraProxy camera) {
mRequestingCameraId = -1;
mCameraProxy = camera;
mCallbackReceiver.onCameraOpened(camera);
}
@Override
public void onCameraDisabled(int cameraId) {
mCallbackReceiver.onCameraDisabled(cameraId);
}
@Override
public void onDeviceOpenFailure(int cameraId) {
mCallbackReceiver.onDeviceOpenFailure(cameraId);
}
@Override
public void onReconnectionFailure(CameraManager mgr) {
mCallbackReceiver.onReconnectionFailure(mgr);
}
@Override
public void requestCamera(int id) {
// Double open is avoided.
if (mRequestingCameraId == id) {
return;
}
mRequestingCameraId = id;
if (mCameraProxy == null) {
// No camera yet.
checkAndOpenCamera(mContext, mCameraManager, id, mCallbackHandler, this);
} else if (mCameraProxy.getCameraId() != id) {
// Already has another camera opened.
mCameraProxy.release(false);
mCameraProxy = null;
checkAndOpenCamera(mContext, mCameraManager, id, mCallbackHandler, this);
} else {
// The same camera, just do a reconnect.
mCameraProxy.reconnect(mCallbackHandler, this);
mCameraProxy = null;
}
}
@Override
public void releaseCamera(int id) {
if (mCameraProxy.getCameraId() != id) {
throw new IllegalStateException("Trying to release an unopened camera.");
}
if (mRequestingCameraId != -1) {
mRequestingCameraId = -1;
}
}
public void removeCallbackReceiver() {
mCallbackReceiver = null;
}
/**
* Closes the opened camera device.
* TODO: Make this method package private.
*/
public void closeCamera() {
Log.v(TAG, "closing camera");
if (mCameraProxy == null) {
return;
}
mCameraProxy.release(true);
mCameraProxy = null;
mRequestingCameraId = -1;
}
private static void checkAndOpenCamera(Context context, CameraManager cameraManager,
final int cameraId, Handler handler, final CameraManager.CameraOpenCallback cb) {
try {
CameraUtil.throwIfCameraDisabled(context);
cameraManager.cameraOpen(handler, cameraId, cb);
} catch (CameraDisabledException ex) {
handler.post(new Runnable() {
@Override
public void run() {
cb.onCameraDisabled(cameraId);
}
});
}
}
public void setOneShotPreviewCallback(Handler handler,
CameraManager.CameraPreviewDataCallback cb) {
mCameraProxy.setOneShotPreviewCallback(handler, cb);
}
}