Anteprima fotocamera

Nota: questa pagina fa riferimento al pacchetto Fotocamera2. A meno che la tua app non richieda funzionalità specifiche di basso livello di Fotocamera2, ti consigliamo di utilizzare FotocameraX. Sia CameraX che Camera2 supportano Android 5.0 (livello API 21) e versioni successive.

Le videocamere e le anteprime delle fotocamere non sono sempre nello stesso orientamento sui dispositivi Android.

Una fotocamera è fissata in posizione fissa su un dispositivo, che sia un telefono, un tablet o un computer. Se l'orientamento del dispositivo cambia, la fotocamera cambia.

Di conseguenza, in genere le app della fotocamera presuppongono una relazione fissa tra l'orientamento del dispositivo e le proporzioni dell'anteprima della fotocamera. Quando l'orientamento del telefono è verticale, si presume che l'anteprima della fotocamera sia più alta che larga. Quando il telefono e la fotocamera vengono ruotati in orizzontale, l'anteprima della fotocamera deve essere più larga che alta.

Tuttavia, queste ipotesi sono messe in discussione da nuovi fattori di forma, come i dispositivi pieghevoli e le modalità di visualizzazione come multi-finestra e multi-display. I dispositivi pieghevoli cambiano le dimensioni del display e le proporzioni senza cambiare l'orientamento. La modalità multi-finestra vincola le app della fotocamera a una parte dello schermo, ridimensionando l'anteprima della fotocamera indipendentemente dall'orientamento del dispositivo. La modalità di visualizzazione multipla consente di utilizzare display secondari che potrebbero non avere lo stesso orientamento del display principale.

Orientamento della fotocamera

La definizione di compatibilità Android specifica che il sensore fotografico di una fotocamera "DEVE essere orientato in modo che la dimensione lunga della fotocamera sia allineata a quella dello schermo. In altre parole, quando il dispositivo viene tenuto in orientamento orizzontale, le videocamere DEVONO acquisire immagini con l'orientamento orizzontale. Questo vale indipendentemente dall'orientamento naturale del dispositivo, vale a dire che si applica sia ai dispositivi principali in modalità orizzontale sia a quelli principali in modalità verticale.

La disposizione della fotocamera sullo schermo massimizza l'area di visualizzazione del mirino della fotocamera in un'app della fotocamera. Inoltre, i sensori di immagine in genere emettono i dati in proporzioni orizzontali, con il formato 4:3 il più comune.

Sensore della fotocamera e del telefono entrambi in orientamento verticale.
Figura 1. Tipico rapporto tra l'orientamento del sensore e quello dello smartphone.

L'orientamento naturale del sensore della fotocamera è orizzontale. Nella Figura 1, il sensore della fotocamera anteriore (la fotocamera che punta nella stessa direzione del display) viene ruotato di 270 gradi rispetto al telefono per rispettare la definizione di compatibilità Android.

Per esporre la rotazione del sensore alle app, l'API camera2 include una costante SENSOR_ORIENTATION. Per la maggior parte degli smartphone e dei tablet, il dispositivo segnala un orientamento del sensore di 270 gradi per le fotocamere anteriori e di 90 gradi (punto di vista dal retro del dispositivo) per le fotocamere posteriori, che allinea il bordo lungo del sensore al bordo lungo del dispositivo. Le fotocamere dei laptop segnalano in genere un orientamento del sensore di 0 o 180 gradi.

Poiché i sensori di immagine della fotocamera emettono i propri dati (un buffer di immagine) nell'orientamento naturale del sensore (orizzontale), il buffer di immagine deve essere ruotato del numero di gradi specificato da SENSOR_ORIENTATION affinché l'anteprima della fotocamera venga visualizzata in posizione verticale nell'orientamento naturale del dispositivo. Per le fotocamere frontali, la rotazione è in senso antiorario, per quella posteriore, in senso orario.

Ad esempio, per la fotocamera anteriore nella figura 1, il buffer di immagine prodotto dal sensore della fotocamera ha il seguente aspetto:

Sensore della videocamera ruotato in orientamento orizzontale con immagine
            lateralmente, in alto a sinistra.

L'immagine deve essere ruotata di 270 gradi in senso antiorario per far sì che l'orientamento dell'anteprima corrisponda a quello del dispositivo:

Sensore della fotocamera in orientamento verticale con l'immagine rivolta verso l'alto.

Una fotocamera posteriore produce un buffer immagine con lo stesso orientamento del buffer riportato sopra, ma SENSOR_ORIENTATION è di 90 gradi. Di conseguenza, il buffer viene ruotato di 90 gradi in senso orario.

Rotazione del dispositivo

La rotazione del dispositivo equivale al numero di gradi di rotazione di un dispositivo rispetto al suo orientamento naturale. Ad esempio, un telefono con orientamento orizzontale ha una rotazione del dispositivo di 90 o 270 gradi, a seconda della direzione di rotazione.

Il buffer dell'immagine del sensore della fotocamera deve essere ruotato dello stesso numero di gradi della rotazione del dispositivo (oltre ai gradi dell'orientamento del sensore) affinché l'anteprima della videocamera venga visualizzata in posizione verticale.

Calcolo dell'orientamento

L'orientamento corretto dell'anteprima della fotocamera tiene conto dell'orientamento del sensore e della rotazione del dispositivo.

La rotazione complessiva del buffer di immagine del sensore può essere calcolata utilizzando la seguente formula:

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

dove sign è 1 per le fotocamere anteriori, -1 per le fotocamere posteriori.

Per le fotocamere anteriori, il buffer dell'immagine viene ruotato in senso antiorario (rispetto all'orientamento naturale del sensore). Per le fotocamere posteriori, il buffer dell'immagine del sensore viene ruotato in senso orario.

L'espressione deviceOrientationDegrees * sign + 360 converte la rotazione del dispositivo da senso antiorario a senso orario per le fotocamere posteriori (ad esempio convertendo 270 gradi in senso antiorario in 90 gradi in senso orario). L'operazione modulo scala il risultato a meno di 360 gradi (ad esempio, scalando 540 gradi di rotazione a 180).

API diverse segnalano la rotazione del dispositivo in modo diverso:

  • Display#getRotation() consente di ruotare il dispositivo in senso antiorario (dal punto di vista dell'utente). Questo valore si inserisce nella formula precedente così com'è.
  • OrientationEventListener#onOrientationChanged() restituisce la rotazione in senso orario del dispositivo (dal punto di vista dell'utente). Negare il valore da utilizzare nella formula precedente.

Fotocamere frontali

L'anteprima della fotocamera e il sensore sono entrambi in orientamento orizzontale, con il sensore rivolto verso l'alto.
Figura 2. Anteprima della fotocamera e sensore con il telefono in posizione orizzontale di 90 gradi.

Ecco il buffer immagine prodotto dal sensore della fotocamera nella Figura 2:

Sensore della fotocamera in orientamento orizzontale con l'immagine rivolta verso l'alto.

Il buffer deve essere ruotato di 270 gradi in senso antiorario per regolare l'orientamento del sensore (vedi Orientamento della fotocamera qui sopra):

Sensore della videocamera ruotato in orientamento verticale con l'immagine ruotata
            in alto a destra.

Quindi, il buffer viene ruotato di altri 90 gradi in senso antiorario per tenere conto della rotazione del dispositivo e ottenere così l'orientamento corretto dell'anteprima della videocamera nella figura 2:

Sensore della fotocamera ruotato in orientamento orizzontale con l'immagine
            rivolta verso l'alto.

Ecco la videocamera orientata verso destra in orientamento orizzontale:

L'anteprima della fotocamera e il sensore sono entrambi in orientamento orizzontale, ma il sensore è capovolto.
Figura 3. Anteprima della fotocamera e sensore con il telefono in posizione orizzontale di 270 gradi (o -90 gradi).

Ecco il buffer immagine:

Sensore della videocamera ruotato in orientamento orizzontale con l'immagine capovolta.

Il buffer deve essere ruotato di 270 gradi in senso antiorario per regolare l'orientamento del sensore:

Sensore della fotocamera classificato come orientamento verticale con immagine ruotata lateralmente, in alto a sinistra.

Quindi il buffer viene ruotato di altri 270 gradi in senso antiorario per tenere conto della rotazione del dispositivo:

Sensore della fotocamera ruotato in orientamento orizzontale con l'immagine
            rivolta verso l'alto.

Fotocamere posteriori

Le fotocamere posteriori in genere hanno un orientamento del sensore di 90 gradi (visto dal retro del dispositivo). Quando orienta l'anteprima della fotocamera, il buffer immagine del sensore viene ruotato in senso orario in base alla quantità di rotazione del sensore (anziché in senso antiorario come per le fotocamere frontali), quindi il buffer immagine viene ruotato in senso antiorario della quantità di rotazione del dispositivo.

L'anteprima della fotocamera e il sensore sono entrambi in orientamento orizzontale, ma il sensore è capovolto.
Figura 4. Telefono con fotocamera posteriore in orientamento orizzontale (270 gradi o -90 gradi).

Ecco il buffer immagine del sensore della fotocamera nella Figura 4:

Sensore della videocamera ruotato in orientamento orizzontale con l'immagine capovolta.

Il buffer deve essere ruotato di 90 gradi in senso orario per regolare l'orientamento del sensore:

Sensore della fotocamera classificato come orientamento verticale con immagine ruotata lateralmente, in alto a sinistra.

Quindi il buffer viene ruotato di 270 gradi in senso antiorario per tenere conto della rotazione del dispositivo:

Sensore della fotocamera ruotato in orientamento orizzontale con l'immagine
            rivolta verso l'alto.

Proporzioni

Le proporzioni del display cambiano quando cambia l'orientamento del dispositivo, ma anche quando gli elementi pieghevoli vengono piegati e aperti, quando le finestre vengono ridimensionate in ambienti multi-finestra e quando le app si aprono su display secondari.

Il buffer immagine del sensore della fotocamera deve essere orientato e ridimensionato in modo che corrisponda all'orientamento e alle proporzioni dell'elemento UI del mirino quando l'interfaccia utente cambia dinamicamente l'orientamento, con o senza che l'orientamento del dispositivo cambi.

Nei nuovi fattori di forma o in ambienti multi-finestra o multi-display, se l'app presuppone che l'anteprima della fotocamera abbia lo stesso orientamento del dispositivo (orizzontale o verticale), l'orientamento potrebbe essere orientato in modo errato, ridimensionato in modo errato o entrambi.

Dispositivo pieghevole aperto con anteprima della fotocamera verticale ruotata.
Figura 5. Il dispositivo pieghevole passa dalle proporzioni da verticale a orizzontale, ma il sensore della fotocamera rimane in orientamento verticale.

Nella Figura 5, l'applicazione presumeva erroneamente che il dispositivo fosse ruotato di 90 gradi in senso antiorario e, pertanto, l'app ha ruotato l'anteprima dello stesso numero.

Dispositivo pieghevole aperto con l'anteprima della fotocamera rivolta verso l'alto, ma compresso a causa del ridimensionamento non corretto.
Figura 6. Il dispositivo pieghevole passa dalle proporzioni da verticale a orizzontale, ma il sensore della fotocamera rimane in orientamento verticale.

Nella Figura 6, l'app non regolava le proporzioni del buffer dell'immagine per adattarlo correttamente alle nuove dimensioni dell'elemento UI di anteprima della fotocamera.

Le app della fotocamera con orientamento fisso in genere riscontrano problemi sui pieghevoli e su altri dispositivi con schermi di grandi dimensioni come i laptop:

L'anteprima della fotocamera sul laptop è in posizione verticale, ma l'interfaccia utente dell'app è ruotata.
Figura 7. App verticale con orientamento fisso su laptop.

Nella Figura 7, l'interfaccia utente dell'app Fotocamera è ruotata perché l'orientamento è limitato solo alla modalità verticale. L'immagine del mirino deve essere orientata correttamente rispetto al sensore della fotocamera.

Modalità verticale integrata

Le app della fotocamera che non supportano la modalità multi-finestra (resizeableActivity="false") e ne limitano l'orientamento (screenOrientation="portrait" o screenOrientation="landscape") possono essere inserite in modalità verticale integrata sui dispositivi con schermo grande per orientare correttamente l'anteprima della fotocamera.

App letterbox (inset) verticali integrate in modalità verticale con orientamento verticale anche se le proporzioni del display sono orizzontali. Le app solo in formato orizzontale hanno letterbox in orientamento orizzontale anche se le proporzioni del display sono verticali. L'immagine della fotocamera viene ruotata per allinearsi all'interfaccia utente dell'app, ritagliata per rispettare le proporzioni dell'anteprima della fotocamera e poi ridimensionata per riempire l'anteprima.

La modalità verticale integrata viene attivata quando le proporzioni del sensore di immagine della fotocamera e le proporzioni dell'attività principale dell'applicazione non corrispondono.

Anteprima della fotocamera e UI dell'app con orientamento verticale corretto sul laptop.
            L'immagine di anteprima larga viene ridimensionata e ritagliata per adattarla all'orientamento verticale.
Figura 8. App verticale con orientamento fisso in modalità verticale integrata su laptop.

Nella figura 8, l'app della fotocamera solo verticale è stata ruotata per mostrare l'interfaccia utente in posizione verticale sul display del laptop. Le proporzioni dell'app sono ridotte a causa delle diverse proporzioni tra l'app verticale e la visualizzazione orizzontale. L'immagine di anteprima della fotocamera è stata ruotata per compensare la rotazione dell'interfaccia utente dell'app (a causa della modalità verticale integrata) e l'immagine è stata ritagliata e ridimensionata per adattarsi all'orientamento verticale, riducendo il campo visivo.

Ruota, ritaglia, ridimensiona

La modalità Ritratto integrato viene richiamata per un'app con fotocamera solo verticale su un display con proporzioni orizzontali:

L'anteprima della fotocamera sul laptop è in posizione verticale, ma l'interfaccia utente dell'app è ruotata.
Figura 9. App verticale con orientamento fisso su laptop.

All'interno dell'app è applicato il letterbox in orientamento verticale:

App ruotata in orientamento verticale e letterbox. L'immagine è ruotata lateralmente, in alto a destra.

L'immagine della fotocamera viene ruotata di 90 gradi per adattarsi al riorientamento dell'app:

Immagine del sensore ruotata di 90 gradi per essere dritta.

L'immagine viene ritagliata in base alle proporzioni dell'anteprima della fotocamera, quindi ridimensionata per riempire l'anteprima (campo visivo ridotto):

Immagine ritagliata della fotocamera ridimensionata per riempire l'anteprima della fotocamera.

Sui dispositivi pieghevoli, l'orientamento del sensore della fotocamera può essere verticale, mentre le proporzioni del display sono orizzontali:

Anteprima della fotocamera e UI dell'app ruotata lateralmente rispetto a un ampio display aperto.
Figura 10. Dispositivo aperto con app della fotocamera solo verticale e diverse proporzioni del sensore e del display della fotocamera.

Poiché l'anteprima della fotocamera viene ruotata in base all'orientamento del sensore, l'immagine è orientata correttamente nel mirino, ma l'app solo verticale è posizionata lateralmente.

Per orientare correttamente l'app e l'anteprima della fotocamera, la modalità verticale integrata deve essere adatta solo all'orientamento verticale.

App in formato letterbox con orientamento verticale con anteprima della fotocamera in verticale su un dispositivo pieghevole.

API

A partire da Android 12 (livello API 31) le app possono anche controllare esplicitamente la modalità verticale integrata tramite la proprietà SCALER_ROTATE_AND_CROP della classe CaptureRequest.

Il valore predefinito è SCALER_ROTATE_AND_CROP_AUTO, che consente al sistema di richiamare la modalità verticale integrata. SCALER_ROTATE_AND_CROP_90 è il comportamento della modalità verticale integrata come descritto sopra.

Non tutti i dispositivi supportano tutti i valori SCALER_ROTATE_AND_CROP. Per ottenere un elenco dei valori supportati, fai riferimento a CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

FotocameraX

Con la libreria Jetpack CameraX, creare un mirino per fotocamera in grado di adattarsi all'orientamento del sensore e alla rotazione del dispositivo è un'operazione semplice.

L'elemento di layout PreviewView crea un'anteprima della fotocamera, regolando automaticamente l'orientamento del sensore, la rotazione del dispositivo e la scalabilità. PreviewView mantiene le proporzioni dell'immagine della fotocamera applicando il tipo di scala FILL_CENTER, che consente di centrare l'immagine, ma potrebbe ritagliarla in modo che corrisponda alle dimensioni di PreviewView. Per modificare le dimensioni dell'immagine della fotocamera, imposta il tipo di scala su FIT_CENTER.

Per apprendere le nozioni di base sulla creazione di un'anteprima della fotocamera con PreviewView, consulta Implementare un'anteprima.

Per un'implementazione di esempio completa, consulta il repository CameraXBasic su GitHub.

Mirino fotocamera

Analogamente al caso d'uso Anteprima, la libreria FotocameraViewfinder offre una serie di strumenti per semplificare la creazione di un'anteprima della fotocamera. Non dipende da CameraX Core, quindi puoi integrarlo perfettamente nel codebase di Camera2 esistente.

Anziché utilizzare direttamente Surface puoi usare il widget CameraViewfinder per visualizzare il feed videocamera per Fotocamera2.

CameraViewfinder usa internamente un TextureView o un SurfaceView per visualizzare il feed della videocamera e applica le trasformazioni richieste per visualizzare correttamente il mirino. Ciò comporta la correzione delle proporzioni, della scala e della rotazione.

Per richiedere la superficie dall'oggetto CameraViewfinder, devi creare un elemento ViewfinderSurfaceRequest.

Questa richiesta contiene i requisiti per le informazioni sulla risoluzione della superficie e sul dispositivo della fotocamera di CameraCharacteristics.

La chiamata a requestSurfaceAsync() invia la richiesta al provider della piattaforma, che è TextureView o SurfaceView e ottiene ListenableFuture di Surface.

La chiamata a markSurfaceSafeToRelease() comunica al provider della piattaforma che la piattaforma non è necessaria e che è possibile rilasciare le risorse correlate.

Kotlin


fun startCamera(){
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */}
    }, ContextCompat.getMainExecutor(context))
}

Java


    void startCamera(){
        Size previewResolution = new Size(width, height);
        ViewfinderSurfaceRequest viewfinderSurfaceRequest =
                new ViewfinderSurfaceRequest(previewResolution, characteristics);
        ListenableFuture<Surface> surfaceListenableFuture =
                cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest);

        Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() {
            @Override
            public void onSuccess(Surface result) {
                /* create a CaptureSession using this surface as usual */
            }
            @Override public void onFailure(Throwable t) { /* something went wrong */}
        },  ContextCompat.getMainExecutor(context));
    }

Visualizzazione superficie

SurfaceView è un approccio semplice per creare un'anteprima della fotocamera se l'anteprima non richiede elaborazione e non è animata.

SurfaceView ruota automaticamente il buffer dell'immagine del sensore della fotocamera in base all'orientamento di visualizzazione, tenendo conto sia dell'orientamento del sensore che della rotazione del dispositivo. Tuttavia, il buffer dell'immagine viene ridimensionato per adattarsi alle dimensioni SurfaceView senza tenere conto delle proporzioni.

Devi assicurarti che le proporzioni del buffer dell'immagine corrispondano a quelle di SurfaceView, operazione che puoi eseguire scalando i contenuti di SurfaceView nel metodo onMeasure() del componente:

(Il codice sorgente di computeRelativeRotation() si trova nella sezione Rotazione relativa di seguito).

Kotlin

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Java

@Override
void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees);

    if (previewWidth > 0f && previewHeight > 0f) {

        /* Scale factor required to scale the preview to its original size on the x-axis. */
        float scaleX = (relativeRotation % 180 == 0)
                       ? (float) width / previewWidth
                       : (float) width / previewHeight;

        /* Scale factor required to scale the preview to its original size on the y-axis. */
        float scaleY = (relativeRotation % 180 == 0)
                       ? (float) height / previewHeight
                       : (float) height / previewWidth;

        /* Scale factor required to fit the preview to the SurfaceView size. */
        float finalScale = Math.min(scaleX, scaleY);

        setScaleX(1 / scaleX * finalScale);
        setScaleY(1 / scaleY * finalScale);
    }
    setMeasuredDimension(width, height);
}

Per maggiori dettagli sull'implementazione di SurfaceView come anteprima della fotocamera, consulta Orientamenti della fotocamera.

Visualizzazione texture

Le prestazioni di TextureView sono inferiori rispetto a SurfaceView e molto altro ancora, ma TextureView ti offre il massimo controllo sull'anteprima della fotocamera.

TextureView ruota il buffer dell'immagine del sensore in base all'orientamento del sensore, ma non gestisce la rotazione del dispositivo o il ridimensionamento dell'anteprima.

La scalabilità e la rotazione possono essere codificate in una trasformazione Matrice. Per informazioni su come ridimensionare e ruotare correttamente una TextureView, consulta la sezione Supportare le superfici ridimensionabili nell'app Fotocamera

Rotazione relativa

La rotazione relativa del sensore della videocamera è la quantità di rotazione necessaria per allineare l'uscita del sensore della videocamera all'orientamento del dispositivo.

La rotazione relativa viene utilizzata da componenti quali SurfaceView e TextureView per determinare i fattori di ridimensionamento x e y dell'immagine di anteprima. Viene utilizzato anche per specificare la rotazione del buffer dell'immagine del sensore.

Le classi CameraCharacteristics e Surface consentono di calcolare la rotazione relativa del sensore della videocamera:

Kotlin

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Java

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public int computeRelativeRotation(
    CameraCharacteristics characteristics,
    int surfaceRotationDegrees
){
    Integer sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Reverse device orientation for back-facing cameras.
    int sign = characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1;

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360;
}

Metriche finestra

Le dimensioni dello schermo non devono essere utilizzate per determinare le dimensioni del mirino della fotocamera; l'app Fotocamera potrebbe essere in esecuzione in una parte dello schermo, in modalità multi-finestra sui dispositivi mobili o in modalità libera su ChromeOS.

WindowManager#getCurrentWindowMetrics() (aggiunto nel livello API 30) restituisce le dimensioni della finestra dell'applicazione anziché le dimensioni dello schermo. I metodi della libreria Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() e WindowInfoTracker#currentWindowMetrics() forniscono un supporto simile con compatibilità con le versioni precedenti al livello API 14.

Rotazione: 180°

Una rotazione di 180 gradi di un dispositivo (ad esempio, da orientamento naturale a orientamento naturale capovolto) non attiva il callback onConfigurationChanged(). Di conseguenza, l'anteprima della fotocamera potrebbe essere capovolta.

Per rilevare una rotazione di 180 gradi, implementa un elemento DisplayListener e controlla la rotazione del dispositivo con una chiamata a Display#getRotation() nel callback onDisplayChanged().

Risorse esclusive

Prima di Android 10, solo l'attività visibile più in alto in un ambiente multi-finestra era nello stato RESUMED. Questo creava confusione per gli utenti, perché il sistema non forniva alcuna indicazione su quale attività fosse stata ripresa.

È stato introdotto il ripristino multiplo in Android 10 (livello API 29) quando tutte le attività visibili sono nello stato RESUMED. Le attività visibili possono comunque entrare nello stato PAUSED se, ad esempio, sopra l'attività è presente un'attività trasparente o non è possibile impostare lo stato attivo, come in modalità Picture in picture (consulta la sezione Supporto di Picture in picture).

Un'applicazione che utilizza la fotocamera, il microfono o qualsiasi risorsa esclusiva o singleton con livello API 29 o successivo deve supportare la ripresa multipla. Ad esempio, se tre attività riprese vogliono utilizzare la videocamera, solo una potrà accedere a questa risorsa esclusiva. Ogni attività deve implementare un callback di onDisconnected() per essere a conoscenza dell'accesso preventivo alla videocamera da parte di un'attività con priorità più elevata.

Per maggiori informazioni, consulta Ripresa multipla.

Risorse aggiuntive