Catatan: Halaman ini merujuk ke paket Camera2. Kecuali aplikasi Anda memerlukan fitur tingkat rendah khusus dari Camera2, sebaiknya gunakan CameraX. CameraX dan Camera2 mendukung Android 5.0 (level API 21) dan versi yang lebih baru.
Banyak perangkat Android modern memiliki dua kamera atau lebih di bagian depan, belakang, atau kedua sisi perangkat. Setiap lensa dapat memiliki kemampuan unik, seperti pengambilan burst, kontrol manual, atau pelacakan gerakan. Aplikasi untuk menyetorkan cek mungkin hanya menggunakan kamera belakang pertama, sedangkan aplikasi media sosial mungkin secara default menggunakan kamera depan, tetapi memberi pengguna opsi untuk beralih antar-lensa yang tersedia. Asisten juga dapat mengingat pilihan mereka.
Halaman ini membahas cara membuat daftar lensa kamera dan kemampuannya sehingga Anda dapat membuat keputusan dalam aplikasi tentang lensa yang akan digunakan dalam situasi tertentu. Cuplikan kode berikut mengambil daftar semua kamera dan melakukan iterasi padanya:
Kotlin
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) } ... }
Java
try { String[] cameraIdList = cameraManager.getCameraIdList(); // may be empty // iterate over available camera devices for (String cameraId : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); int cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); int[] cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API boolean isBackwardCompatible = false; for (int capability : cameraCapabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { isBackwardCompatible = true; break; } } ... } } catch (CameraAccessException e) { Log.e(TAG, e.getMessage()); ... }
Variabel cameraLensFacing
menjelaskan arah hadap kamera
relatif terhadap layar perangkat, dan memiliki salah satu dari nilai berikut:
CameraMetadata.LENS_FACING_FRONT
CameraMetadata.LENS_FACING_BACK
CameraMetadata.LENS_FACING_EXTERNAL
Untuk mengetahui informasi selengkapnya tentang konfigurasi hadap lensa, lihat
CameraCharacteristics.LENS_FACING
.
Variabel cameraCapabilities
dari contoh kode sebelumnya berisi
informasi tentang kemampuan lain-lain, termasuk apakah kamera
mampu menghasilkan frame standar sebagai output (bukan, misalnya, hanya
data sensor kedalaman). Anda dapat mencari apakah
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
adalah salah satu kemampuan yang tercantum pada kamera, yang disimpan sebagai flag di
isBackwardCompatible
.
Pilih default yang masuk akal
Di aplikasi, Anda mungkin ingin membuka kamera tertentu secara default (jika tersedia). Misalnya, aplikasi selfie kemungkinan akan membuka kamera depan, sedangkan aplikasi augmented reality mungkin dimulai dengan kamera belakang. Fungsi berikut menampilkan kamera pertama yang menghadap ke arah tertentu:
Kotlin
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) } } }
Java
public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) { if (facing == null) facing = CameraMetadata.LENS_FACING_BACK; String cameraId = null; try { // Get a list of all compatible cameras String[] cameraIdList = cameraManager.getCameraIdList(); // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration and backward compatibility for (String id : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE && characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing)) { cameraId = id; break; } } } // If no camera matches the desired orientation, return the first one from the list cameraId = cameraIdList[0]; } catch (CameraAccessException e) { Log.e(TAG, "getFirstCameraIdFacing: " + e.getMessage()); } return cameraId; }
Aktifkan beralih kamera
Banyak aplikasi kamera memberi pengguna opsi untuk beralih antar-kamera:
![](https://developer.android.com/static/images/training/camera/camera2/camera-enumeration-1.png?authuser=6&hl=id)
Banyak perangkat memiliki beberapa kamera yang menghadap ke arah yang sama. Beberapa bahkan memiliki kamera USB eksternal. Untuk memberi pengguna UI yang memungkinkan mereka beralih antar kamera berbeda, pilih kamera pertama yang tersedia untuk setiap kemungkinan konfigurasi hadap lensa.
Meskipun tidak ada logika universal untuk memilih kamera berikutnya, kode berikut berfungsi untuk sebagian besar kasus penggunaan:
Kotlin
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) } }
Java
public List<String> filterCompatibleCameras(CameraManager cameraManager, String[] cameraIds) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { compatibleCameras.add(id); } } } } catch (CameraAccessException e) { Log.e(TAG, "filterCompatibleCameras: " + e.getMessage()); } return compatibleCameras; } public List<String> filterCameraIdsFacing(CameraManager cameraManager, List<String> cameraIds, int lensFacing) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); if (characteristics.get(CameraCharacteristics.LENS_FACING) == lensFacing) { compatibleCameras.add(id); } } } catch (CameraAccessException e) { Log.e(TAG, "filterCameraIdsFacing: " + e.getMessage()); } return compatibleCameras; } public String getNextCameraId(CameraManager cameraManager, @Nullable String currentCameraId) { String nextCameraId = null; try { // Get all front, back, and external cameras in 3 separate lists List<String> compatibleCameraIds = filterCompatibleCameras(cameraManager, cameraManager.getCameraIdList()); List<String> backCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_BACK); List<String> frontCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_FRONT); List<String>externalCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_EXTERNAL); // The recommended order of iteration is: all external, first back, first front List<String> allCameras = new ArrayList<>(externalCameras); if (!backCameras.isEmpty()) allCameras.add(backCameras.get(0)); if (!frontCameras.isEmpty()) allCameras.add(frontCameras.get(0)); // Get the index of the currently selected camera in the list int cameraIndex = allCameras.indexOf(currentCameraId); // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user if (cameraIndex == -1) { // Return the first camera from the list nextCameraId = !allCameras.isEmpty() ? allCameras.get(0) : null; else { if (!allCameras.isEmpty()) { // Return the next camera from the list, wrap around if necessary nextCameraId = allCameras.get((cameraIndex + 1) % allCameras.size()); } } } catch (CameraAccessException e) { Log.e(TAG, "getNextCameraId: " + e.getMessage()); } return nextCameraId; }
Kode ini berfungsi untuk serangkaian besar perangkat dengan berbagai
konfigurasi. Untuk mengetahui informasi selengkapnya tentang cara memperhitungkan kasus ekstrem, lihat CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
.
Membuat aplikasi yang kompatibel
Untuk aplikasi yang masih menggunakan Camera API yang tidak digunakan lagi, jumlah kamera
yang
ditampilkan oleh Camera.getNumberOfCameras()
bergantung pada implementasi OEM. Jika ada multi-kamera logis dalam
sistem, untuk mempertahankan kompatibilitas mundur aplikasi, metode ini hanya akan menampilkan satu
kamera untuk setiap kamera logis dan grup kamera fisik yang mendasarinya.
Gunakan Camera2 API untuk melihat semua kamera.
Untuk mengetahui informasi latar belakang selengkapnya tentang orientasi kamera, lihat
Camera.CameraInfo.orientation
.
Secara umum, gunakan
Camera.getCameraInfo()
API untuk membuat kueri semua
orientation
kamera,
dan hanya menampilkan satu kamera untuk setiap orientasi yang tersedia kepada pengguna yang
beralih antarkamera.
Mengakomodasi semua jenis perangkat
Jangan berasumsi bahwa aplikasi Anda selalu berjalan di perangkat genggam dengan satu atau dua kamera. Sebagai gantinya, pilih kamera yang paling sesuai untuk aplikasi. Jika Anda tidak memerlukan kamera tertentu, pilih kamera pertama yang menghadap ke arah yang diinginkan. Jika kamera eksternal terhubung, Anda dapat berasumsi bahwa pengguna lebih memilihnya sebagai default.