Nota: questa pagina si riferisce al pacchetto Camera2. A meno che la tua app non richieda funzionalità specifiche di basso livello di Camera2, ti consigliamo di usare CameraX. Sia CameraX che Camera2 supportano Android 5.0 (livello API 21) e versioni successive.
Molti dispositivi Android moderni hanno due o più fotocamere nella parte anteriore, nella parte posteriore su entrambi i lati del dispositivo. Ogni obiettivo può avere funzionalità uniche, come l'acquisizione a raffica, controllo manuale o rilevamento del movimento. Un'app per il deposito di assegni può usare solo la prima fotocamera posteriore, mentre un'app di social media potrebbe usare per impostazione predefinita fotocamera anteriore, ma offre agli utenti la possibilità di alternare tra tutte le opzioni disponibili lenti. Può anche ricordare le sue scelte.
In questa pagina viene spiegato come elencare gli obiettivi della fotocamera e le loro funzionalità per possono prendere decisioni all'interno dell'app su quale obiettivo usare in una determinata situazione. Lo snippet di codice riportato di seguito recupera un elenco di tutte le telecamere ed esegue l'iterazione quali:
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()); ... }
La variabile cameraLensFacing
descrive la direzione in cui è rivolta la fotocamera
rispetto allo schermo del dispositivo e abbia uno dei seguenti valori:
CameraMetadata.LENS_FACING_FRONT
CameraMetadata.LENS_FACING_BACK
CameraMetadata.LENS_FACING_EXTERNAL
Per ulteriori informazioni sulla configurazione dell'obiettivo, vedi
CameraCharacteristics.LENS_FACING
La variabile cameraCapabilities
dell'esempio di codice precedente contiene
informazioni su funzionalità varie, ad esempio se la fotocamera è
in grado di produrre frame standard come output (a differenza, ad esempio,
dati del sensore di profondità). Puoi verificare se
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
è una delle funzionalità elencate della videocamera, che viene memorizzata sotto forma di flag
isBackwardCompatible
.
Scegli valori predefiniti appropriati
Nella tua app, probabilmente vuoi aprire una videocamera specifica per impostazione predefinita (se disponibile). Ad esempio, un'app per selfie probabilmente apre la parte anteriore fotocamera, mentre un'app di realtà aumentata potrebbe avviarsi con la fotocamera posteriore. La seguente funzione restituisce la prima videocamera rivolta verso una determinata direzione:
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; }
Attiva il passaggio da una fotocamera all'altra
Molte app per fotocamera offrono agli utenti la possibilità di passare da una fotocamera all'altra:
Molti dispositivi hanno diverse fotocamere rivolte nella stessa direzione. Alcuni hanno anche fotocamere USB esterne. Offrire agli utenti una UI che permetta loro di passare da un'esperienza all'altra fotocamere frontali diverse, scegli la prima videocamera disponibile per ognuna dell'obiettivo.
Sebbene non esista una logica universale per la selezione della prossima videocamera, la il seguente codice funziona per la maggior parte dei casi d'uso:
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; }
Questo codice funziona per un gran numero di dispositivi con molti
configurazioni. Per saperne di più sulla contabilizzazione dei casi limite, consulta CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
.
Crea app compatibili
Per le app che utilizzano ancora l'API Fotocamera deprecata, il numero di fotocamere
che
Camera.getNumberOfCameras()
i resi dipendono dall'implementazione dell'OEM. Se è presente una funzione multicamera logica
di sistema, per mantenere la compatibilità con le versioni precedenti dell'app, questo metodo espone solo
videocamera per ogni videocamera logica e gruppo di videocamere fisiche sottostanti.
Utilizza l'API Camera2 per visualizzare tutte le fotocamere.
Per ulteriori informazioni di base sugli orientamenti della fotocamera, vedi
Camera.CameraInfo.orientation
In generale, utilizza la classe
Camera.getCameraInfo()
API per eseguire query su tutte le videocamere
orientation
ed esporre una sola videocamera per ogni orientamento disponibile agli utenti che
passando da una videocamera all'altra.
Supporta tutti i tipi di dispositivi
Non dare per scontato che la tua app venga sempre eseguita su un dispositivo portatile con uno o due videocamere. Scegli invece le fotocamere più appropriate per l'app. Se non occorre una videocamera specifica, seleziona la prima videocamera rivolta verso il dispositivo desiderato . Se è collegata una videocamera esterna, potresti presumere che l'utente lo preferisce come predefinito.