Nota: questa pagina fa riferimento al pacchetto Camera2. A meno che la tua app non richieda funzionalità specifiche di basso livello di Camera2, ti consigliamo di utilizzare CameraX. Sia CameraX che Camera2 supportano Android 5.0 (livello API 21) e versioni successive.
Molti dispositivi Android moderni hanno due o più fotocamere sulla parte anteriore, posteriore o su entrambi i lati del dispositivo. Ogni obiettivo può avere funzionalità uniche, come l'acquisizione a raffica, il controllo manuale o il rilevamento del movimento. Un'app per il deposito di assegni potrebbe utilizzare solo la prima fotocamera posteriore, mentre un'app di social media potrebbe utilizzare per impostazione predefinita una fotocamera anteriore, ma offrire agli utenti la possibilità di passare da un obiettivo all'altro tra quelli disponibili. Può anche ricordare le loro scelte.
Questa pagina spiega come elencare gli obiettivi della fotocamera e le relative funzionalità in modo da poter prendere decisioni all'interno dell'app su quale obiettivo utilizzare in una determinata situazione. Il seguente snippet di codice recupera un elenco di tutte le videocamere e ne esegue l'iterazione:
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) } // ... }
La variabile cameraLensFacing descrive la direzione in cui è rivolta la fotocamera
rispetto allo schermo del dispositivo e ha uno dei seguenti valori:
CameraMetadata.LENS_FACING_FRONTCameraMetadata.LENS_FACING_BACKCameraMetadata.LENS_FACING_EXTERNAL
Per saperne di più sulla configurazione della direzione dell'obiettivo, consulta
CameraCharacteristics.LENS_FACING.
La variabile cameraCapabilities dell'esempio di codice precedente contiene informazioni su varie funzionalità, tra cui se la fotocamera è in grado di produrre frame standard come output (anziché, ad esempio, solo dati dei sensori di profondità). Puoi verificare se
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
è una delle funzionalità elencate della fotocamera, che viene memorizzata come flag in
isBackwardCompatible.
Scegli valori predefiniti ragionevoli
Nella tua app, probabilmente vorrai aprire una videocamera specifica per impostazione predefinita (se disponibile). Ad esempio, un'app per selfie probabilmente apre la fotocamera anteriore, mentre un'app di realtà aumentata potrebbe avviarsi con la fotocamera posteriore. La seguente funzione restituisce la prima videocamera rivolta in una determinata direzione:
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 } }
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 più fotocamere rivolte nella stessa direzione. Alcuni hanno anche videocamere USB esterne. Per fornire agli utenti una UI che consenta loro di passare da una fotocamera all'altra, scegli la prima fotocamera disponibile per ogni possibile configurazione di orientamento dell'obiettivo.
Sebbene non esista una logica universale per la selezione della fotocamera successiva, il seguente codice funziona per la maggior parte dei casi d'uso:
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) } }
Questo codice funziona per un ampio insieme di dispositivi con molte configurazioni diverse. Per saperne di più sulla gestione dei casi limite, consulta
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA.
Crea app compatibili
Per le app che utilizzano ancora l'API Camera deprecata, il numero di fotocamere restituite da Camera.getNumberOfCameras() dipende dall'implementazione dell'OEM. Se nel sistema è presente una videocamera multipla logica, per mantenere la compatibilità con le versioni precedenti dell'app, questo metodo esporrà una sola videocamera per ogni videocamera logica e gruppo di videocamere fisiche sottostanti. Utilizza l'API Camera2 per visualizzare tutte le fotocamere.
Per ulteriori informazioni sugli orientamenti della videocamera, consulta
Camera.CameraInfo.orientation.
In generale, utilizza l'API Camera.getCameraInfo() per eseguire query su tutte le orientation della fotocamera ed esponi una sola fotocamera per ogni orientamento disponibile agli utenti che passano da una fotocamera all'altra.
Adattarsi a tutti i tipi di dispositivi
Non dare per scontato che la tua app venga sempre eseguita su un dispositivo palmare con una o due fotocamere. Scegli invece le fotocamere più appropriate per l'app. Se non hai bisogno di una fotocamera specifica, seleziona la prima fotocamera rivolta nella direzione scelta. Se la videocamera rivolta in una determinata direzione non è disponibile, valuta se l'utente può completare il percorso con un'altra videocamera. Non limitare la disponibilità della tua app su determinati dispositivi in base all'hardware della fotocamera. Se è collegata una fotocamera esterna, l'utente probabilmente preferisce utilizzarla come predefinita.