API Android 4.3

Niveau d'API: 18

Android 4.3 (JELLY_BEAN_MR2) est une mise à jour de la version Jelly Bean qui offre de nouvelles fonctionnalités aux utilisateurs et aux développeurs d'applications. Ce document présente les nouvelles API les plus notables.

En tant que développeur d'applications, vous devez télécharger l'image système Android 4.3 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.3 sur lequel tester votre application, utilisez l'image système Android 4.3 pour tester votre application sur Android Emulator. Compilez ensuite vos applications sur la plate-forme Android 4.3 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.3, vous devez définir targetSdkVersion sur "18", l'installer sur une image système Android 4.3, la tester, puis publier une mise à jour avec cette modification.

Vous pouvez utiliser des API dans Android 4.3 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.

Différentes API sont également disponibles dans la bibliothèque Support Android. Elles vous permettent d'implémenter de nouvelles fonctionnalités sur d'anciennes versions de la 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.3.

Si votre application utilise des intents implicites...

Il est possible que votre application se comporte mal dans un environnement de profil limité.

Il est possible que les utilisateurs se trouvant dans un environnement de profil limité n'aient pas toutes les applications Android standards disponibles. Par exemple, pour un profil limité, le navigateur Web et l'application Appareil photo peuvent être désactivés. Votre application ne doit donc pas faire de suppositions sur les applications disponibles, car si vous appelez startActivity() sans vérifier si une application est disponible pour gérer le Intent, elle risque de planter dans un profil limité.

Lorsque vous utilisez un intent implicite, vous devez toujours vérifier qu'une application est disponible pour gérer l'intent en appelant resolveActivity() ou queryIntentActivities(). Par exemple :

Kotlin

val intent = Intent(Intent.ACTION_SEND)
...
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show()
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);
...
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show();
}

Si votre application dépend de comptes...

Il est possible que votre application se comporte mal dans un environnement de profil limité.

Par défaut, les utilisateurs appartenant à un environnement à profil limité n'ont pas accès aux comptes utilisateur. Si votre application dépend d'un Account, elle peut planter ou se comporter de manière inattendue lorsqu'elle est utilisée dans un profil limité.

Si vous souhaitez empêcher les profils restreints d'utiliser votre application parce qu'elle dépend d'informations de compte sensibles, spécifiez l'attribut android:requiredAccountType dans l'élément <application> de votre fichier manifeste.

Si vous souhaitez autoriser les profils restreints à continuer à utiliser votre application même s'ils ne peuvent pas créer leurs propres comptes, vous pouvez désactiver les fonctionnalités de votre application qui nécessitent un compte ou autoriser les profils restreints à accéder aux comptes créés par l'utilisateur principal. Pour en savoir plus, consultez la section ci-dessous sur la prise en charge des comptes dans un profil limité.

Si votre application utilise VideoView...

Votre vidéo sera peut-être plus petite sur Android 4.3.

Dans les versions précédentes d'Android, le widget VideoView a calculé à tort que la valeur "wrap_content" de layout_height et layout_width était identique à "match_parent". Ainsi, même si l'utilisation de "wrap_content" pour la hauteur ou la largeur a déjà fourni la mise en page vidéo souhaitée, cela peut se traduire par une vidéo beaucoup plus petite sur Android 4.3 ou version ultérieure. Pour résoudre le problème, remplacez "wrap_content" par "match_parent" et vérifiez que votre vidéo s'affiche comme prévu sur Android 4.3 ainsi que sur les anciennes versions.

Profils limités

Sur les tablettes Android, les utilisateurs peuvent désormais créer des profils limités en fonction de l'utilisateur principal. Lorsque les utilisateurs créent un profil limité, ils peuvent activer des restrictions telles que les applications disponibles pour le profil. Un nouvel ensemble d'API dans Android 4.3 vous permet également de créer des paramètres de restriction précis pour les applications que vous développez. Par exemple, en utilisant les nouvelles API, vous pouvez permettre aux utilisateurs de contrôler le type de contenu disponible dans votre application lorsqu'elle s'exécute dans un environnement de profil limité.

L'interface utilisateur permettant aux utilisateurs de contrôler les restrictions que vous avez créées est gérée par l'application Paramètres du système. Pour que l'utilisateur puisse voir les paramètres de restriction de votre application, vous devez déclarer les restrictions qu'elle fournit en créant un BroadcastReceiver qui reçoit l'intent ACTION_GET_RESTRICTION_ENTRIES. Le système appelle cet intent pour interroger toutes les applications afin d'identifier les restrictions disponibles, puis crée l'interface utilisateur pour permettre à l'utilisateur principal de gérer les restrictions pour chaque profil limité.

Dans la méthode onReceive() de votre BroadcastReceiver, vous devez créer un RestrictionEntry pour chaque restriction fournie par votre application. Chaque RestrictionEntry définit un titre de restriction, une description et l'un des types de données suivants:

  • TYPE_BOOLEAN pour une restriction "true" ou "false".
  • TYPE_CHOICE pour une restriction qui comporte plusieurs choix s'excluant mutuellement (cases d'option).
  • TYPE_MULTI_SELECT pour une restriction qui comporte plusieurs choix qui ne s'excluent pas mutuellement (options de cases à cocher).

Vous placez ensuite tous les objets RestrictionEntry dans un ArrayList, puis vous les placez dans le résultat du broadcast receiver en tant que valeur de l'extra EXTRA_RESTRICTIONS_LIST.

Le système crée l'interface utilisateur pour les restrictions de votre application dans l'application Paramètres et enregistre chaque restriction avec la clé unique que vous avez fournie pour chaque objet RestrictionEntry. Lorsque l'utilisateur ouvre votre application, vous pouvez interroger les restrictions actuelles en appelant getApplicationRestrictions(). Cela renvoie un Bundle contenant les paires clé/valeur pour chaque restriction que vous avez définie avec les objets RestrictionEntry.

Si vous souhaitez fournir des restrictions plus spécifiques qui ne peuvent pas être gérées par des valeurs booléennes, à choix unique ou à choix multiples, vous pouvez créer une activité dans laquelle l'utilisateur peut spécifier les restrictions et autoriser les utilisateurs à ouvrir cette activité à partir des paramètres de restriction. Dans votre broadcast receiver, incluez l'extra EXTRA_RESTRICTIONS_INTENT dans le résultat Bundle. Cet extra doit spécifier un Intent indiquant la classe Activity à lancer (utilisez la méthode putParcelable() pour transmettre EXTRA_RESTRICTIONS_INTENT avec l'intent). Lorsque l'utilisateur principal entre dans votre activité pour définir des restrictions personnalisées, celle-ci doit renvoyer un résultat contenant les valeurs de restriction dans un extra à l'aide de la clé EXTRA_RESTRICTIONS_LIST ou EXTRA_RESTRICTIONS_BUNDLE, selon que vous spécifiez respectivement des objets RestrictionEntry ou des paires clé/valeur.

Comptes compatibles dans un profil limité

Tous les comptes ajoutés à l'utilisateur principal sont disponibles pour un profil limité, mais ils ne sont pas accessibles par défaut depuis les API AccountManager. Si vous tentez d'ajouter un compte avec AccountManager alors que vous êtes dans un profil limité, vous obtiendrez un résultat d'échec. En raison de ces restrictions, vous disposez des trois options suivantes:

  • Autorisez l'accès aux comptes du propriétaire à partir d'un profil limité.

    Pour accéder à un compte à partir d'un profil limité, vous devez ajouter l'attribut android:restrictedAccountType à la balise <application>:

    <application ...
        android:restrictedAccountType="com.example.account.type" >
    

    Attention:L'activation de cet attribut permet à votre application d'accéder aux comptes de l'utilisateur principal à partir de profils limités. Vous ne devez donc autoriser cette utilisation que si les informations affichées par votre application ne révèlent pas d'informations permettant d'identifier personnellement l'utilisateur considérées comme sensibles. Les paramètres système informent l'utilisateur principal que votre application accorde des profils limités à ses comptes. Il doit donc être clair pour lui que l'accès au compte est important pour le fonctionnement de votre application. Si possible, vous devez également fournir à l'utilisateur principal des contrôles de restriction appropriés qui définissent le niveau d'accès au compte autorisé dans votre application.

  • Désactivez certaines fonctionnalités lorsque vous ne pouvez pas modifier les comptes.

    Si vous souhaitez utiliser des comptes, mais que vous n'en avez pas besoin pour la fonctionnalité principale de votre application, vous pouvez vérifier la disponibilité des comptes et désactiver les fonctionnalités lorsqu'elles ne sont pas disponibles. Commencez par vérifier si un compte existe déjà. Si ce n'est pas le cas, demandez s'il est possible de créer un compte en appelant getUserRestrictions() et vérifiez l'extra DISALLOW_MODIFY_ACCOUNTS dans le résultat. Si la valeur est true, vous devez désactiver toute fonctionnalité de votre application nécessitant un accès aux comptes. Par exemple :

    Kotlin

    val um = context.getSystemService(Context.USER_SERVICE) as UserManager
    val restrictions: Bundle = um.userRestrictions
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    Java

    UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    Bundle restrictions = um.getUserRestrictions();
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    Remarque:Dans ce scénario, vous ne devez pas déclarer de nouveaux attributs dans le fichier manifeste.

  • Désactivez votre application lorsqu'elle ne peut pas accéder aux comptes privés.

    S'il est important que votre application ne soit pas disponible pour les profils dont l'accès est limité, car elle dépend d'informations personnelles sensibles dans un compte (et parce que les profils dont l'accès est limité ne peuvent actuellement pas ajouter de nouveaux comptes), ajoutez l'attribut android:requiredAccountType à la balise <application>:

    <application ...
        android:requiredAccountType="com.example.account.type" >
    

    Par exemple, l'application Gmail utilise cet attribut pour se désactiver pour les profils dont l'accès est limité, car l'adresse e-mail personnelle du propriétaire ne doit pas être disponible pour ces profils.

  • Sans fil et connectivité

    Bluetooth à basse consommation (compatible Smart)

    Android prend désormais en charge la technologie Bluetooth Low Energy (LE) avec de nouvelles API dans android.bluetooth. Les nouvelles API vous permettent de créer des applications Android qui communiquent avec des périphériques Bluetooth à basse consommation, tels que des cardiofréquencemètres et des podomètres.

    Étant donné que la technologie Bluetooth LE est une fonctionnalité matérielle qui n'est pas disponible sur tous les appareils Android, vous devez déclarer un élément <uses-feature> dans votre fichier manifeste pour "android.hardware.bluetooth_le":

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
    

    Si vous connaissez déjà les API Bluetooth classiques d'Android, notez que l'utilisation des API Bluetooth LE présente quelques différences. Plus important encore, il existe désormais une classe BluetoothManager que vous devez utiliser pour certaines opérations de haut niveau, telles que l'acquisition d'un BluetoothAdapter, l'obtention d'une liste d'appareils connectés et la vérification de l'état d'un appareil. Par exemple, voici comment obtenir à présent BluetoothAdapter:

    Kotlin

    val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = bluetoothManager.adapter
    

    Java

    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();
    

    Pour détecter les périphériques Bluetooth LE, appelez startLeScan() au niveau de BluetoothAdapter, en lui transmettant une implémentation de l'interface BluetoothAdapter.LeScanCallback. Lorsque l'adaptateur Bluetooth détecte un périphérique Bluetooth LE, votre implémentation BluetoothAdapter.LeScanCallback reçoit un appel à la méthode onLeScan(). Cette méthode fournit un objet BluetoothDevice représentant l'appareil détecté, la valeur RSSI de l'appareil et un tableau d'octets contenant l'enregistrement d'annonces de l'appareil.

    Si vous souhaitez rechercher uniquement des types de périphériques spécifiques, vous pouvez appeler startLeScan() et inclure un tableau d'objets UUID qui spécifient les services GATT compatibles avec votre application.

    Remarque:Vous ne pouvez rechercher que des appareils Bluetooth LE ou des appareils Bluetooth classiques à l'aide des API précédentes. Vous ne pouvez pas rechercher à la fois des appareils Bluetooth LE et Classic.

    Pour vous connecter ensuite à un périphérique Bluetooth LE, appelez connectGatt() sur l'objet BluetoothDevice correspondant, en lui transmettant une implémentation de BluetoothGattCallback. Votre implémentation de BluetoothGattCallback reçoit des rappels concernant l'état de la connectivité avec l'appareil et d'autres événements. C'est lors du rappel onConnectionStateChange() que vous pouvez commencer à communiquer avec l'appareil si la méthode transmet STATE_CONNECTED comme nouvel état.

    Pour accéder aux fonctionnalités Bluetooth sur un appareil, votre application doit également demander certaines autorisations utilisateur Bluetooth. Pour en savoir plus, consultez le guide de l'API Bluetooth Low Energy.

    Mode recherche Wi-Fi uniquement

    Lorsque vous essayez d'identifier la position de l'utilisateur, Android peut utiliser le Wi-Fi pour déterminer sa position en recherchant les points d'accès à proximité. Toutefois, les utilisateurs maintiennent souvent le Wi-Fi désactivé pour économiser la batterie, ce qui entraîne des données de localisation moins précises. Android inclut désormais un mode de recherche uniquement qui permet au Wi-Fi de l'appareil de rechercher les points d'accès afin d'obtenir la position sans se connecter à un point d'accès, ce qui réduit considérablement l'utilisation de la batterie.

    Si vous souhaitez obtenir la position de l'utilisateur, mais que le Wi-Fi est actuellement désactivé, vous pouvez demander à l'utilisateur d'activer le mode de recherche Wi-Fi uniquement en appelant startActivity() avec l'action ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE.

    Configuration Wi-Fi

    Les nouvelles API WifiEnterpriseConfig permettent aux services destinés aux entreprises d'automatiser la configuration Wi-Fi pour les appareils gérés.

    Réponse rapide pour les appels entrants

    Depuis Android 4.0, une fonctionnalité appelée "Réponse rapide" permet aux utilisateurs de répondre aux appels entrants avec un SMS immédiat sans avoir à prendre l'appel ni à déverrouiller l'appareil. Jusqu'à présent, ces messages rapides étaient toujours gérés par l'application de messagerie par défaut. Toute application peut désormais déclarer sa capacité à gérer ces messages en créant un Service avec un filtre d'intent pour ACTION_RESPOND_VIA_MESSAGE.

    Lorsque l'utilisateur répond à un appel entrant par une réponse rapide, l'application Téléphone envoie l'intent ACTION_RESPOND_VIA_MESSAGE avec un URI décrivant le destinataire (l'appelant) et l'extra EXTRA_TEXT avec le message que l'utilisateur souhaite envoyer. Lorsque votre service reçoit l'intent, il doit diffuser le message et s'arrêter immédiatement (votre application ne doit pas afficher d'activité).

    Pour recevoir cet intent, vous devez déclarer l'autorisation SEND_RESPOND_VIA_MESSAGE.

    Multimédia

    Améliorations apportées à MediaExtractor et MediaCodec

    Android vous permet désormais d'écrire plus facilement vos propres lecteurs DASH (Dynamic Adaptive Streaming over HTTP) conformément à la norme ISO/IEC 23009-1, en utilisant les API existantes dans MediaCodec et MediaExtractor. Le framework sous-jacent de ces API a été mis à jour pour permettre l'analyse des fichiers MP4 fragmentés, mais votre application est toujours responsable de l'analyse des métadonnées de la description de la présentation du média et de la transmission des flux individuels à MediaExtractor.

    Si vous souhaitez utiliser DASH avec du contenu chiffré, la méthode getSampleCryptoInfo() renvoie les métadonnées MediaCodec.CryptoInfo décrivant la structure de chaque échantillon de média chiffré. En outre, la méthode getPsshInfo() a été ajoutée à MediaExtractor afin que vous puissiez accéder aux métadonnées PSSH pour vos médias DASH. Cette méthode renvoie un mappage d'objets UUID en octets, UUID spécifiant le schéma de chiffrement, les octets correspondant aux données spécifiques à ce schéma.

    DRM des contenus multimédias

    La nouvelle classe MediaDrm fournit une solution modulaire de gestion des droits numériques (DRM, Digital Rights Management) pour votre contenu multimédia, en séparant les problèmes de DRM de la lecture de contenus multimédias. Par exemple, cette séparation API vous permet de lire le contenu chiffré par Widevine sans avoir à utiliser le format multimédia Widevine. Cette solution DRM est également compatible avec le chiffrement courant DASH. Vous pouvez donc utiliser divers schémas DRM avec votre contenu en streaming.

    Vous pouvez utiliser MediaDrm pour obtenir des messages de demande de clé opaques et traiter les messages de réponse de clé à partir du serveur pour l'acquisition et le provisionnement de licences. Votre application est responsable de la gestion de la communication réseau avec les serveurs. La classe MediaDrm permet uniquement de générer et de traiter les messages.

    Les API MediaDrm sont destinées à être utilisées avec les API MediaCodec introduites dans Android 4.1 (niveau d'API 16), y compris MediaCodec pour encoder et décoder votre contenu, MediaCrypto pour gérer le contenu chiffré et MediaExtractor pour extraire et démuxer le contenu.

    Vous devez d'abord créer des objets MediaExtractor et MediaCodec. Vous pouvez ensuite accéder au UUID qui identifie le schéma DRM, généralement à partir des métadonnées du contenu, et l'utiliser pour construire une instance d'un objet MediaDrm avec son constructeur.

    Encodage vidéo depuis une surface

    Android 4.1 (niveau d'API 16) a ajouté la classe MediaCodec pour l'encodage et le décodage de bas niveau du contenu multimédia. Lors de l'encodage vidéo, Android 4.1 exigeait que vous fournissiez le contenu multimédia avec un tableau ByteBuffer, mais Android 4.3 vous permet désormais d'utiliser Surface comme entrée dans un encodeur. Par exemple, cela vous permet d'encoder l'entrée d'un fichier vidéo existant ou d'utiliser des images générées à partir d'OpenGL ES.

    Pour utiliser un Surface comme entrée de votre encodeur, commencez par appeler configure() pour votre MediaCodec. Appelez ensuite createInputSurface() pour recevoir le Surface sur lequel vous pouvez diffuser vos contenus multimédias.

    Par exemple, vous pouvez utiliser la Surface donnée comme fenêtre pour un contexte OpenGL en la transmettant à eglCreateWindowSurface(). Ensuite, lors du rendu de la surface, appelez eglSwapBuffers() pour transmettre l'image à MediaCodec.

    Pour commencer l'encodage, appelez start() au niveau de MediaCodec. Une fois l'encodage terminé, appelez signalEndOfInputStream() pour arrêter l'encodage, puis appelez release() sur Surface.

    Multimédia

    La nouvelle classe MediaMuxer permet le multiplexage entre un flux audio et un flux vidéo. Ces API servent d'équivalent à la classe MediaExtractor ajoutée à Android 4.2 pour le démultiplexage (deemuxing) de contenus multimédias.

    Les formats de sortie compatibles sont définis dans MediaMuxer.OutputFormat. Actuellement, MP4 est le seul format de sortie compatible, et MediaMuxer n'accepte qu'un seul flux audio et/ou vidéo à la fois.

    MediaMuxer est principalement conçu pour fonctionner avec MediaCodec afin que vous puissiez effectuer le traitement vidéo via MediaCodec, puis enregistrer la sortie dans un fichier MP4 via MediaMuxer. Vous pouvez également combiner MediaMuxer et MediaExtractor pour modifier des contenus multimédias sans avoir à encoder ni à décoder.

    Progression de la lecture et utilisation de la barre de lecture pour RemoteControlClient

    Dans Android 4.0 (niveau d'API 14), RemoteControlClient a été ajouté pour permettre les commandes de lecture multimédia des clients de télécommande, telles que les commandes disponibles sur l'écran de verrouillage. Android 4.3 permet désormais à ces contrôleurs d'afficher la position de lecture et les commandes pour utiliser la barre de lecture. Si vous avez activé la télécommande pour votre application multimédia avec les API RemoteControlClient, vous pouvez autoriser le défilement de la lecture en implémentant deux nouvelles interfaces.

    Tout d'abord, vous devez activer l'option FLAG_KEY_MEDIA_POSITION_UPDATE en la transmettant à setTransportControlsFlags().

    Implémentez ensuite les deux nouvelles interfaces suivantes:

    RemoteControlClient.OnGetPlaybackPositionListener
    Cela inclut le rappel onGetPlaybackPosition(), qui demande la position actuelle de vos contenus multimédias lorsque la télécommande doit mettre à jour la progression dans son UI.
    RemoteControlClient.OnPlaybackPositionUpdateListener
    Cela inclut le rappel onPlaybackPositionUpdate(), qui indique à votre application le nouveau code temporel de votre contenu multimédia lorsque l'utilisateur utilise la barre de lecture avec l'interface utilisateur de la télécommande.

    Une fois la lecture mise à jour avec la nouvelle position, appelez setPlaybackState() pour indiquer le nouvel état, la nouvelle position et la vitesse de lecture.

    Une fois ces interfaces définies, vous pouvez les définir pour votre RemoteControlClient en appelant respectivement setOnGetPlaybackPositionListener() et setPlaybackPositionUpdateListener().

    Graphismes

    Compatibilité avec OpenGL ES 3.0

    Android 4.3 ajoute des interfaces Java et est compatible en natif avec OpenGL ES 3.0. Les principales nouvelles fonctionnalités d'OpenGL ES 3.0 sont les suivantes:

    • Accélération des effets visuels avancés
    • Compression de texture ETC2/EAC haute qualité en tant que fonctionnalité standard
    • Nouvelle version du langage de nuance GLSL ES compatible avec les nombres entiers et les valeurs à virgule flottante 32 bits
    • Rendu de texture avancé
    • Normalisation plus étendue de la taille de la texture et des formats de tampon de rendu

    L'interface Java pour OpenGL ES 3.0 sur Android est fournie avec GLES30. Lorsque vous utilisez OpenGL ES 3.0, veillez à le déclarer dans votre fichier manifeste avec la balise <uses-feature> et l'attribut android:glEsVersion. Par exemple :

    <manifest>
        <uses-feature android:glEsVersion="0x00030000" />
        ...
    </manifest>
    

    N'oubliez pas de spécifier le contexte OpenGL ES en appelant setEGLContextClientVersion() et en transmettant 3 comme version.

    Pour en savoir plus sur l'utilisation d'OpenGL ES, y compris sur la vérification de la version OpenGL ES compatible de l'appareil au moment de l'exécution, consultez le guide de l'API OpenGL ES.

    Mipmapping pour les drawables

    L'utilisation d'un mipmap comme source de votre bitmap ou de votre drawable est un moyen simple de fournir une image de qualité et différentes échelles d'image, ce qui peut être particulièrement utile si vous prévoyez que votre image doit être mise à l'échelle lors d'une animation.

    Android 4.2 (niveau d'API 17) est compatible avec les mipmaps dans la classe Bitmap : Android remplace les images mip dans votre Bitmap lorsque vous avez fourni une source de mipmaps et que vous avez activé setHasMipMap(). Désormais, dans Android 4.3, vous pouvez également activer les mipmaps pour un objet BitmapDrawable en fournissant un élément mipmap et en définissant l'attribut android:mipMap dans un fichier de ressources bitmap, ou en appelant hasMipMap().

    Interface utilisateur

    Afficher les superpositions

    La nouvelle classe ViewOverlay fournit une couche transparente au-dessus d'une View à laquelle vous pouvez ajouter du contenu visuel et qui n'affecte pas la hiérarchie de la mise en page. Vous pouvez obtenir un ViewOverlay pour n'importe quel View en appelant getOverlay(). La superposition a toujours la même taille et la même position que sa vue hôte (la vue à partir de laquelle elle a été créée), ce qui vous permet d'ajouter du contenu qui apparaît devant la vue hôte, mais qui ne peut pas étendre les limites de cette vue hôte.

    L'utilisation d'un ViewOverlay est particulièrement utile lorsque vous souhaitez créer des animations, par exemple faire glisser une vue en dehors de son conteneur ou déplacer des éléments sur l'écran sans affecter la hiérarchie des vues. Toutefois, comme la zone utilisable d'une superposition est limitée à la vue hôte, si vous souhaitez animer une vue qui se déplace en dehors de sa position dans la mise en page, vous devez utiliser une superposition à partir d'une vue parent ayant les limites de mise en page souhaitées.

    Lorsque vous créez une superposition pour une vue Widget telle qu'une Button, vous pouvez ajouter des objets Drawable à la superposition en appelant add(Drawable). Si vous appelez getOverlay() pour une vue de mise en page, telle que RelativeLayout, l'objet renvoyé est un ViewGroupOverlay. La classe ViewGroupOverlay est une sous-classe de ViewOverlay qui vous permet également d'ajouter des objets View en appelant add(View).

    Remarque:Tous les drawables et les vues que vous ajoutez à une superposition sont uniquement visuels. Elles ne peuvent pas recevoir d'événements de sélection ou d'entrée.

    Par exemple, le code suivant anime une vue glissant vers la droite en la plaçant dans la superposition de la vue parent, puis en exécutant une animation de translation sur cette vue:

    Kotlin

    val view: View? = findViewById(R.id.view_to_remove)
    val container: ViewGroup? = view?.parent as ViewGroup
    
    container?.apply {
        overlay.add(view)
        ObjectAnimator.ofFloat(view, "translationX", right.toFloat())
                .start()
    }
    

    Java

    View view = findViewById(R.id.view_to_remove);
    ViewGroup container = (ViewGroup) view.getParent();
    container.getOverlay().add(view);
    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight());
    anim.start();
    

    Mise en page des limites optiques

    Pour les vues contenant des images de fond Nine-Patch, vous pouvez désormais spécifier qu'elles doivent être alignées sur les vues voisines en fonction des limites "optiques" de l'image de fond plutôt qu'en fonction des limites "Extrait" de la vue.

    Par exemple, les figures 1 et 2 présentent chacune la même mise en page, mais la version de la figure 1 utilise des limites de rognage (comportement par défaut), tandis que la figure 2 utilise des limites optiques. Étant donné que les images Nine-Patch utilisées pour le bouton et le cadre photo incluent une marge intérieure autour des bords, elles ne semblent pas s'aligner entre elles ni avec le texte lorsque vous utilisez des contours.

    Remarque:Sur la capture d'écran des figures 1 et 2, le paramètre développeur "Afficher les contours" est activé. Pour chaque affichage, les lignes rouges correspondent aux limites optiques, les lignes bleues aux limites du clip et la couleur rose aux marges.

    Figure 1 : Mise en page utilisant des limites de rognage (par défaut).

    Figure 2. Mise en page utilisant des limites optiques.

    Pour aligner les vues en fonction de leurs limites optiques, définissez l'attribut android:layoutMode sur "opticalBounds" dans l'une des mises en page parentes. Par exemple :

    <LinearLayout android:layoutMode="opticalBounds" ... >
    

    Figure 3. Vue agrandie du bouton Holo Nine-Patch avec des limites optiques.

    Pour que cela fonctionne, les images Nine-Patch appliquées à l'arrière-plan de vos vues doivent spécifier les limites optiques à l'aide de lignes rouges en bas et à droite du fichier Nine-Patch (comme illustré dans la figure 3). Les lignes rouges indiquent la zone à soustraire des limites du clip, ce qui laisse les limites optiques de l'image.

    Lorsque vous activez les limites optiques pour un ViewGroup dans votre mise en page, toutes les vues descendantes héritent du mode de mise en page des limites optiques, sauf si vous le remplacez pour un groupe en définissant android:layoutMode sur "clipBounds". Tous les éléments de mise en page respectent également les limites optiques de leurs vues enfants, en adaptant leurs propres limites en fonction des limites optiques des vues qu'elles contiennent. Toutefois, les éléments de mise en page (sous-classes de ViewGroup) ne sont actuellement pas compatibles avec les limites optiques pour les images Nine-Patch appliquées à leur propre arrière-plan.

    Si vous créez une vue personnalisée en sous-classant View, ViewGroup ou l'une de ses sous-classes, votre vue héritera de ces comportements de liaison optique.

    Remarque:Tous les widgets compatibles avec le thème Holo ont été mis à jour avec des limites optiques, y compris Button, Spinner, EditText, etc. Vous pouvez donc en profiter immédiatement en définissant l'attribut android:layoutMode sur "opticalBounds" si votre application applique un thème Holo (Theme.Holo, Theme.Holo.Light, etc.).

    Pour spécifier des limites optiques pour vos propres images Nine-Patch avec l'outil Draw 9-patch, maintenez la touche Ctrl enfoncée lorsque vous cliquez sur les pixels de bordure.

    Animation pour les valeurs Rect

    Vous pouvez désormais effectuer une animation entre deux valeurs Rect avec le nouveau RectEvaluator. Cette nouvelle classe est une implémentation de TypeEvaluator que vous pouvez transmettre à ValueAnimator.setEvaluator().

    Association de fenêtres et écouteur de focus

    Auparavant, si vous vouliez écouter le moment où votre vue était associée/détachée à la fenêtre ou lorsque sa cible changeait, vous deviez remplacer la classe View pour implémenter onAttachedToWindow() et onDetachedFromWindow(), ou onWindowFocusChanged(), respectivement.

    Désormais, pour recevoir des événements d'association et de dissociation, vous pouvez implémenter ViewTreeObserver.OnWindowAttachListener et le définir sur une vue avec addOnWindowAttachListener(). Pour recevoir des événements de sélection, vous pouvez implémenter ViewTreeObserver.OnWindowFocusChangeListener et le définir sur une vue avec addOnWindowFocusChangeListener().

    Compatibilité avec le surbalayage TV

    Pour vous assurer que votre application occupe tout l'écran sur tous les téléviseurs, vous pouvez désormais activer le surbalayage pour la mise en page de votre application. Le mode de surbalayage est déterminé par l'indicateur FLAG_LAYOUT_IN_OVERSCAN, que vous pouvez activer avec des thèmes de plate-forme tels que Theme_DeviceDefault_NoActionBar_Overscan ou en activant le style windowOverscan dans un thème personnalisé.

    Orientation de l'écran

    L'attribut screenOrientation de la balise <activity> accepte désormais des valeurs supplémentaires afin de respecter les préférences de rotation automatique de l'utilisateur:

    "userLandscape"
    Se comporte de la même manière que "sensorLandscape", sauf si l'utilisateur désactive la rotation automatique. Elle se verrouille alors en mode paysage normal et ne retourne pas.
    "userPortrait"
    Se comporte de la même manière que "sensorPortrait", sauf que si l'utilisateur désactive la rotation automatique, elle se verrouille en mode portrait normal et ne retourne pas.
    "fullUser"
    Se comporte la même chose que "fullSensor" et autorise la rotation dans les quatre sens, sauf si l'utilisateur désactive la rotation automatique, le verrouillage se fait dans l'orientation préférée de l'utilisateur.

    De plus, vous pouvez désormais déclarer "locked" pour verrouiller l'orientation de votre application dans l'orientation actuelle de l'écran.

    Animations de rotation

    Le nouveau champ rotationAnimation dans WindowManager vous permet de sélectionner l'une des trois animations à utiliser lorsque le système change d'orientation de l'écran. Les trois animations sont les suivantes:

    Remarque:Ces animations ne sont disponibles que si vous avez configuré votre activité pour utiliser le mode "Plein écran", que vous pouvez activer avec des thèmes tels que Theme.Holo.NoActionBar.Fullscreen.

    Par exemple, voici comment activer l'animation "Fondu enchaîné" :

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val params: WindowManager.LayoutParams = window.attributes
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE
        window.attributes = params
        ...
    }
    

    Java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
        getWindow().setAttributes(params);
        ...
    }
    

    Entrée utilisateur

    Nouveaux types de capteurs

    Le nouveau capteur TYPE_GAME_ROTATION_VECTOR vous permet de détecter les rotations de l'appareil sans vous soucier des interférences magnétiques. Contrairement au capteur TYPE_ROTATION_VECTOR, le TYPE_GAME_ROTATION_VECTOR n'est pas basé sur le nord magnétique.

    Les nouveaux capteurs TYPE_GYROSCOPE_UNCALIBRATED et TYPE_MAGNETIC_FIELD_UNCALIBRATED fournissent des données de capteurs brutes sans tenir compte des estimations de biais. Autrement dit, les capteurs TYPE_GYROSCOPE et TYPE_MAGNETIC_FIELD existants fournissent des données de capteurs qui tiennent compte du biais estimé de la dérive gyroscopique et du fer dur de l'appareil, respectivement. Les nouvelles versions "non calibrées" de ces capteurs fournissent à la place les données brutes des capteurs et présentent les valeurs de biais estimées séparément. Ces capteurs vous permettent de proposer un étalonnage personnalisé des données de capteurs en renforçant le biais estimé à l'aide de données externes.

    Écouteur des notifications

    Android 4.3 ajoute une nouvelle classe de service, NotificationListenerService, qui permet à votre application de recevoir des informations sur les nouvelles notifications lorsqu'elles sont publiées par le système.

    Si votre application utilise actuellement les API des services d'accessibilité pour accéder aux notifications système, vous devez la mettre à jour pour qu'elle utilise ces API à la place.

    Contacts Provider

    Requête pour "contactables"

    La nouvelle requête du fournisseur de contacts, Contactables.CONTENT_URI, permet d'obtenir efficacement un Cursor contenant toutes les adresses e-mail et tous les numéros de téléphone appartenant à tous les contacts correspondant à la requête spécifiée.

    Requête pour les deltas de contacts

    De nouvelles API ont été ajoutées à Contacts Provider pour vous permettre d'interroger efficacement les modifications récentes apportées aux données des contacts. Auparavant, votre application pouvait recevoir une notification en cas de modification dans les données des contacts. Toutefois, vous ne sauriez pas exactement ce qui a changé et vous deviez récupérer tous les contacts, puis les itérer pour identifier le changement.

    Pour suivre les modifications apportées aux insertions et aux mises à jour, vous pouvez désormais inclure le paramètre CONTACT_LAST_UPDATED_TIMESTAMP dans votre sélection afin de n'interroger que les contacts qui ont été modifiés depuis la dernière fois que vous avez interrogé le fournisseur.

    Pour vous permettre de savoir quels contacts ont été supprimés, le nouveau tableau ContactsContract.DeletedContacts fournit un journal des contacts qui ont été supprimés (mais chaque contact supprimé est conservé dans ce tableau pendant une durée limitée). Comme pour CONTACT_LAST_UPDATED_TIMESTAMP, vous pouvez utiliser le nouveau paramètre de sélection, CONTACT_DELETED_TIMESTAMP, pour vérifier quels contacts ont été supprimés depuis la dernière fois que vous avez interrogé le fournisseur. La table contient également la constante DAYS_KEPT_MILLISECONDS, qui indique le nombre de jours (en millisecondes) pendant lesquels le journal sera conservé.

    En outre, le fournisseur de contacts diffuse désormais l'action CONTACTS_DATABASE_CREATED lorsque l'utilisateur efface le stockage des contacts via le menu des paramètres système, recréant ainsi la base de données du fournisseur de contacts. Elle sert à signaler aux applications qu'elles doivent supprimer toutes les informations de contact qu'elles ont stockées et les actualiser avec une nouvelle requête.

    Si vous souhaitez obtenir un exemple de code utilisant ces API pour vérifier les modifications apportées aux contacts, consultez l'exemple ApiDemos disponible dans le téléchargement des exemples de SDK.

    Localisation

    Amélioration de la compatibilité avec le texte bidirectionnel

    Les versions précédentes d'Android prennent en charge les langues et la mise en page qui se lisent de droite à gauche, mais ne gèrent parfois pas correctement le texte dans le sens mixte. Android 4.3 ajoute donc les API BidiFormatter qui vous aident à mettre en forme correctement le texte avec du contenu dans le sens opposé sans en altérer aucune partie.

    Par exemple, lorsque vous souhaitez créer une phrase avec une variable de chaîne, comme "Essayez avec cette orthographe : 15 Bay Street, Laurel, Californie ?", vous transmettez normalement une ressource de chaîne localisée et la variable à String.format() :

    Kotlin

    val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
    

    Java

    Resources res = getResources();
    String suggestion = String.format(res.getString(R.string.did_you_mean), address);
    

    Toutefois, si les paramètres régionaux sont l'hébreu, la chaîne mise en forme s'affiche comme suit:

    האם התכוונת ל 15 Bay Street, Laurel, CA?

    C'est faux, car le "15" devrait rester à gauche de "Bay Street". La solution consiste à utiliser BidiFormatter et sa méthode unicodeWrap(). Par exemple, le code ci-dessus devient:

    Kotlin

    val bidiFormatter = BidiFormatter.getInstance()
    val suggestion = String.format(
            resources.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address)
    )
    

    Java

    Resources res = getResources();
    BidiFormatter bidiFormatter = BidiFormatter.getInstance();
    String suggestion = String.format(res.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address));
    

    Par défaut, unicodeWrap() utilise la méthode heuristique d'estimation de l'orientation du texte la plus forte, ce qui peut poser des erreurs si le premier signal d'orientation du texte ne représente pas l'orientation appropriée pour le contenu dans son ensemble. Si nécessaire, vous pouvez spécifier une heuristique différente en transmettant l'une des constantes TextDirectionHeuristic de TextDirectionHeuristics à unicodeWrap().

    Remarque:Ces nouvelles API sont également disponibles pour les versions précédentes d'Android via la bibliothèque Support Android, avec la classe BidiFormatter et les API associées.

    Services d'accessibilité

    Gérer les événements clés

    Un AccessibilityService peut désormais recevoir un rappel pour les événements d'entrée de touche avec la méthode de rappel onKeyEvent(). Cela permet à votre service d'accessibilité de gérer les entrées des périphériques d'entrée à touches telles qu'un clavier et de traduire ces événements en actions spéciales qui n'étaient auparavant possibles qu'avec la saisie tactile ou le pavé directionnel de l'appareil.

    Sélectionner du texte et le copier-coller

    AccessibilityNodeInfo fournit désormais des API qui permettent à un AccessibilityService de sélectionner, couper, copier et coller du texte dans un nœud.

    Pour spécifier la sélection du texte à couper ou copier, votre service d'accessibilité peut utiliser la nouvelle action ACTION_SET_SELECTION, en lui transmettant les positions de début et de fin de la sélection avec ACTION_ARGUMENT_SELECTION_START_INT et ACTION_ARGUMENT_SELECTION_END_INT. Vous pouvez également sélectionner du texte en manipulant la position du curseur à l'aide de l'action existante, ACTION_NEXT_AT_MOVEMENT_GRANULARITY (auparavant réservée à déplacer la position du curseur), et en ajoutant l'argument ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN.

    Vous pouvez ensuite couper ou copier avec ACTION_CUT ou ACTION_COPY, puis coller ultérieurement avec ACTION_PASTE.

    Remarque:Ces nouvelles API sont également disponibles pour les versions précédentes d'Android via la bibliothèque Support Android, avec la classe AccessibilityNodeInfoCompat.

    Déclarer des fonctionnalités d'accessibilité

    À partir de la version 4.3 d'Android, un service d'accessibilité doit déclarer les fonctionnalités d'accessibilité dans son fichier de métadonnées afin de pouvoir en utiliser certaines. Si la capacité n'est pas demandée dans le fichier de métadonnées, il s'agit d'une fonctionnalité no-op. Pour déclarer les fonctionnalités d'accessibilité de votre service, vous devez utiliser des attributs XML correspondant aux différentes constantes "capability" de la classe AccessibilityServiceInfo.

    Par exemple, si un service ne demande pas la fonctionnalité flagRequestFilterKeyEvents, il ne recevra pas d'événements de touche.

    Tests et débogage

    Tests automatisés de l'interface utilisateur

    La nouvelle classe UiAutomation fournit des API qui vous permettent de simuler des actions utilisateur pour l'automatisation des tests. En utilisant les API AccessibilityService de la plate-forme, les API UiAutomation vous permettent d'inspecter le contenu de l'écran, et d'injecter des événements de clavier et des événements tactiles arbitraires.

    Pour obtenir une instance de UiAutomation, appelez Instrumentation.getUiAutomation(). Pour que cela fonctionne, vous devez fournir l'option -w avec la commande instrument lorsque vous exécutez InstrumentationTestCase à partir de adb shell.

    Avec l'instance UiAutomation, vous pouvez exécuter des événements arbitraires pour tester votre application. Pour ce faire, appelez executeAndWaitForEvent(), transmettez-lui un Runnable à effectuer, un délai avant expiration pour l'opération et une implémentation de l'interface UiAutomation.AccessibilityEventFilter. C'est dans votre implémentation UiAutomation.AccessibilityEventFilter que vous recevrez un appel vous permettant de filtrer les événements qui vous intéressent et de déterminer la réussite ou l'échec d'un scénario de test donné.

    Pour observer tous les événements lors d'un test, créez une implémentation de UiAutomation.OnAccessibilityEventListener et transmettez-la à setOnAccessibilityEventListener(). Votre interface d'écouteur reçoit ensuite un appel à onAccessibilityEvent() chaque fois qu'un événement se produit, recevant un objet AccessibilityEvent qui le décrit.

    Les API UiAutomation exposent diverses autres opérations à un niveau très bas pour encourager le développement d'outils de test d'interface utilisateur tels que uiautomator. Par exemple, UiAutomation peut également:

    • Injecter des événements d'entrée
    • Modifier l'orientation de l'écran
    • Réaliser des captures d'écran

    Et surtout, pour les outils de test de l'interface utilisateur, les API UiAutomation fonctionnent au-delà des limites des applications, contrairement à celles de Instrumentation.

    Événements Systrace pour les applis

    Android 4.3 ajoute la classe Trace avec deux méthodes statiques, beginSection() et endSection(), qui vous permettent de définir des blocs de code à inclure dans le rapport Systrace. En créant des sections de code traçable dans votre application, les journaux Systrace vous fournissent une analyse beaucoup plus détaillée de l'endroit où le ralentissement se produit dans votre application.

    Pour en savoir plus sur l'utilisation de l'outil Systrace, consultez Analyser l'affichage et les performances avec Systrace.

    Sécurité

    Magasin de clés Android pour les clés privées d'application

    Android propose désormais un fournisseur de sécurité Java personnalisé dans l'installation KeyStore, appelé Android Key Store, qui vous permet de générer et d'enregistrer des clés privées susceptibles d'être affichées et utilisées uniquement par votre application. Pour charger Android Key Store, transmettez "AndroidKeyStore" à KeyStore.getInstance().

    Pour gérer les identifiants privés de votre application dans l'Android Key Store, générez une nouvelle clé avec KeyPairGenerator avec KeyPairGeneratorSpec. Commencez par obtenir une instance de KeyPairGenerator en appelant getInstance(). Appelez ensuite initialize(), en lui transmettant une instance de KeyPairGeneratorSpec, que vous pouvez obtenir à l'aide de KeyPairGeneratorSpec.Builder. Enfin, obtenez votre KeyPair en appelant generateKeyPair().

    Stockage des identifiants matériels

    Android est désormais compatible avec le stockage matériel pour vos identifiants KeyChain, ce qui renforce la sécurité en rendant les clés indisponibles pour l'extraction. Autrement dit, une fois que les clés se trouvent dans un magasin de clés intégré au matériel (élément sécurisé, TPM ou TrustZone), elles peuvent être utilisées pour des opérations de chiffrement, mais le matériel de clé privée ne peut pas être exporté. Même le noyau OS ne peut pas accéder à ce matériel de clé. Bien que tous les appareils Android ne soient pas compatibles avec le stockage sur le matériel, vous pouvez vérifier au moment de l'exécution si un espace de stockage intégré au matériel est disponible en appelant KeyChain.IsBoundKeyAlgorithm().

    Déclarations du fichier manifeste

    Fonctionnalités requises déclarables

    Les valeurs suivantes sont désormais compatibles avec l'élément <uses-feature> afin que vous puissiez vous assurer que votre application n'est installée que sur les appareils qui fournissent les fonctionnalités dont elle a besoin.

    FEATURE_APP_WIDGETS
    Indique que votre application fournit un widget d'application et ne doit être installée que sur les appareils dotés d'un écran d'accueil ou d'un emplacement similaire où les utilisateurs peuvent intégrer des widgets d'application. Exemple :
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    
    FEATURE_HOME_SCREEN
    Déclare que votre application se comporte comme un remplacement de l'écran d'accueil et ne doit être installée que sur les appareils compatibles avec les applications tierces de l'écran d'accueil. Exemple :
    <uses-feature android:name="android.software.home_screen" android:required="true" />
    
    FEATURE_INPUT_METHODS
    Indique que votre application fournit un mode de saisie personnalisé (un clavier créé avec InputMethodService) et ne doit être installée que sur les appareils compatibles avec les modes de saisie tiers. Exemple :
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    
    FEATURE_BLUETOOTH_LE
    Indique que votre application utilise des API Bluetooth Low Energy et ne doit être installée que sur des appareils capables de communiquer avec d'autres appareils via Bluetooth Low Energy. Exemple :
    <uses-feature android:name="android.software.bluetooth_le" android:required="true" />
    

    Autorisations utilisateur

    Les valeurs suivantes sont désormais prises en charge dans <uses-permission> pour déclarer les autorisations dont votre application a besoin pour accéder à certaines API.

    BIND_NOTIFICATION_LISTENER_SERVICE
    Obligatoire pour utiliser les nouvelles API NotificationListenerService.
    SEND_RESPOND_VIA_MESSAGE
    Obligatoire pour recevoir l'intent ACTION_RESPOND_VIA_MESSAGE.

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