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.
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:
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:
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
où 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
Voici le tampon d'image produit par le capteur de l'appareil photo sur la figure 2:
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):
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) :
Voici comment l'appareil photo est orienté vers la droite en mode paysage:
Voici le tampon d'image:
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:
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:
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.
Voici le tampon d'image du capteur photo de la figure 4:
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:
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:
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.
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.
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:
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.
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'application est mise au format letterbox en mode portrait:
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:
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):
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:
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:
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
- Pour un exemple Camera2, consultez l'application Camera2Basic sur GitHub.
- Pour en savoir plus sur le cas d'utilisation de l'aperçu de CameraX, consultez Implémenter un aperçu de CameraX.
- Pour obtenir un exemple d'implémentation d'un aperçu de l'appareil photo CameraX, consultez le dépôt CameraXBasic sur GitHub.
- Pour en savoir plus sur l'aperçu de l'appareil photo sous ChromeOS, consultez Orientation de l'appareil photo.
- Pour en savoir plus sur le développement pour les appareils pliables, consultez En savoir plus sur les pliables.