相機鏡頭和功能

注意:本頁面所述是指 Camera2 套件。除非應用程式需要 Camera2 的特定低階功能,否則建議使用 CameraX。CameraX 和 Camera2 均支援 Android 5.0 (API 級別 21) 以上版本。

許多現代 Android 裝置在正面、背面或兩側都有兩個以上的相機。每個鏡頭都可能有獨特功能,例如連拍、手動控制或動作追蹤。舉例來說,用於存入支票的應用程式可能只會使用第一個後置鏡頭,而社群媒體應用程式可能會預設使用前置鏡頭,但允許使用者在所有可用鏡頭之間切換。也能記住他們的選擇。

本頁面說明如何列出相機鏡頭及其功能,以便您在應用程式中決定在特定情況下要使用哪個鏡頭。下列程式碼片段會擷取所有攝影機的清單,並逐一檢查:

try {
    val cameraIdList = cameraManager.cameraIdList // may be empty

    // iterate over available camera devices.
    for (cameraId in cameraIdList) {
        val characteristics = cameraManager.getCameraCharacteristics(cameraId)
        val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
        val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)

        // check if the selected camera device supports basic features
        // ensures backward compatibility with the original Camera API.
        val isBackwardCompatible = cameraCapabilities?.contains(
            CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
        ) ?: false
        // ...
    }
} catch (e: CameraAccessException) {
    e.message?.let { Log.e(TAG, it) }
    // ...
}

變數 cameraLensFacing 描述相機相對於裝置螢幕的方向,並具有下列其中一個值:

如要進一步瞭解鏡頭朝向設定,請參閱 CameraCharacteristics.LENS_FACING。

上述程式碼範例中的 cameraCapabilities 變數包含各種功能的資訊,包括相機是否能產生標準影格做為輸出內容 (而非僅限深度感應器資料)。您可以查看 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE 是否為攝影機列出的功能之一,該功能會以旗標形式儲存在 isBackwardCompatible 中。

選擇合理的預設值

在應用程式中,您可能希望預設開啟特定相機 (如果可用)。舉例來說,自拍應用程式可能會開啟前置鏡頭,而擴增實境應用程式則可能從後置鏡頭開始。下列函式會傳回第一個朝向指定方向的攝影機:

fun getFirstCameraIdFacing(
    cameraManager: CameraManager,
    facing: Int = CameraMetadata.LENS_FACING_BACK
): String? {
    try {
        // Get list of all compatible cameras.
        val cameraIds = cameraManager.cameraIdList.filter {
            val characteristics = cameraManager.getCameraCharacteristics(it)
            val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
            capabilities?.contains(
                CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
            ) ?: false
        }

        // Iterate over the list of cameras and return the first one matching desired
        // lens-facing configuration.
        cameraIds.forEach {
            val characteristics = cameraManager.getCameraCharacteristics(it)
            if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {
                return it
            }
        }

        // If no camera matched desired orientation, return the first one from the list.
        return cameraIds.firstOrNull()
    } catch (e: CameraAccessException) {
        e.message?.let { Log.e(TAG, it) }
        return null
    }
}

啟用切換相機功能

許多相機應用程式都提供切換相機的選項:

Google 相機應用程式介面,顯示切換相機按鈕。
圖 1 Google 相機應用程式中的切換鏡頭按鈕

許多裝置都有多個朝向相同方向的相機。有些甚至配備外接 USB 攝影機。如要為使用者提供 UI,讓他們切換不同鏡頭方向的相機,請為每個可能的鏡頭方向設定選擇第一個可用的相機。

雖然沒有選擇下一個相機的通用邏輯,但下列程式碼適用於大多數用途:

fun filterCompatibleCameras(
    cameraIds: Array<String>,
    cameraManager: CameraManager
): List<String> {
    return cameraIds.filter {
        val characteristics = cameraManager.getCameraCharacteristics(it)
        characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains(
            CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
        ) ?: false
    }
}

fun filterCameraIdsFacing(
    cameraIds: List<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 = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager)
    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 in 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)
    }
}

這段程式碼適用於多種不同設定的大量裝置。如要進一步瞭解如何處理極端案例,請參閱 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA。

建立相容的應用程式

如果應用程式仍在使用已淘汰的 Camera API,Camera.getNumberOfCameras() 傳回的相機數量取決於原始設備製造商 (OEM) 的實作方式。如果系統中有邏輯多鏡頭,為了維持應用程式的回溯相容性,這個方法只會為每個邏輯相機和基礎實體相機群組提供一個相機。使用 Camera2 API 查看所有相機。

如要進一步瞭解相機方向,請參閱 Camera.CameraInfo.orientation。

一般來說,請使用 Camera.getCameraInfo() API 查詢所有相機 orientation,並在使用者切換相機時,只向他們顯示每個可用方向的一個相機。

支援所有裝置類型

請勿假設應用程式一律在配備一或兩部相機的手持裝置上執行。請改為選擇最適合應用程式的相機。如果您不需要特定相機,請選取朝向所選方向的第一部相機。如果朝向特定方向的相機無法使用,請考慮使用者是否能改用其他相機完成操作。請勿根據相機硬體限制應用程式在特定裝置上的可用性。如果使用者連接了外接相機,可能就會偏好將其設為預設相機。