从 Android P 开始,Android将添加对逻辑多摄像头和 USB 摄像头的支持。这意味着,除了前后两个摄像头外,Android手机的前置或者后置有两个及两个以上的摄像头。对此,对于Android开发者来说,就需要完成这方面的适配工作。
多摄像头
一台设备有多个摄像头没什么新鲜的,但是直到现在,Android 设备仍然最多只有前后两个摄像头。而新出的Android P系统将打破这一常规,今后Android将支持多个摄像头,用户想打开哪个就打开哪个。
在Android P出现之前,我们可以使用如下的一些方法来操作摄像头。
//判断是否存在摄像头
fun hasCameraSupport():Boolean {
return CONTEXT.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)
}
//获取摄像头个数
fun getNumberOfCameras():Int {
if (Build.VERSION.SDK_INT >= 9)
{
return Camera.getNumberOfCameras()
}
else
{
return if (hasCameraSupport()) 1 else 0
}
}
当然,如果想要打开某个摄像头,还可以使用下面的操作。例如,打开第一个摄像头:
val cameraDevice = Camera.open(0)
Camera2
由于兼容性问题,尽管旧的 Camera API 已经被废弃很长时间,上述的代码仍然有效。但是随着生态系统的发展,需要更先进的相机功能。因此,Android 5.0(Lollipop)引进了 Camera2,适用于 API 21 及以上。在Camera2中,我们可以使用下面的方式来打开摄像头。
val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(device: CameraDevice) {
// Do something with `device`
}
override fun onDisconnected(device: CameraDevice) {
device.close()
}
override fun onError(device: CameraDevice, error: Int) {
onDisconnected(device)
}
}, null)
为了正确的打开某个摄像头,我们可以封装一个如下的函数来获取第一个摄像头。
fun getFirstCameraIdFacing(cameraManager: CameraManager,
facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
val cameraIds = cameraManager.cameraIdList
cameraIds.forEach {
val characteristics = cameraManager.getCameraCharacteristics(it)
if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {
return it
}
}
return cameraIds.firstOrNull()
}
当然,很多应用程序还为用户提供切换摄像头的功能,例如Google 相机应用中切换摄像头按钮。
当然,我们可以使用CameraManager.getCameraIdList()获取摄像头列表,然后选择下一个摄像头,但是这并不是个好的方式。因为从 Android P 开始,我们将会看到在同样的情况下更多的设备有多个摄像头,甚至有通过 USB 连接的外部摄像头。如果我们想要提供给用户切换不同摄像头的 UI,建议(按照文档)为每个可能的镜头配置选择第一个可用的摄像头。我们可以使用下面的代码来选择第一个可用的摄像头。
fun filterCameraIdsFacing(cameraIds: Array<String>, cameraManager: CameraManager,
facing: Int): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.LENS_FACING) == facing
}
}
fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? {
// Get all front, back and external cameras in 3 separate lists
val cameraIds = cameraManager.cameraIdList
val backCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK)
val frontCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT)
val externalCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL)
// The recommended order of iteration is: all external, first back, first front
val allCameras = (externalCameras + listOf(
backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull()
// Get the index of the currently selected camera in the list
val cameraIndex = allCameras.indexOf(currCameraId)
// The selected camera may not be on the list, for example it could be an
// external camera that has been removed by the user
return if (cameraIndex == -1) {
// Return the first camera from the list
allCameras.getOrNull(0)
} else {
// Return the next camera from the list, wrap around if necessary
allCameras.getOrNull((cameraIndex + 1) % allCameras.size)
}
}
当然对于废弃的Camera,我们仍然可以使用 Camera.getNumberOfCameras()来获取摄像头的个数。具体的数量取决于 OEM 的具体实现。具体的适配工作可以参考Android P多摄像头API。