Aperçu de l'appareil photo

Remarque:Cette page fait référence au package Camera2. Sauf si votre application nécessite des fonctionnalités spécifiques de bas niveau de Camera2, nous vous recommandons d'utiliser CameraX. CameraX et Camera2 sont compatibles avec Android 5.0 (niveau d'API 21) ou version ultérieure.

Les appareils photo et leurs aperçus ne sont pas toujours dans la même orientation sur les appareils Android.

La position d'une caméra est fixe sur un appareil, qu'il s'agisse d'un téléphone, d'une tablette ou d'un ordinateur. Lorsque l'orientation de l'appareil change, l'orientation de la caméra change.

Par conséquent, les applications d'appareil photo supposent généralement qu'il existe une relation fixe entre l'orientation de l'appareil et le format de l'aperçu de l'appareil photo. Lorsqu'un téléphone est en mode portrait, l'aperçu de l'appareil photo est considéré comme plus grand que large. Lorsque vous faites pivoter le téléphone (et l'appareil photo) en mode paysage, l'aperçu de l'appareil photo doit être plus large que haut.

Mais ces hypothèses sont remises en question par de nouveaux facteurs de forme, tels que les appareils pliables, et les modes d'affichage tels que le mode multifenêtre et le mode multi-écran. Les appareils pliables modifient la taille d'affichage et le format sans modifier l'orientation. Le mode multifenêtre limite les applications d'appareil photo à une partie de l'écran, en redimensionnant l'aperçu de l'appareil photo quelle que soit l'orientation de l'appareil. Le mode multi-écran permet d'utiliser des écrans secondaires qui peuvent ne pas être dans la même orientation que l'écran principal.

Orientation de l'appareil photo

La Définition de compatibilité Android spécifie qu'un capteur d'image d'appareil photo "DOIT être orienté de sorte que la dimension longue de l'appareil photo s'aligne sur la dimension longue de l'écran. Autrement dit, lorsque l'appareil est tenu en mode paysage, les appareils photo DOIVENT capturer des images en mode paysage. Cela s'applique quelle que soit l'orientation naturelle de l'appareil, c'est-à-dire qu'elle s'applique aux appareils principaux en mode paysage ainsi qu'aux appareils en mode portrait.

La disposition de l'appareil photo sur l'écran maximise la zone d'affichage du viseur de l'appareil photo dans une application d'appareil photo. De plus, les capteurs d'image génèrent généralement leurs données au format paysage, 4:3 étant le format le plus courant.

Téléphone et capteur de l'appareil photo en mode portrait.
Image 1. Relation habituelle entre l'orientation du téléphone et du capteur de l'appareil photo.

L'orientation naturelle du capteur de l'appareil photo est le mode paysage. Dans la figure 1, le capteur de la caméra avant (celle orientée dans la même direction que l'écran) fait pivoter le capteur de 270 degrés par rapport au téléphone afin de respecter la définition de compatibilité Android.

Pour exposer la rotation des capteurs aux applications, l'API camera2 inclut une constante SENSOR_ORIENTATION. Pour la plupart des téléphones et des tablettes, l'appareil signale une orientation de capteur de 270 degrés pour les caméras avant et de 90 degrés (point de vue depuis l'arrière de l'appareil) pour les caméras arrière, ce qui aligne le bord long du capteur sur le bord long de l'appareil. Les caméras des ordinateurs portables signalent généralement une orientation de capteur de 0 ou 180 degrés.

Étant donné que les capteurs d'image de l'appareil photo envoient leurs données (tampon d'image) dans l'orientation naturelle du capteur (paysage), le tampon d'image doit faire l'objet d'une rotation selon le nombre de degrés spécifié par SENSOR_ORIENTATION pour que l'aperçu de l'appareil photo apparaisse à la verticale dans l'orientation naturelle de l'appareil. Pour les caméras avant, la rotation est dans le sens inverse des aiguilles d'une montre. Pour les caméras arrière, dans le sens des aiguilles d'une montre.

Par exemple, pour la caméra frontale de la figure 1, le tampon d'image produit par le capteur de l'appareil photo se présente comme suit:

Capteur de l'appareil photo orienté en mode paysage avec l'image latéralement, en haut à gauche.

Vous devez faire pivoter l'image de 270 degrés dans le sens inverse des aiguilles d'une montre pour que l'orientation de l'aperçu corresponde à celle de l'appareil:

Capteur de l'appareil photo en mode portrait avec l'image dans le bon sens.

Une caméra arrière générerait un tampon d'image avec la même orientation que le tampon ci-dessus, mais SENSOR_ORIENTATION est de 90 degrés. En conséquence, le tampon est pivoté de 90 degrés dans le sens des aiguilles d'une montre.

Rotation de l'appareil

La rotation de l'appareil correspond au nombre de degrés de rotation d'un appareil par rapport à son orientation naturelle. Par exemple, un téléphone en mode paysage a une rotation de l'appareil de 90 ou 270 degrés, selon le sens de rotation.

Le tampon d'image d'un capteur d'appareil photo doit faire l'objet d'une rotation du même nombre de degrés que la rotation de l'appareil (en plus des degrés d'orientation du capteur) pour que l'aperçu de l'appareil photo s'affiche à la verticale.

Calcul de l'orientation

L'orientation correcte de l'aperçu de l'appareil photo tient compte de l'orientation du capteur et de la rotation de l'appareil.

La rotation globale du tampon d'image du capteur peut être calculée à l'aide de la formule suivante:

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

sign est 1 pour les caméras avant et -1 pour les caméras arrière.

Pour les caméras avant, le tampon d'image est pivoté dans le sens inverse des aiguilles d'une montre (à partir de l'orientation naturelle du capteur). Pour les caméras arrière, le tampon d'image du capteur est pivoté dans le sens des aiguilles d'une montre.

L'expression deviceOrientationDegrees * sign + 360 convertit la rotation de l'appareil de la rotation antihoraire en sens horaire pour les appareils photo arrière (par exemple, conversion de 270 degrés dans le sens inverse des aiguilles d'une montre à 90 degrés dans le sens des aiguilles d'une montre). L'opération modulo redimensionne le résultat à moins de 360 degrés (par exemple, en passant de 540 degrés à 180 degrés).

Chaque API n'indique pas la rotation des appareils:

  • Display#getRotation() fournit la rotation de l'appareil dans le sens inverse des aiguilles d'une montre (du point de vue de l'utilisateur). Cette valeur s'intègre telle quelle dans la formule ci-dessus.
  • OrientationEventListener#onOrientationChanged() affiche la rotation de l'appareil dans le sens des aiguilles d'une montre (du point de vue de l'utilisateur). Nécessité la valeur à utiliser dans la formule ci-dessus.

Caméras avant

L'aperçu de l'appareil photo et le capteur sont en mode paysage. Le capteur est à l'endroit.
Figure 2 : Aperçu de l'appareil photo et capteur avec le téléphone réglé sur l'orientation paysage à 90 degrés.

Voici le tampon d'image produit par le capteur de l'appareil photo sur la figure 2:

Capteur de l'appareil photo en mode paysage avec l'image droite.

Vous devez faire pivoter le tampon de 270 degrés dans le sens inverse des aiguilles d'une montre pour ajuster l'orientation du capteur (voir la section Orientation de la caméra ci-dessus):

Capteur de l'appareil photo orienté pour afficher l'image de côté, en haut à droite.

Ensuite, le tampon est pivoté de 90 degrés supplémentaire dans le sens inverse des aiguilles d'une montre pour tenir compte de la rotation de l'appareil, ce qui aboutit à l'orientation correcte de l'aperçu de l'appareil photo (figure 2) :

Capteur de l'appareil photo pivoté en mode paysage avec l'image à l'endroit.

Voici comment l'appareil photo est orienté vers la droite en mode paysage:

L'aperçu de l'appareil photo et le capteur sont tous deux en mode paysage, mais le capteur est à l'envers.
Figure 3 : Aperçu de l'appareil photo et capteur avec le téléphone réglé sur l'orientation paysage à 270 degrés (ou -90 degrés).

Voici le tampon d'image:

Capteur de l'appareil photo orienté en mode paysage avec l'image à l'envers.

Vous devez faire pivoter le tampon de 270 degrés dans le sens inverse des aiguilles d'une montre pour s'adapter à l'orientation du capteur:

Capteur de l'appareil photo classé en mode portrait avec l'image de travers, en haut à gauche.

Ensuite, le tampon est pivoté de 270 degrés dans le sens inverse des aiguilles d'une montre pour tenir compte de la rotation de l'appareil:

Capteur de l'appareil photo pivoté en mode paysage avec l'image à l'endroit.

Caméras arrière

Les caméras arrière ont généralement une orientation de capteur de 90 degrés (comme vu de l'arrière de l'appareil). Lorsque vous orientez l'aperçu de l'appareil photo, le tampon d'image du capteur fait l'objet d'une rotation dans le sens des aiguilles d'une montre en fonction de la rotation du capteur (plutôt que dans le sens inverse des aiguilles d'une montre comme les caméras avant). Le tampon d'image est ensuite pivoté dans le sens inverse des aiguilles d'une montre en fonction de la rotation de l'appareil.

L'aperçu de l'appareil photo et le capteur sont tous deux en mode paysage, mais le capteur est à l'envers.
Figure 4 : Téléphone avec la caméra arrière en mode paysage (270 ou -90 degrés).

Voici le tampon d'image du capteur photo de la figure 4:

Capteur de l'appareil photo orienté en mode paysage avec l'image à l'envers.

Vous devez faire pivoter le tampon de 90 degrés dans le sens des aiguilles d'une montre pour s'adapter à l'orientation du capteur:

Capteur de l'appareil photo classé en mode portrait avec l'image de travers, en haut à gauche.

Ensuite, le tampon est pivoté de 270 degrés dans le sens inverse des aiguilles d'une montre pour tenir compte de la rotation de l'appareil:

Capteur de l'appareil photo pivoté en mode paysage avec l'image à l'endroit.

Format

Le format d'affichage change lorsque l'orientation de l'appareil change, mais également lorsque les pliables se plient et se déplient, lorsque les fenêtres sont redimensionnées dans des environnements multifenêtres et lorsque des applications s'ouvrent sur des écrans secondaires.

Le tampon d'image du capteur de l'appareil photo doit être orienté et mis à l'échelle pour correspondre à l'orientation et au format de l'élément d'interface utilisateur du viseur, car l'interface utilisateur change d'orientation de manière dynamique, que l'appareil change d'orientation ou non.

Sur de nouveaux facteurs de forme, ou dans des environnements multifenêtres ou multi-écrans, si votre application suppose que l'aperçu de l'appareil photo a la même orientation que l'appareil (portrait ou paysage), il est possible qu'il soit orienté de manière incorrecte, qu'il soit mis à l'échelle de manière incorrecte, ou les deux.

Appareil pliable déplié avec l'aperçu de l'appareil photo en mode portrait tourné sur le côté.
Image 5. L'appareil pliable passe du format portrait au format paysage, mais le capteur de l'appareil photo reste en mode portrait.

Dans la figure 5, l'application a supposé à tort que l'appareil avait été pivoté de 90 degrés dans le sens inverse des aiguilles d'une montre. L'application a donc fait pivoter l'aperçu de la même manière.

Appareil pliable déplié avec l'aperçu de l'appareil photo à la verticale, mais écrasé en raison d'une mise à l'échelle incorrecte.
Image 6. L'appareil pliable passe du format portrait au format paysage, mais le capteur de l'appareil photo reste en mode portrait.

Dans la figure 6, l'application n'a pas ajusté le format du tampon d'image pour lui permettre de s'adapter aux nouvelles dimensions de l'élément d'interface utilisateur d'aperçu de l'appareil photo.

Les applications d'appareil photo à orientation fixe rencontrent généralement des problèmes sur les appareils pliables et sur d'autres appareils à grand écran tels que les ordinateurs portables:

L'aperçu de l'appareil photo sur un ordinateur portable est à la verticale, mais l'interface de l'application est affichée sur le côté.
Image 7. Application en mode portrait à orientation fixe sur un ordinateur portable

Dans la figure 7, l'interface utilisateur de l'application d'appareil photo est affichée de travers, car l'orientation de l'application est limitée au mode portrait. L'image du viseur est correctement orientée par rapport au capteur de l'appareil photo.

Mode Portrait en incrustation

Les applications d'appareil photo qui ne sont pas compatibles avec le mode multifenêtre (resizeableActivity="false") et limitent leur orientation (screenOrientation="portrait" ou screenOrientation="landscape") peuvent être placées en mode portrait en incrustation sur les appareils à grand écran afin d'orienter correctement l'aperçu de l'appareil photo.

Insérer des encarts dans les applications en mode portrait uniquement dans l'orientation portrait, même si le format d'affichage est en mode paysage Les applications en mode paysage uniquement sont mises au format letterbox en mode paysage, même si le format d'affichage est en mode portrait. L'image de l'appareil photo est pivotée pour s'aligner sur l'interface utilisateur de l'application, recadrée pour correspondre au format de l'aperçu de l'appareil photo, puis mise à l'échelle pour remplir l'aperçu.

Le mode Portrait incrusté est déclenché lorsque le format du capteur d'image de l'appareil photo et celui de l'activité principale de l'application ne correspondent pas.

Aperçu de l'appareil photo et interface utilisateur de l'application en mode portrait correct sur un ordinateur portable.
            L'image d'aperçu large est mise à l'échelle et recadrée pour s'adapter à l'orientation portrait.
Figure 8 : Application de portrait à orientation fixe en mode portrait en encart sur un ordinateur portable

Dans la figure 8, l'application d'appareil photo en mode portrait a été pivotée pour afficher l'interface utilisateur à la verticale sur l'écran de l'ordinateur portable. L'application est mise au format letterbox en raison de la différence de format entre l'application en mode portrait et l'affichage en mode paysage. L'image d'aperçu de l'appareil photo a été pivotée pour compenser la rotation de l'interface utilisateur de l'application (en raison du mode portrait en incrustation), et l'image a été recadrée et mise à l'échelle pour s'adapter à l'orientation portrait, ce qui réduit le champ de vision.

Faire pivoter, recadrer, mettre à l'échelle

Le mode Portrait en encart est appelé pour une application d'appareil photo en mode portrait sur un écran au format paysage:

L'aperçu de l'appareil photo sur un ordinateur portable est à la verticale, mais l'interface de l'application est affichée sur le côté.
Figure 9 : Application en mode portrait à orientation fixe sur un ordinateur portable

L'application est mise au format letterbox en mode portrait:

L'application a été pivotée en mode portrait et mise au format letterbox. L'image est de travers, en haut à droite.

L'image de l'appareil photo fait l'objet d'une rotation de 90 degrés pour s'adapter à la réorientation de l'application:

Rotation de 90 degrés de l'image du capteur pour la rendre à la verticale.

L'image est recadrée au format de l'aperçu de l'appareil photo, puis mise à l'échelle pour remplir l'aperçu (le champ de vision est réduit):

Image recadrée de l'appareil photo mise à l'échelle pour remplir l'aperçu de l'appareil photo.

Sur les appareils pliables, l'orientation du capteur de l'appareil photo peut être en mode portrait tandis que le format de l'écran est en mode paysage:

L'aperçu de l'appareil photo et l'interface utilisateur de l'application sont orientés sur le côté par rapport à l'écran grand angle déplié.
Figure 10. Appareil déplié avec une application d'appareil photo en mode portrait uniquement et différents formats de capteur et d'écran de l'appareil photo.

Comme l'aperçu de l'appareil photo est pivoté pour s'adapter à l'orientation du capteur, l'image est correctement orientée dans le viseur, mais l'application en mode portrait uniquement est affichée sur le côté.

Le mode Portrait en encart n'a besoin que de mettre l'application au format letterbox en mode portrait pour orienter correctement l'application et l'aperçu de l'appareil photo:

Application au format letterbox dans un format portrait avec l'aperçu de l'appareil photo à la verticale sur un appareil pliable.

API

À partir d'Android 12 (niveau d'API 31), les applications peuvent également contrôler explicitement le mode portrait en incrustation à l'aide de la propriété SCALER_ROTATE_AND_CROP de la classe CaptureRequest.

La valeur par défaut est SCALER_ROTATE_AND_CROP_AUTO, ce qui permet au système d'appeler le mode Portrait en encart. SCALER_ROTATE_AND_CROP_90 correspond au comportement du mode Portrait en encart, comme décrit ci-dessus.

Certains appareils n'acceptent pas toutes les valeurs SCALER_ROTATE_AND_CROP. Pour obtenir la liste des valeurs acceptées, reportez-vous à CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

CameraX

La bibliothèque Jetpack CameraX permet de créer facilement un viseur d'appareil photo qui s'adapte à l'orientation du capteur et à la rotation de l'appareil.

L'élément de mise en page PreviewView crée un aperçu de l'appareil photo, en ajustant automatiquement l'orientation du capteur, la rotation de l'appareil et la mise à l'échelle. PreviewView conserve le format de l'image de l'appareil photo en appliquant le type d'échelle FILL_CENTER, qui centre l'image, mais peut la recadrer pour qu'elle corresponde aux dimensions de la PreviewView. Pour mettre l'image de l'appareil photo au format letterbox, définissez le type d'échelle sur FIT_CENTER.

Pour découvrir les bases de la création d'un aperçu d'appareil photo avec PreviewView, consultez Implémenter un aperçu.

Pour obtenir un exemple d'implémentation complet, consultez le dépôt CameraXBasic sur GitHub.

Viseur de l'appareil photo

Semblable au cas d'utilisation Preview (Aperçu), la bibliothèque CameraViewfinder fournit un ensemble d'outils pour simplifier la création d'un aperçu d'appareil photo. Il ne dépend pas de CameraX Core. Vous pouvez donc l'intégrer parfaitement à votre codebase Camera2 existant.

Au lieu d'utiliser directement Surface, vous pouvez utiliser le widget CameraViewfinder pour afficher le flux de l'appareil photo de Camera2.

CameraViewfinder utilise en interne un TextureView ou un SurfaceView pour afficher le flux de l'appareil photo et applique les transformations requises pour afficher correctement le viseur. Cela implique de corriger leurs proportions, leur échelle et leur rotation.

Pour demander la surface à l'objet CameraViewfinder, vous devez créer un ViewfinderSurfaceRequest.

Cette requête contient des exigences concernant la résolution de surface et les informations sur l'appareil photo de CameraCharacteristics.

L'appel de requestSurfaceAsync() envoie la requête au fournisseur de surface, qui est un TextureView ou un SurfaceView, et obtient un ListenableFuture de Surface.

Appeler markSurfaceSafeToRelease() informe le fournisseur de surface que la surface n'est pas nécessaire et que les ressources associées peuvent être libérées.

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));
    }

SurfaceView

SurfaceView est une approche simple pour créer un aperçu d'appareil photo s'il ne nécessite aucun traitement et s'il n'est pas animé.

SurfaceView fait pivoter automatiquement le tampon d'image du capteur de l'appareil photo pour qu'il corresponde à l'orientation d'affichage, en tenant compte à la fois de l'orientation du capteur et de la rotation de l'appareil. Cependant, le tampon d'image est mis à l'échelle pour s'adapter aux dimensions SurfaceView sans tenir compte du format.

Vous devez vous assurer que le format du tampon d'image correspond à celui de SurfaceView. Pour ce faire, mettez à l'échelle le contenu de SurfaceView dans la méthode onMeasure() du composant:

(Le code source de computeRelativeRotation() est en rotation relative ci-dessous.)

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);
}

Pour savoir comment implémenter SurfaceView en tant qu'aperçu d'appareil photo, consultez Orientation de l'appareil photo.

TextureView

TextureView est moins performant que SurfaceView et offre plus de travail, mais TextureView vous permet de contrôler au maximum l'aperçu de l'appareil photo.

TextureView fait pivoter le tampon d'image du capteur en fonction de l'orientation du capteur, mais ne gère pas la rotation de l'appareil ni la mise à l'échelle de l'aperçu.

Le scaling et la rotation peuvent être encodés dans une transformation matrice. Pour savoir comment mettre à l'échelle et faire pivoter correctement un TextureView, consultez Prendre en charge les surfaces redimensionnables dans votre application d'appareil photo.

Rotation relative

La rotation relative du capteur de l'appareil photo correspond au degré de rotation requis pour aligner la sortie du capteur de l'appareil photo avec l'orientation de l'appareil.

Les composants tels que SurfaceView et TextureView utilisent la rotation relative pour déterminer les facteurs de mise à l'échelle x et y de l'image d'aperçu. Elle permet également de spécifier la rotation du tampon d'image du capteur.

Les classes CameraCharacteristics et Surface permettent de calculer la rotation relative du capteur photo:

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;
}

Métriques sur les fenêtres

La taille de l'écran ne doit pas être utilisée pour déterminer les dimensions du viseur de l'appareil photo. L'application Appareil photo peut s'exécuter sur une partie de l'écran, que ce soit en mode multifenêtre sur les appareils mobiles ou en mode sans mode sur ChromeOS.

WindowManager#getCurrentWindowMetrics() (ajouté au niveau d'API 30) renvoie la taille de la fenêtre de l'application plutôt que la taille de l'écran. Les méthodes WindowMetricsCalculator#computeCurrentWindowMetrics() et WindowInfoTracker#currentWindowMetrics() de la bibliothèque Jetpack WindowManager offrent une prise en charge similaire avec la rétrocompatibilité avec le niveau d'API 14.

Rotation à 180 degrés

Une rotation à 180 degrés d'un appareil (par exemple, de l'orientation naturelle à l'orientation naturelle à l'envers) ne déclenche pas le rappel onConfigurationChanged(). L'aperçu de l'appareil photo peut donc être à l'envers.

Pour détecter une rotation à 180 degrés, implémentez un DisplayListener et vérifiez la rotation de l'appareil avec un appel à Display#getRotation() dans le rappel onDisplayChanged().

Ressources exclusives

Avant Android 10, seule l'activité la plus visible dans un environnement multifenêtre était à l'état RESUMED. Cela prêtait à confusion pour les utilisateurs, car le système n'indiquait pas quelle activité était réactivée.

Android 10 (niveau d'API 29) a introduit la fonctionnalité de multireprise où toutes les activités visibles sont à l'état RESUMED. Les activités visibles peuvent toujours passer à l'état PAUSED si, par exemple, une activité transparente se superpose ou si l'activité n'est pas sélectionnable, comme en mode Picture-in-picture (voir Compatibilité Picture-in-picture).

Une application utilisant l'appareil photo, le micro, ou une ressource exclusive ou Singleton au niveau d'API 29 ou supérieur doit être compatible avec la multireprise. Par exemple, si trois activités réactivées souhaitent utiliser l'appareil photo, une seule d'entre elles peut accéder à cette ressource exclusive. Chaque activité doit implémenter un rappel onDisconnected() pour prévenir l'accès préventif à l'appareil photo par une activité de priorité plus élevée.

Pour en savoir plus, consultez la section Multireprise.

Ressources supplémentaires