在上一篇文章《Android Camera原理之openCamera模块(一)》我们主要介绍了openCamera的调用流程以及camera模块涉及到的4个层次之间的调用关系,但是一些细节问题并没有阐释到,本文我们补充一下细节问题,力求丰满整个openCamera模块的知识体系。
在《Android Camera模块解析之拍照》一文中谈到了调用openCamera方法:
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
这个manager就是CameraManager实例,openCamera方法上一篇文章已经介绍地比较清楚了,但是第二个参数mStateCallback没有深入讲解,大家只知道是一个相机状态的回调,但是这个状态很重要。这个状态回调会告知开发者当前的camera处于什么状态,在确切获得这个状态之后,才能进行下一步的操作。例如我打开camera是成功还是失败了,如果不知道的话是不能进行下一步的操作的。
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
Activity activity = getActivity();
if (null != activity) {
activity.finish();
}
}
};
本文想搞清楚的一点是:Camera状态是如何回调的?
由于上一篇openCamera的文章已经谈到了详细的调用流程,这里不会赘述了。
1.openCameraDeviceUserAsync中StateCallback
openCamera会调用到openCameraDeviceUserAsync(...)中,当然也会把它的StateCallback参数传进来,这个参数和获取到的CameraCharacteristics一起传入CameraDeviceImpl的构造函数中。
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
executor,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);
但是传入cameraService的回调参数却不是这个回调,看一下代码:
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
//......
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
这个callbacks是CameraDeviceImpl实例中的参数,那么这个callbacks和我们传入的StateCallback有什么关系了,还是要去CameraDeviceImpl看一下。
public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
CameraCharacteristics characteristics, int appTargetSdkVersion) {
if (cameraId == null || callback == null || executor == null || characteristics == null) {
throw new IllegalArgumentException("Null argument given");
}
mCameraId = cameraId;
mDeviceCallback = callback;
mDeviceExecutor = executor;
mCharacteristics = characteristics;
mAppTargetSdkVersion = appTargetSdkVersion;
final int MAX_TAG_LEN = 23;
String tag = String.format("CameraDevice-JV-%s", mCameraId);
if (tag.length() > MAX_TAG_LEN) {
tag = tag.substring(0, MAX_TAG_LEN);
}
TAG = tag;
Integer partialCount =
mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
if (partialCount == null) {
// 1 means partial result is not supported.
mTotalPartialCount = 1;
} else {
mTotalPartialCount = partialCount;
}
}
- 构造函数中传入的StateCallback赋给了CameraDeviceImpl中的mDeviceCallback
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
public CameraDeviceCallbacks getCallbacks() {
return mCallbacks;
}
public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
//......
}
- CameraDeviceCallbacks继承ICameraDeviceCallbacks.Stub,而ICameraDeviceCallbacks.Stub是可以在Binder IPC中传输的对象,很显然这个才是应用程序与CameraService通信的回调,在这个回调中的执行方法标识当前的camera的执行状态
2.CameraDeviceCallbacks回调
ICameraDeviceCallbacks.aidl自动生成的android/hardware/camera2/ICameraDeviceCallbacks.h文件
class ICameraDeviceCallbacksDefault : public ICameraDeviceCallbacks {
public:
::android::IBinder* onAsBinder() override;
::android::binder::Status onDeviceError(int32_t errorCode, const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras) override;
::android::binder::Status onDeviceIdle() override;
::android::binder::Status onCaptureStarted(const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras, int64_t timestamp) override;
::android::binder::Status onResultReceived(const ::android::hardware::camera2::impl::CameraMetadataNative& result, const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras, const ::std::vector<::android::hardware::camera2::impl::PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
::android::binder::Status onPrepared(int32_t streamId) override;
::android::binder::Status onRepeatingRequestError(int64_t lastFrameNumber, int32_t repeatingRequestId) override;
::android::binder::Status onRequestQueueEmpty() override;
};
这个回调函数是从CameraService中调上来的。下面的回调包含了Camera执行过程中的各种状态,执行成功、执行失败、数据接收成功等等。这儿暂时不展开描述,等后面capture image的时候会详细阐释。
- onDeviceError
- onDeviceIdle
- onCaptureStarted
- onResultReceived
- onPrepared
- onRepeatingRequestError
- onRequestQueueEmpty
3.StateCallback回调
StateCallback是openCamera传入的3个参数中的一个,这是一个标识当前camera连接状态的回调。
public static abstract class StateCallback {
public static final int ERROR_CAMERA_IN_USE = 1;
public static final int ERROR_MAX_CAMERAS_IN_USE = 2;
public static final int ERROR_CAMERA_DISABLED = 3;
public static final int ERROR_CAMERA_DEVICE = 4;
public static final int ERROR_CAMERA_SERVICE = 5;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"ERROR_"}, value =
{ERROR_CAMERA_IN_USE,
ERROR_MAX_CAMERAS_IN_USE,
ERROR_CAMERA_DISABLED,
ERROR_CAMERA_DEVICE,
ERROR_CAMERA_SERVICE })
public @interface ErrorCode {};
public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
public void onClosed(@NonNull CameraDevice camera) {
// Default empty implementation
}
public abstract void onDisconnected(@NonNull CameraDevice camera); // Must implement
public abstract void onError(@NonNull CameraDevice camera,
@ErrorCode int error); // Must implement
}
- onOpened回调:
当前camera device已经被打开了,会触发这个回调。探明camera的状态是opened了,这是可以开始createCaptureSession开始使用camera 捕捉图片或者视频了。
触发onOpened回调的地方在setRemoteDevice(...),这个函数在connectDevice(...)连接成功之后执行,表明当前的camera device已经连接成功了,触发camera 能够打开的回调。
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
if (mInError) return;
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
IBinder remoteDeviceBinder = remoteDevice.asBinder();
// For legacy camera device, remoteDevice is in the same process, and
// asBinder returns NULL.
if (remoteDeviceBinder != null) {
try {
remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
} catch (RemoteException e) {
CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"The camera device has encountered a serious error");
}
}
mDeviceExecutor.execute(mCallOnOpened);
mDeviceExecutor.execute(mCallOnUnconfigured);
}
}
private final Runnable mCallOnOpened = new Runnable() {
@Override
public void run() {
StateCallbackKK sessionCallback = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
sessionCallback = mSessionStateCallback;
}
if (sessionCallback != null) {
sessionCallback.onOpened(CameraDeviceImpl.this);
}
mDeviceCallback.onOpened(CameraDeviceImpl.this);
}
};
- onClosed回调:
camera device已经被关闭,这个回调被触发。一般是终端开发者closeCamera的时候会释放当前持有的camera device,这是正常的现象。
public void close() {
synchronized (mInterfaceLock) {
if (mClosing.getAndSet(true)) {
return;
}
if (mRemoteDevice != null) {
mRemoteDevice.disconnect();
mRemoteDevice.unlinkToDeath(this, /*flags*/0);
}
if (mRemoteDevice != null || mInError) {
mDeviceExecutor.execute(mCallOnClosed);
}
mRemoteDevice = null;
}
}
private final Runnable mCallOnClosed = new Runnable() {
private boolean mClosedOnce = false;
@Override
public void run() {
if (mClosedOnce) {
throw new AssertionError("Don't post #onClosed more than once");
}
StateCallbackKK sessionCallback = null;
synchronized(mInterfaceLock) {
sessionCallback = mSessionStateCallback;
}
if (sessionCallback != null) {
sessionCallback.onClosed(CameraDeviceImpl.this);
}
mDeviceCallback.onClosed(CameraDeviceImpl.this);
mClosedOnce = true;
}
};
- onDisconnected回调:
camera device不再可用,打开camera device失败了,一般是因为权限或者安全策略问题导致camera device打不开。一旦连接camera device出现ERROR_CAMERA_DISCONNECTED问题了,这是函数就会被回调,表示当前camera device处于断开的状态。- onError回调:
调用camera device的时候出现了严重的问题。执行CameraService-->connectDevice 出现异常了
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
} else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
// Received one of the known connection errors
// The remote camera device cannot be connected to, so
// set the local camera to the startup error state
deviceImpl.setRemoteFailure(e);
if (e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throwAsPublicException(e);
}
} else {
// Unexpected failure - rethrow
throwAsPublicException(e);
}
} catch (RemoteException e) {
// Camera service died - act as if it's a CAMERA_DISCONNECTED case
ServiceSpecificException sse = new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
deviceImpl.setRemoteFailure(sse);
throwAsPublicException(sse);
}
deviceImpl.setRemoteFailure(e);是执行onError回调的函数。
小结
Camera的知识点非常多,我们从openCamera讲起,也是希望从代码实践中真正了解camera的调用流程,由浅入深的学习camera知识。下面我们会继续讲解连接成功之后,也就是StateCallback-->onOpened回调中camera会如何操作。敬请期待,不足之处,敬请谅解。