API Android 4.4

Niveau d'API: 19

Android 4.4 (KITKAT) est une nouvelle version de la plate-forme Android qui propose de nouvelles fonctionnalités aux utilisateurs et aux développeurs d'applications. Ce document présente les nouvelles API les plus importantes.

En tant que développeur d'applications, vous devez télécharger l'image système Android 4.4 et la plate-forme SDK à partir de SDK Manager dès que possible. Si vous ne disposez pas d'un appareil exécutant Android 4.4 sur lequel tester votre application, utilisez l'image système Android 4.4 pour tester votre application sur Android Emulator. Compilez ensuite vos applications sur la plate-forme Android 4.4 pour commencer à utiliser les dernières API.

Mettre à jour votre niveau d'API cible

Afin d'optimiser votre application pour les appareils équipés d'Android 4.4, vous devez définir targetSdkVersion sur "19", l'installer sur une image système Android 4.4, la tester, puis publier une mise à jour avec cette modification.

Vous pouvez utiliser des API dans Android 4.4 tout en prenant en charge les anciennes versions en ajoutant à votre code des conditions qui vérifient le niveau d'API du système avant d'exécuter des API non compatibles avec votre minSdkVersion. Pour en savoir plus sur la gestion de la rétrocompatibilité, consultez la page Compatibilité avec différentes versions de plate-forme.

Pour en savoir plus sur le fonctionnement des niveaux d'API, consultez Qu'est-ce que le niveau d'API ?

Changements de comportement importants

Si vous avez déjà publié une application pour Android, sachez qu'elle peut être affectée par des modifications dans Android 4.4.

Si votre application lit des données depuis un espace de stockage externe...

Lorsqu'elle est exécutée sur Android 4.4, votre application ne peut pas lire les fichiers partagés de la mémoire de stockage externe, sauf si elle dispose de l'autorisation READ_EXTERNAL_STORAGE. Autrement dit, les fichiers contenus dans le répertoire renvoyé par getExternalStoragePublicDirectory() ne sont plus accessibles sans autorisation. Toutefois, si vous n'avez besoin d'accéder qu'aux répertoires spécifiques à votre application, fournis par getExternalFilesDir(), vous n'avez pas besoin de l'autorisation READ_EXTERNAL_STORAGE.

Si votre application utilise WebView...

Votre application peut se comporter différemment sous Android 4.4, en particulier lorsque vous mettez à jour targetSdkVersion vers "19" ou une version ultérieure.

Le code sous-jacent de la classe WebView et des API associées a été mis à niveau pour être basé sur un instantané moderne du code source de Chromium. Cela se traduit par diverses améliorations des performances, la prise en charge de nouvelles fonctionnalités HTML5 et la prise en charge du débogage à distance de votre contenu WebView. Le champ d'application de cette mise à niveau signifie que si votre appli utilise WebView, son comportement peut être affecté dans certains cas. Bien que les changements de comportement connus soient documentés et n'affectent principalement votre application que lorsque vous mettez à jour la version targetSdkVersion de votre application vers la version 19 ou une version ultérieure, le nouveau WebView fonctionne en "mode quirks" pour fournir d'anciennes fonctionnalités dans les applications qui ciblent le niveau d'API 18 ou inférieur. Toutefois, il est possible que votre application dépende de comportements inconnus de la version précédente de WebView.

Par conséquent, si votre application existante utilise WebView, il est important de la tester sur Android 4.4 dès que possible et de consulter la section Migrer vers WebView dans Android 4.4 pour connaître les conséquences sur votre application si vous passez à targetSdkVersion sur "19" ou une version ultérieure.

Si votre application utilise AlarmManager...

Lorsque vous définissez la valeur targetSdkVersion de votre application sur "19 " ou plus, les alarmes que vous créez à l'aide de set() ou setRepeating() sont inexactes.

Pour améliorer l'efficacité énergétique, Android regroupe désormais les alarmes de toutes les applications qui se produisent à des moments raisonnablement similaires. Ainsi, le système active l'appareil une seule fois au lieu de plusieurs fois pour gérer chaque alarme.

Si votre alarme n'est pas associée à une heure exacte, mais qu'il reste important qu'elle soit appelée pendant une période spécifique (par exemple, entre 14h et 16h), vous pouvez utiliser la nouvelle méthode setWindow(), qui accepte une heure "au plus tôt" pour l'alarme et une "fenêtre" de temps après l'heure à laquelle le système doit l'appeler au plus tôt.

Si votre alarme doit être épinglée à une heure précise (par exemple, pour un rappel d'événement de l'agenda), vous pouvez utiliser la nouvelle méthode setExact().

Ce comportement inexact de traitement par lot ne s'applique qu'aux applications mises à jour. Si vous avez défini targetSdkVersion sur "18 " ou une valeur inférieure, vos alarmes continueront de se comporter comme sur les versions précédentes lorsqu'elles sont exécutées sur Android 4.4.

Si votre application synchronise les données à l'aide de ContentResolver...

Lorsque vous définissez targetSdkVersion de votre application sur "19" ou une valeur supérieure, la création d'une synchronisation avec addPeriodicSync() effectue les opérations de synchronisation dans un intervalle flexible par défaut d'environ 4% de la période que vous spécifiez. Par exemple, si la fréquence des sondages est de 24 heures, la synchronisation peut avoir lieu sur une période d'environ une heure chaque jour, et non à la même heure chaque jour.

Pour spécifier votre propre intervalle flexible pour les opérations de synchronisation, vous devez commencer à utiliser la nouvelle méthode requestSync(). Pour en savoir plus, consultez la section ci-dessous sur les adaptateurs de synchronisation.

Ce comportement de l'intervalle flexible ne s'applique qu'aux applications mises à jour. Si vous avez défini targetSdkVersion sur "18" ou une valeur inférieure, vos demandes de synchronisation existantes continueront de se comporter comme dans les versions précédentes sur Android 4.4.

Cadre d'impression

Android inclut désormais un framework complet qui permet aux utilisateurs d'imprimer n'importe quel document à l'aide d'une imprimante connectée via Wi-Fi, Bluetooth ou d'autres services. Le système gère la transaction entre une application qui souhaite imprimer un document et les services qui fournissent des tâches d'impression à une imprimante. Le framework android.print fournit toutes les API nécessaires pour spécifier un document imprimé et le transmettre au système pour impression. Les API dont vous avez besoin pour une tâche d'impression donnée dépendent de votre contenu.

Impression de contenu générique

Si vous souhaitez imprimer le contenu de votre interface utilisateur sous forme de document, vous devez d'abord créer une sous-classe de PrintDocumentAdapter. Dans cette classe, vous devez implémenter quelques méthodes de rappel, y compris onLayout() pour établir votre mise en page en fonction des propriétés d'impression fournies et onWrite() pour sérialiser votre contenu imprimable dans un ParcelFileDescriptor.

Pour écrire votre contenu dans ParcelFileDescriptor, vous devez lui transmettre un PDF. Les nouvelles API PdfDocument offrent un moyen pratique d'y parvenir en fournissant un Canvas à partir de getCanvas(), sur lequel vous pouvez dessiner votre contenu imprimable. Ensuite, écrivez PdfDocument dans ParcelFileDescriptor à l'aide de la méthode writeTo().

Une fois que vous avez défini votre implémentation pour PrintDocumentAdapter, vous pouvez exécuter des tâches d'impression sur la requête de l'utilisateur à l'aide de la méthode PrintManager, print(), qui utilise PrintDocumentAdapter comme argument.

Imprimer des images

Si vous souhaitez imprimer uniquement une photo ou un autre bitmap, les API d'assistance de la bibliothèque Support font tout le travail à votre place. Il vous suffit de créer une instance de PrintHelper, de définir le mode de scaling avec setScaleMode(), puis de transmettre votre Bitmap à printBitmap(). C'est tout. La bibliothèque gère toutes les interactions restantes avec le système pour envoyer le bitmap à l'imprimante.

Créer des services d'impression

En tant qu'OEM d'imprimantes, vous pouvez utiliser le framework android.printservice pour assurer l'interopérabilité avec vos imprimantes à partir d'appareils Android. Vous pouvez créer et distribuer des services d'impression sous forme de fichiers APK que les utilisateurs peuvent installer sur leurs appareils . Une application de service d'impression fonctionne principalement comme un service sans interface graphique en sous-classant la classe PrintService, qui reçoit les tâches d'impression du système et les communique à ses imprimantes à l'aide des protocoles appropriés.

Pour savoir comment imprimer le contenu de votre application, consultez Imprimer le contenu.

Fournisseur de SMS

Le fournisseur de contenu Telephony (le "fournisseur de SMS") permet aux applications de lire et d'écrire des SMS et des MMS sur l'appareil. Il comprend des tableaux des SMS et MMS reçus, brouillons, envoyés, en attente, etc.

À partir de la version 4.4 d'Android, les paramètres système permettent aux utilisateurs de sélectionner une "application de SMS par défaut". Une fois sélectionnée, seule l'application de SMS par défaut peut écrire au fournisseur de SMS, et seule l'application de SMS par défaut reçoit la diffusion SMS_DELIVER_ACTION lorsque l'utilisateur reçoit un SMS ou la diffusion WAP_PUSH_DELIVER_ACTION lorsqu'il reçoit un MMS. L'application SMS par défaut est chargée d'écrire les informations au fournisseur de SMS lorsqu'elle reçoit ou envoie un nouveau message.

Les autres applications qui ne sont pas sélectionnées comme application de SMS par défaut peuvent uniquement lire le fournisseur de SMS, mais elles peuvent également recevoir une notification lorsqu'un nouveau SMS arrive en écoutant la diffusion SMS_RECEIVED_ACTION, qui est une annonce non annulable qui peut être envoyée à plusieurs applications. Cette annonce est destinée aux applications qui, bien qu'elles ne soient pas sélectionnées comme application de SMS par défaut, doivent lire des messages entrants spéciaux, par exemple pour valider un numéro de téléphone.

Pour en savoir plus, consultez l'article de blog Getting Your SMS Apps Ready for KitKat (Préparer vos applications SMS pour KitKat).

Sans fil et connectivité

Émulation de carte hôte

Les applications Android peuvent désormais émuler des cartes NFC ISO14443-4 (ISO-DEP) qui utilisent des APDU pour l'échange de données (comme spécifié dans la norme ISO7816-4). Cela permet à un appareil compatible NFC équipé d'Android 4.4 d'émuler plusieurs cartes NFC en même temps. Cela permet également à un terminal de paiement NFC ou à un autre lecteur NFC d'initier une transaction avec la carte NFC appropriée en fonction de l'identifiant d'application (AID).

Si vous souhaitez émuler une carte NFC qui utilise ces protocoles dans votre application, créez un composant de service basé sur la classe HostApduService. Alors que si votre application utilise plutôt un composant sécurisé pour l'émulation de cartes, vous devez créer un service basé sur la classe OffHostApduService, qui n'est pas directement impliquée dans les transactions, mais qui est nécessaire pour enregistrer les AID devant être gérés par le composant sécurisé.

Pour en savoir plus, consultez le guide Émulation de carte NFC.

Mode Lecteur NFC

Un nouveau mode Lecteur NFC permet à une activité de limiter toute activité NFC à la lecture uniquement des types de tags qui l'intéressent lorsqu'elle est exécutée au premier plan. Vous pouvez activer le mode Lecteur pour votre activité avec enableReaderMode(), en fournissant une implémentation de NfcAdapter.ReaderCallback qui reçoit un rappel lorsque de nouvelles balises sont détectées.

Cette nouvelle fonctionnalité, associée à l'émulation de carte hôte, permet à Android de fonctionner aux deux extrémités d'une interface de paiement mobile: un appareil fonctionne comme terminal de paiement (appareil exécutant une activité en mode lecteur) et un autre appareil en tant que client de paiement (appareil émulant une carte NFC).

Émetteurs infrarouges

Sur un appareil doté d'un émetteur infrarouge (IR), vous pouvez désormais transmettre des signaux infrarouges à l'aide des API ConsumerIrManager. Pour obtenir une instance de ConsumerIrManager, appelez getSystemService() avec CONSUMER_IR_SERVICE comme argument. Vous pouvez ensuite interroger les fréquences infrarouges prises en charge par l'appareil avec getCarrierFrequencies(), puis transmettre les signaux en transmettant la fréquence et le schéma de signal souhaités avec transmit().

Vous devez toujours vérifier d'abord si un appareil inclut un émetteur infrarouge en appelant hasIrEmitter(). Toutefois, si votre application n'est compatible qu'avec les appareils qui en ont un, vous devez inclure un élément <uses-feature> dans votre fichier manifeste pour "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Multimédia

Lecture adaptative

La lecture de vidéos adaptatives est désormais disponible avec les API MediaCodec, ce qui permet de modifier facilement la résolution en cours de lecture sur un Surface. Vous pouvez transmettre les images d'entrée du décodeur d'une nouvelle résolution, et la résolution des tampons de sortie change sans écart important.

Vous pouvez activer la lecture adaptative en ajoutant deux clés à MediaFormat, qui spécifient la résolution maximale requise par votre application à partir du codec: KEY_MAX_WIDTH et KEY_MAX_HEIGHT. Une fois ces éléments ajoutés à votre MediaFormat, transmettez MediaFormat à votre instance MediaCodec avec configure().

Le codec effectue une transition fluide entre des résolutions identiques ou inférieures à ces valeurs. Le codec peut également prendre en charge des résolutions supérieures aux valeurs maximales spécifiées (tant qu'il se trouve dans les limites des profils pris en charge), mais les transitions vers des résolutions plus élevées peuvent ne pas être fluides.

Pour modifier la résolution lors du décodage de la vidéo H.264, continuez à mettre des images en file d'attente à l'aide de MediaCodec.queueInputBuffer(), mais assurez-vous de fournir les nouvelles valeurs SPS (Sequence Parameter Set) et PPS avec l'image IDR (Instantaneous Decoder Refresh) dans un seul tampon.

Toutefois, avant d'essayer de configurer votre codec pour la lecture adaptative, vous devez vérifier que l'appareil est compatible avec la lecture adaptative en appelant isFeatureSupported(String) avec FEATURE_AdaptivePlayback.

Remarque:La compatibilité avec la lecture adaptative dépend du fournisseur. Certains codecs peuvent nécessiter plus de mémoire pour des indications de plus grande résolution. Par conséquent, vous devez définir les valeurs maximales de résolution en fonction du matériau source que vous décoderez.

Horodatage de l'audio à la demande

Pour faciliter la synchronisation audio-vidéo, la nouvelle classe AudioTimestamp fournit des détails sur la timeline sur une "image" spécifique d'un flux audio géré par AudioTrack. Pour obtenir le dernier horodatage disponible, instanciez un objet AudioTimestamp et transmettez-le à getTimestamp(). Si la requête de code temporel aboutit, l'instance AudioTrack est remplie avec une position en unités de frame, ainsi que l'heure estimée à laquelle ce frame a été présenté ou est sur le point d'être présenté.

Vous pouvez utiliser la valeur de nanoTime dans AudioTimestamp (qui est monotone) pour trouver l'image vidéo associée la plus proche par rapport à framePosition. Vous pourrez ainsi supprimer, dupliquer ou interpoler des images vidéo pour correspondre à l'audio. Vous pouvez également déterminer le décalage entre la valeur de nanoTime et la durée prévue d'une image vidéo future (en tenant compte du taux d'échantillonnage) pour prédire quelle image audio est attendue au même moment qu'une image vidéo.

Lecteur d'images de surface

La nouvelle API ImageReader vous fournit un accès direct aux tampons d'image lorsqu'ils sont affichés dans un Surface. Vous pouvez acquérir un ImageReader avec la méthode statique newInstance(). Appelez ensuite getSurface() pour créer un Surface et diffuser vos données d'image avec un producteur tel que MediaPlayer ou MediaCodec. Pour recevoir une notification lorsque de nouvelles images sont disponibles à partir de la surface, implémentez l'interface ImageReader.OnImageAvailableListener et enregistrez-la avec setOnImageAvailableListener().

Désormais, lorsque vous dessinez du contenu dans votre Surface, votre ImageReader.OnImageAvailableListener reçoit un appel à onImageAvailable() à mesure que chaque nouveau cadre d'image devient disponible, ce qui vous fournit le ImageReader correspondant. Vous pouvez utiliser ImageReader pour acquérir les données d'image du cadre en tant qu'objet Image en appelant acquireLatestImage() ou acquireNextImage().

L'objet Image fournit un accès direct au code temporel, au format, aux dimensions et aux données de pixels de l'image dans une ByteBuffer. Toutefois, pour que la classe Image interprète vos images, elles doivent être formatées selon l'un des types définis par des constantes dans ImageFormat ou PixelFormat.

Mesure des pics et RMS

Vous pouvez maintenant interroger le pic et la RMS du flux audio actuel à partir de Visualizer en créant une instance de Visualizer.MeasurementPeakRms et en la transmettant à getMeasurementPeakRms(). Lorsque vous appelez cette méthode, les valeurs maximale et RMS de l'élément Visualizer.MeasurementPeakRms donné sont définies sur les dernières valeurs mesurées.

Outil pour améliorer le son

LoudnessEnhancer est une nouvelle sous-classe de AudioEffect qui vous permet d'augmenter le volume sonore de votre MediaPlayer ou AudioTrack. Cela peut être particulièrement utile avec la nouvelle méthode getMeasurementPeakRms() mentionnée ci-dessus, afin d'augmenter le volume des pistes audio parlées lorsque d'autres contenus multimédias sont en cours de lecture.

Télécommandes

Android 4.0 (niveau d'API 14) a introduit les API RemoteControlClient qui permettent aux applications multimédias de consommer les événements de contrôleur multimédia provenant de clients distants, tels que les commandes multimédias sur l'écran de verrouillage. Les nouvelles API RemoteController vous permettent désormais de créer votre propre télécommande, ce qui vous permet de concevoir des applications et des périphériques innovants qui peuvent contrôler la lecture de n'importe quelle application multimédia qui s'intègre à RemoteControlClient.

Pour créer une télécommande, vous pouvez implémenter votre interface utilisateur comme vous le souhaitez. Toutefois, pour transmettre les événements du bouton multimédia à l'application multimédia de l'utilisateur, vous devez créer un service qui étend la classe NotificationListenerService et implémente l'interface RemoteController.OnClientUpdateListener. Il est important d'utiliser NotificationListenerService comme base, car il applique les restrictions de confidentialité appropriées, qui obligent les utilisateurs à activer votre application en tant qu'écouteur de notifications dans les paramètres de sécurité du système.

La classe NotificationListenerService comprend quelques méthodes abstraites que vous devez implémenter. Toutefois, si vous vous intéressez uniquement aux événements de contrôleur multimédia pour la gestion de la lecture de contenus multimédias, vous pouvez laisser votre implémentation vide et vous concentrer plutôt sur les méthodes RemoteController.OnClientUpdateListener.

Évaluations des télécommandes

Android 4.4 s'appuie sur les fonctionnalités existantes des clients de télécommande (les applications qui reçoivent des événements de commande multimédia avec RemoteControlClient) en ajoutant la possibilité pour les utilisateurs d'évaluer le titre en cours à partir de la télécommande.

La nouvelle classe Rating encapsule des informations sur une note d'utilisateur. Une note est définie en fonction de son style (RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, RATING_5_STARS ou RATING_PERCENTAGE) et de la valeur appropriée pour ce style.

Pour autoriser les utilisateurs à évaluer vos pistes à partir d'une télécommande:

Pour recevoir un rappel lorsque l'utilisateur modifie la note de la télécommande, implémentez la nouvelle interface RemoteControlClient.OnMetadataUpdateListener et transmettez une instance à setMetadataUpdateListener(). Lorsque l'utilisateur modifie la note, votre RemoteControlClient.OnMetadataUpdateListener reçoit un appel à onMetadataUpdate(), transmettant RATING_KEY_BY_USER comme clé et un objet Rating comme valeur.

Sous-titres

VideoView est désormais compatible avec les pistes de sous-titres WebVTT lors de la lecture de vidéos HTTP Live Stream (HLS), qui affichent la piste de sous-titres en fonction des préférences de sous-titres définies par l'utilisateur dans les paramètres système.

Vous pouvez également fournir à VideoView vos pistes de sous-titres WebVTT à l'aide de la méthode addSubtitleSource(). Cette méthode accepte un InputStream contenant les données de sous-titres et un objet MediaFormat qui spécifie le format de ces données, que vous pouvez spécifier à l'aide de createSubtitleFormat(). Ces sous-titres apparaissent également sur la vidéo selon les préférences de l'utilisateur.

Si vous n'utilisez pas VideoView pour afficher votre contenu vidéo, vous devez faire en sorte que vos sous-titres en superposition correspondent le plus possible aux préférences de sous-titrage de l'utilisateur. Une nouvelle API CaptioningManager vous permet d'interroger les préférences de sous-titrage de l'utilisateur, y compris les styles définis par CaptioningManager.CaptionStyle, comme la police de caractères et la couleur. Si l'utilisateur ajuste certaines préférences une fois que la vidéo a déjà commencé, enregistrez une instance de CaptioningManager.CaptioningChangeListener afin de recevoir un rappel lorsque l'une des préférences change, puis mettez à jour vos sous-titres si nécessaire.

Animation et graphisme

Scènes et transitions

Le nouveau framework android.transition fournit des API qui facilitent les animations entre différents états de votre interface utilisateur. L'une des fonctionnalités clés est la possibilité de définir des états distincts de votre interface utilisateur, appelés "scènes", en créant une mise en page distincte pour chacun d'eux. Lorsque vous souhaitez effectuer une animation d'une scène à une autre, exécutez une "transition" qui calcule l'animation nécessaire pour passer de la scène actuelle à la scène suivante.

Pour passer d'une scène à une autre, procédez comme suit:

  1. Spécifiez le ViewGroup contenant les composants de l'interface utilisateur que vous souhaitez modifier.
  2. Spécifiez la mise en page représentant le résultat final du changement (la scène suivante).
  3. Spécifiez le type de transition qui doit animer le changement de mise en page.
  4. Exécutez la transition.

Vous pouvez utiliser un objet Scene pour accomplir les étapes 1 et 2. Un élément Scene contient des métadonnées décrivant les propriétés d'une mise en page nécessaires à l'exécution d'une transition, y compris la vue parent et la disposition de la scène. Vous pouvez créer un Scene à l'aide d'un constructeur de classe ou de la méthode statique getSceneForLayout().

Vous devez ensuite utiliser TransitionManager pour accomplir les étapes 3 et 4. Vous pouvez, par exemple, transmettre votre Scene à la méthode statique go(). Cette opération trouve la vue parente de la scène dans la mise en page actuelle et effectue une transition sur les vues enfants afin d'atteindre la mise en page définie par le Scene.

Sinon, vous n'avez pas besoin de créer d'objet Scene, mais vous pouvez appeler beginDelayedTransition() en spécifiant un ViewGroup contenant les vues que vous souhaitez modifier. Ajoutez, supprimez ou reconfigurez ensuite les vues cibles. Une fois que le système a déployé les modifications selon les besoins, une transition commence à animer toutes les vues concernées.

Pour un contrôle accru, vous pouvez définir des ensembles de transitions entre les scènes prédéfinies, à l'aide d'un fichier XML dans le répertoire res/transition/ de votre projet. Dans un élément <transitionManager>, spécifiez une ou plusieurs balises <transition> spécifiant chacune une scène (une référence à un fichier de mise en page) et la transition à appliquer lors de l'entrée et/ou de la sortie de cette scène. Gonflez ensuite cet ensemble de transitions à l'aide de inflateTransitionManager(). Utilisez le TransitionManager renvoyé pour exécuter chaque transition avec transitionTo(), en transmettant un Scene représenté par l'une des balises <transition>. Vous pouvez également définir des ensembles de transitions de manière programmatique avec les API TransitionManager.

Lorsque vous spécifiez une transition, vous pouvez utiliser plusieurs types prédéfinis définis par des sous-classes de Transition, telles que Fade et ChangeBounds. Si vous ne spécifiez pas de type de transition, le système utilise AutoTransition par défaut, qui effectue automatiquement un fondu, un déplacement et un redimensionnement des vues si nécessaire. De plus, vous pouvez créer des transitions personnalisées en étendant n'importe laquelle de ces classes pour exécuter les animations comme vous le souhaitez. Une transition personnalisée permet de suivre les modifications que vous souhaitez apporter aux propriétés et de créer n'importe quelle animation en fonction de ces modifications. Par exemple, vous pouvez fournir une sous-classe de Transition qui écoute les modifications apportées à la propriété de rotation d'une vue, puis anime les modifications.

Pour en savoir plus, consultez la documentation TransitionManager.

Mise en pause de l'animation

Les API Animator vous permettent désormais de mettre en pause et de reprendre une animation en cours à l'aide des méthodes pause() et resume().

Pour suivre l'état d'une animation, vous pouvez implémenter l'interface Animator.AnimatorPauseListener, qui fournit des rappels lorsqu'une animation est mise en pause et réactivée: pause() et resume(). Ajoutez ensuite l'écouteur à un objet Animator avec addPauseListener().

Vous pouvez également sous-classer la classe abstraite AnimatorListenerAdapter, qui inclut désormais des implémentations vides pour les rappels de pause et de reprise définis par Animator.AnimatorPauseListener.

Bitmaps réutilisables

Vous pouvez désormais réutiliser n'importe quel bitmap modifiable dans BitmapFactory pour décoder n'importe quel autre bitmap, même lorsque la taille du nouveau bitmap est différente, à condition que le nombre d'octets du bitmap décodé (disponible à partir de getByteCount()) soit inférieur ou égal au nombre d'octets alloués du bitmap réutilisé (disponible sur getAllocationByteCount()). Pour en savoir plus, consultez inBitmap

Les nouvelles API pour Bitmap permettent une reconfiguration similaire pour la réutilisation en dehors de BitmapFactory (pour la génération manuelle de bitmaps ou la logique de décodage personnalisée). Vous pouvez désormais définir les dimensions d'un bitmap à l'aide des méthodes setHeight() et setWidth(), et spécifier un nouveau Bitmap.Config avec setConfig() sans affecter l'allocation de bitmap sous-jacente. La méthode reconfigure() offre également un moyen pratique de combiner ces modifications avec un seul appel.

Toutefois, vous ne devez pas reconfigurer un bitmap actuellement utilisé par le système de vues, car le tampon de pixels sous-jacent ne sera pas remappé de manière prévisible.

Contenu généré par l'utilisateur

Framework d'accès au stockage

Sur les versions précédentes d'Android, si vous souhaitez que votre application récupère un type spécifique de fichier à partir d'une autre application, elle doit appeler un intent avec l'action ACTION_GET_CONTENT. Cette action reste la méthode appropriée pour demander un fichier que vous souhaitez importer dans votre application. Cependant, Android 4.4 introduit l'action ACTION_OPEN_DOCUMENT, qui permet à l'utilisateur de sélectionner un fichier d'un type spécifique et d'accorder à votre application un accès en lecture à long terme à ce fichier (éventuellement avec un accès en écriture) sans importer le fichier dans votre application.

Si vous développez une application qui fournit des services de stockage de fichiers (un service d'enregistrement dans le cloud, par exemple), vous pouvez participer à cette UI unifiée pour la sélection de fichiers en implémentant un fournisseur de contenu en tant que sous-classe de la nouvelle classe DocumentsProvider. Votre sous-classe de DocumentsProvider doit inclure un filtre d'intent qui accepte l'action PROVIDER_INTERFACE ("android.content.action.DOCUMENTS_PROVIDER"). Vous devez ensuite implémenter les quatre méthodes abstraites dans le DocumentsProvider:

queryRoots()
Doit renvoyer un Cursor décrivant tous les répertoires racine de votre espace de stockage de documents, à l'aide des colonnes définies dans DocumentsContract.Root.
queryChildDocuments()
Doit renvoyer un Cursor décrivant tous les fichiers du répertoire spécifié, à l'aide des colonnes définies dans DocumentsContract.Document.
queryDocument()
Doit renvoyer un Cursor décrivant le fichier spécifié, à l'aide des colonnes définies dans DocumentsContract.Document.
openDocument()
Doit renvoyer un ParcelFileDescriptor représentant le fichier spécifié. Le système appelle cette méthode une fois que l'utilisateur a sélectionné un fichier et que l'application cliente demande l'accès à celui-ci en appelant openFileDescriptor().

Pour en savoir plus, consultez le guide Storage Access Framework.

Accès à l'espace de stockage externe

Vous pouvez désormais lire et écrire des fichiers spécifiques à une application sur un support de stockage externe secondaire, par exemple lorsqu'un appareil fournit à la fois un espace de stockage émulé et une carte SD. La nouvelle méthode getExternalFilesDirs() fonctionne de la même manière que la méthode getExternalFilesDir() existante, sauf qu'elle renvoie un tableau d'objets File. Avant de lire ou d'écrire dans l'un des chemins renvoyés par cette méthode, transmettez l'objet File à la nouvelle méthode getStorageState() pour vérifier que l'espace de stockage est actuellement disponible.

D'autres méthodes permettant d'accéder au répertoire de cache spécifique à votre application et au répertoire OBB ont également désormais des versions correspondantes qui donnent accès aux périphériques de stockage secondaires: getExternalCacheDirs() et getObbDirs(), respectivement.

La première entrée du tableau File renvoyé est considérée comme la mémoire de stockage externe principale de l'appareil, identique au File renvoyé par les méthodes existantes telles que getExternalFilesDir().

Remarque:À partir d'Android 4.4, la plate-forme n'exige plus que votre application acquière WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE lorsque vous devez accéder uniquement aux régions de la mémoire de stockage externe spécifiques à votre application à l'aide des méthodes ci-dessus. Toutefois, les autorisations sont requises si vous souhaitez accéder aux régions partageables de l'espace de stockage externe, fournies par getExternalStoragePublicDirectory().

Adaptateurs de synchronisation

La nouvelle méthode requestSync() dans ContentResolver simplifie une partie de la procédure de définition d'une requête de synchronisation pour votre ContentProvider en encapsulant les requêtes dans le nouvel objet SyncRequest, que vous pouvez créer avec SyncRequest.Builder. Les propriétés de SyncRequest offrent les mêmes fonctionnalités que les appels de synchronisation ContentProvider existants, mais permettent de spécifier qu'une synchronisation doit être interrompue si le réseau est facturé à l'usage, en activant setDisallowMetered().

Entrée utilisateur

Nouveaux types de capteurs

Le nouveau capteur TYPE_GEOMAGNETIC_ROTATION_VECTOR fournit des données vectorielles de rotation basées sur un magnétomètre, ce qui constitue une alternative utile au capteur TYPE_ROTATION_VECTOR lorsqu'aucun gyroscope n'est disponible ou lorsqu'il est utilisé avec des événements de capteur par lot pour enregistrer l'orientation de l'appareil pendant que le téléphone est en veille. Ce capteur consomme moins d'énergie que TYPE_ROTATION_VECTOR, mais il peut être exposé à des données d'événement bruyantes et est plus efficace lorsque l'utilisateur est à l'extérieur.

Désormais, Android est également compatible avec les capteurs de pas intégrés dans le matériel:

TYPE_STEP_DETECTOR
Ce capteur déclenche un événement chaque fois que l'utilisateur fait un pas. À chaque pas de l'utilisateur, ce capteur envoie un événement d'une valeur de 1,0 avec un code temporel indiquant le moment où l'étape s'est produite.
TYPE_STEP_COUNTER
Ce capteur déclenche également un événement à chaque étape détectée, mais fournit à la place le nombre total de pas cumulés depuis que ce capteur a été enregistré pour la première fois par une application.

Sachez que ces deux capteurs ne produisent pas toujours les mêmes résultats. Les événements TYPE_STEP_COUNTER se produisent avec une latence plus élevée que ceux de TYPE_STEP_DETECTOR, mais cela est dû au fait que l'algorithme TYPE_STEP_COUNTER effectue plus de traitement pour éliminer les faux positifs. Par conséquent, TYPE_STEP_COUNTER peut être plus lent pour diffuser les événements, mais ses résultats devraient être plus précis.

Les deux capteurs de pas dépendent du matériel (le Nexus 5 est le premier appareil compatible). Vous devez donc vérifier leur disponibilité avec hasSystemFeature(), à l'aide des constantes FEATURE_SENSOR_STEP_DETECTOR et FEATURE_SENSOR_STEP_COUNTER.

Événements de capteurs par lot

Pour mieux gérer la puissance de l'appareil, les API SensorManager vous permettent désormais de spécifier la fréquence à laquelle vous souhaitez que le système envoie des lots d'événements de capteurs à votre application. Cela ne réduit pas le nombre d'événements de capteurs réels disponibles pour votre application pour une période donnée, mais réduit la fréquence à laquelle le système appelle votre SensorEventListener avec les mises à jour des capteurs. Autrement dit, au lieu de transmettre chaque événement à votre application au moment où il se produit, le système enregistre tous les événements qui se produisent au cours d'une période donnée, puis les transmet en une seule fois à votre application.

Pour permettre le traitement par lot, la classe SensorManager ajoute deux nouvelles versions de la méthode registerListener() qui vous permettent de spécifier la "latence maximale des rapports". Ce nouveau paramètre spécifie le délai maximal toléré par votre SensorEventListener pour l'envoi de nouveaux événements de capteurs. Par exemple, si vous spécifiez une latence de lot d'une minute, le système diffusera l'ensemble récent d'événements par lot à un intervalle inférieur à une minute en effectuant des appels consécutifs à votre méthode onSensorChanged() (une fois pour chaque événement traité par lot). Les événements de capteurs ne seront jamais retardés au-delà de la valeur de latence maximale de vos rapports. Toutefois, ils peuvent arriver plus tôt si d'autres applications ont demandé une latence plus courte pour le même capteur.

Toutefois, sachez que le capteur transmet à votre application les événements par lot en fonction de la latence de votre rapport uniquement lorsque le processeur est activé. Bien qu'un capteur matériel compatible avec le traitement par lot continue de collecter les événements de capteur lorsque le processeur est en veille, il n'active pas le processeur pour envoyer les événements par lot à votre application. Lorsque le capteur n'a plus de mémoire disponible pour certains événements, il commence à abandonner les événements les plus anciens pour conserver les événements les plus récents. Pour éviter de perdre des événements, vous pouvez activer l'appareil avant que le capteur ne remplisse sa mémoire, puis appeler flush() pour capturer le dernier lot d'événements. Pour estimer le moment où la mémoire sera pleine et doit être vidée, appelez getFifoMaxEventCount() afin d'obtenir le nombre maximal d'événements de capteurs qu'il peut enregistrer, puis divisez ce nombre par la fréquence à laquelle votre application souhaite chaque événement. Utilisez ce calcul pour définir des alarmes wakeup avec AlarmManager qui appellent votre Service (qui implémente SensorEventListener) pour vider le capteur.

Remarque:Tous les appareils ne sont pas compatibles avec le traitement par lot des événements de capteurs, car le capteur matériel doit le prendre en charge. Toutefois, à partir d'Android 4.4, vous devez toujours utiliser les nouvelles méthodes registerListener(). En effet, si l'appareil n'est pas compatible avec le traitement par lot, le système ignore de manière optimale l'argument de latence du lot et envoie les événements de capteur en temps réel.

Identités du contrôleur

Android identifie désormais chaque manette connectée avec un entier unique que vous pouvez interroger avec getControllerNumber(), ce qui vous permet d'associer plus facilement chaque manette à un joueur différent dans un jeu. Le numéro de chaque manette peut changer lorsque les manettes sont déconnectées, connectées ou reconfigurées par l'utilisateur. Vous devez donc identifier le numéro de manette correspondant à chaque périphérique d'entrée en enregistrant une instance de InputManager.InputDeviceListener. Appelez ensuite getControllerNumber() pour chaque InputDevice lorsqu'une modification se produit.

Désormais, les appareils connectés fournissent également les ID des produits et des fournisseurs disponibles dans getProductId() et getVendorId(). Si vous devez modifier le mappage de vos clés en fonction de l'ensemble de clés disponible sur un appareil, vous pouvez interroger l'appareil pour vérifier si certaines clés sont disponibles avec hasKeys(int...).

Interface utilisateur

Mode plein écran immersif

Pour proposer à votre application une mise en page qui occupe tout l'écran, le nouvel indicateur SYSTEM_UI_FLAG_IMMERSIVE pour setSystemUiVisibility() (associé à SYSTEM_UI_FLAG_HIDE_NAVIGATION) active un nouveau mode plein écran immersif. Lorsque le mode immersif en plein écran est activé, votre activité continue de recevoir tous les événements tactiles. L'utilisateur peut afficher les barres système en balayant l'écran vers l'intérieur de la zone où elles apparaissent normalement. L'option SYSTEM_UI_FLAG_HIDE_NAVIGATION est effacée (et l'option SYSTEM_UI_FLAG_FULLSCREEN, s'il est appliqué), de sorte que les barres système restent visibles. Toutefois, si vous souhaitez que les barres système soient à nouveau masquées au bout de quelques instants, vous pouvez utiliser l'indicateur SYSTEM_UI_FLAG_IMMERSIVE_STICKY.

Barres système translucides

Vous pouvez désormais rendre les barres système partiellement translucides avec les nouveaux thèmes Theme.Holo.NoActionBar.TranslucentDecor et Theme.Holo.Light.NoActionBar.TranslucentDecor. Si vous activez les barres système translucides, votre mise en page remplira la zone derrière les barres système. Vous devez donc également activer fitsSystemWindows pour la partie de votre mise en page qui ne doit pas être recouverte par ces barres.

Si vous créez un thème personnalisé, définissez-le en tant que thème parent ou incluez les propriétés de style windowTranslucentNavigation et windowTranslucentStatus dans votre thème.

Écouteur de notifications amélioré

Android 4.3 a ajouté les API NotificationListenerService, qui permettent aux applications de recevoir des informations sur les nouvelles notifications lorsqu'elles sont publiées par le système. Dans Android 4.4, les écouteurs de notifications peuvent récupérer des métadonnées supplémentaires pour la notification et des informations complètes sur les actions de la notification:

Le nouveau champ Notification.extras inclut un Bundle pour transmettre des métadonnées supplémentaires à votre générateur de notifications, telles que EXTRA_TITLE et EXTRA_PICTURE. La nouvelle classe Notification.Action définit les caractéristiques d'une action associée à la notification, que vous pouvez récupérer à partir du nouveau champ actions.

Mise en miroir de drawables pour les mises en page de droite à gauche

Dans les versions précédentes d'Android, si votre application inclut des images qui doivent inverser leur orientation horizontale pour les mises en page de droite à gauche, vous devez inclure l'image en miroir dans un répertoire de ressources drawables-ldrtl/. Désormais, le système peut automatiquement mettre en miroir les images pour vous en activant l'attribut autoMirrored sur une ressource drawable ou en appelant setAutoMirrored(). Lorsque cette option est activée, Drawable est automatiquement mis en miroir lorsque la mise en page s'oriente de droite à gauche.

Accessibilité

La classe View vous permet désormais de déclarer des "régions actives" pour les parties de votre interface utilisateur qui se mettent à jour de façon dynamique avec un nouveau contenu textuel. Pour ce faire, ajoutez le nouvel attribut accessibilityLiveRegion à votre mise en page XML ou appelez setAccessibilityLiveRegion(). Par exemple, un écran de connexion avec un champ de texte qui affiche une notification "mot de passe incorrect" doit être marqué comme une zone active, afin que le lecteur d'écran répète le message lorsqu'il change.

Désormais, les applications qui fournissent un service d'accessibilité peuvent également améliorer leurs capacités grâce à de nouvelles API qui fournissent des informations sur les collections de vues, comme les vues sous forme de liste ou de grille, à l'aide de AccessibilityNodeInfo.CollectionInfo et AccessibilityNodeInfo.CollectionItemInfo.

Autorisations de l'application

Voici les nouvelles autorisations que votre application doit demander avec la balise <uses-permission> pour utiliser certaines nouvelles API:

INSTALL_SHORTCUT
Permet à une application d'installer un raccourci dans le Lanceur d'applications.
UNINSTALL_SHORTCUT
Permet à une application de désinstaller un raccourci dans le Lanceur d'applications
TRANSMIT_IR
Permet à une application d'utiliser l'émetteur infrarouge de l'appareil, s'il est disponible.

Remarque:À partir d'Android 4.4, la plate-forme n'exige plus que votre application acquière WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE lorsque vous souhaitez accéder aux régions de stockage externe spécifiques à votre application à l'aide de méthodes telles que getExternalFilesDir(). Toutefois, les autorisations sont toujours nécessaires si vous souhaitez accéder aux régions partageables de l'espace de stockage externe, fournies par getExternalStoragePublicDirectory().

Fonctionnalités de l'appareil

Voici les nouvelles fonctionnalités d'appareil que vous pouvez déclarer avec la balise <uses-feature> pour déclarer les exigences de votre application et activer le filtrage sur Google Play, ou vérifier ces exigences au moment de l'exécution:

FEATURE_CONSUMER_IR
L'appareil est capable de communiquer avec les appareils infrarouges grand public.
FEATURE_DEVICE_ADMIN
L'appareil est compatible avec l'application des règles relatives aux appareils par le biais d'administrateurs.
FEATURE_NFC_HOST_CARD_EMULATION
L'appareil est compatible avec l'émulation de carte NFC basée sur l'hôte.
FEATURE_SENSOR_STEP_COUNTER
L'appareil inclut un compteur de pas matériel.
FEATURE_SENSOR_STEP_DETECTOR
L'appareil inclut un détecteur de pas matériel.

Pour obtenir une vue détaillée de toutes les modifications apportées aux API dans Android 4.4, consultez le rapport sur les différences d'API.