Créer des blocs "Réglages rapides" personnalisés pour votre application

Les Réglages rapides sont des blocs affichés dans le panneau des Réglages rapides. Ils représentent des actions sur lesquelles les utilisateurs peuvent appuyer pour effectuer rapidement des tâches récurrentes. Votre application peut fournir un bloc personnalisé aux utilisateurs via la classe TileService et utiliser un objet Tile pour suivre l'état du bloc. Par exemple, vous pouvez créer un bloc qui permet aux utilisateurs d'activer ou de désactiver un VPN fourni par votre application.

Panneau Réglages rapides avec le bloc VPN activé et désactivé
Figure 1. Panneau Réglages rapides avec le bloc VPN activé et désactivé.

Décider quand créer une vignette

Nous vous recommandons de créer des cartes pour des fonctionnalités spécifiques auxquelles vous vous attendez à ce que les utilisateurs accèdent souvent ou rapidement (ou les deux). Les tuiles les plus efficaces sont celles qui présentent ces deux qualités, car elles permettent d'accéder rapidement aux actions fréquemment effectuées.

Par exemple, vous pouvez créer une vignette pour une application de fitness qui permet aux utilisateurs de démarrer rapidement une séance d'entraînement. Toutefois, nous vous déconseillons de créer une vignette pour la même application qui permettrait aux utilisateurs de consulter l'intégralité de leur historique d'entraînement.

Cas d'utilisation des cartes d'applications de fitness
Figure 2. Exemples de tuiles recommandées et non recommandées pour une application de fitness.

Pour améliorer la visibilité et la facilité d'utilisation de votre tuile, nous vous recommandons d'éviter certaines pratiques :

  • Évitez d'utiliser des tuiles pour lancer une application. Utilisez plutôt un raccourci d'application ou un lanceur d'applications standard.

  • Évitez d'utiliser des tuiles pour les actions ponctuelles des utilisateurs. Utilisez plutôt un raccourci d'application ou une notification.

  • Évitez de créer trop de cartes. Nous vous recommandons de ne pas en utiliser plus de deux par application. Utilisez plutôt un raccourci d'application.

  • Évitez d'utiliser des tuiles qui affichent des informations, mais qui ne sont pas interactives pour les utilisateurs. Utilisez plutôt une notification ou un widget.

Créer votre vignette

Pour créer un bloc, vous devez d'abord créer une icône de bloc appropriée, puis créer et déclarer votre TileService dans le fichier manifeste de votre application.

L'exemple de réglages rapides montre comment créer et gérer un bloc.

Créer votre icône personnalisée

Vous devrez fournir une icône personnalisée qui s'affichera sur la tuile du panneau "Réglages rapides". (Vous ajouterez cette icône lorsque vous déclarerez TileService, comme décrit dans la section suivante.) L'icône doit être blanche unie avec un arrière-plan transparent, mesurer 24 x 24 dp et être au format VectorDrawable.

Exemple de drawable vectoriel
Figure 3. Exemple de drawable vectoriel.

Créez une icône qui indique visuellement l'objectif de votre carte. Cela permet aux utilisateurs d'identifier facilement si votre carte répond à leurs besoins. Par exemple, vous pouvez créer une icône de chronomètre pour une tuile d'application de fitness qui permet aux utilisateurs de démarrer une séance d'entraînement.

Créer et déclarer votre TileService

Créez un service pour votre carte qui étend la classe TileService.

Kotlin

class MyQSTileService: TileService() {

  // Called when the user adds your tile.
  override fun onTileAdded() {
    super.onTileAdded()
  }
  // Called when your app can update your tile.
  override fun onStartListening() {
    super.onStartListening()
  }

  // Called when your app can no longer update your tile.
  override fun onStopListening() {
    super.onStopListening()
  }

  // Called when the user taps on your tile in an active or inactive state.
  override fun onClick() {
    super.onClick()
  }
  // Called when the user removes your tile.
  override fun onTileRemoved() {
    super.onTileRemoved()
  }
}

Java

public class MyQSTileService extends TileService {

  // Called when the user adds your tile.
  @Override
  public void onTileAdded() {
    super.onTileAdded();
  }

  // Called when your app can update your tile.
  @Override
  public void onStartListening() {
    super.onStartListening();
  }

  // Called when your app can no longer update your tile.
  @Override
  public void onStopListening() {
    super.onStopListening();
  }

  // Called when the user taps on your tile in an active or inactive state.
  @Override
  public void onClick() {
    super.onClick();
  }

  // Called when the user removes your tile.
  @Override
  public void onTileRemoved() {
    super.onTileRemoved();
  }
}

Déclarez votre TileService dans le fichier manifeste de votre application. Ajoutez le nom et le libellé de votre TileService, l'icône personnalisée que vous avez créée dans la section précédente et l'autorisation appropriée.

 <service
     android:name=".MyQSTileService"
     android:exported="true"
     android:label="@string/my_default_tile_label"  // 18-character limit.
     android:icon="@drawable/my_default_icon_label"
     android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
     <intent-filter>
         <action android:name="android.service.quicksettings.action.QS_TILE" />
     </intent-filter>
 </service>

Gérer votre TileService

Une fois que vous avez créé et déclaré votre TileService dans le fichier manifeste de votre application, vous devez gérer son état.

TileService est un service lié. Votre TileService est lié lorsque votre application le demande ou si le système doit communiquer avec lui. Un cycle de vie de service lié typique contient les quatre méthodes de rappel suivantes : onCreate(), onBind(), onUnbind() et onDestroy(). Ces méthodes sont appelées par le système chaque fois que le service entre dans une nouvelle phase du cycle de vie.

Présentation du cycle de vie de TileService

En plus des rappels qui contrôlent le cycle de vie du service lié, vous devez implémenter d'autres méthodes spécifiques au cycle de vie TileService. Ces méthodes peuvent être appelées en dehors de onCreate() et onDestroy(), car les méthodes de cycle de vie Service et TileService sont appelées dans deux threads asynchrones distincts.

Le cycle de vie TileService contient les méthodes suivantes, qui sont appelées par le système chaque fois que votre TileService entre dans une nouvelle phase du cycle de vie :

  • onTileAdded() : cette méthode n'est appelée que lorsque l'utilisateur ajoute votre bloc pour la première fois, et s'il le supprime et l'ajoute à nouveau. C'est le meilleur moment pour effectuer une initialisation ponctuelle. Toutefois, cela ne suffit pas toujours pour l'initialisation.

  • onStartListening() et onStopListening() : ces méthodes sont appelées chaque fois que votre application met à jour le bloc, et ce, fréquemment. TileService reste lié entre onStartListening() et onStopListening(), ce qui permet à votre application de modifier le bloc et d'envoyer des mises à jour.

  • onTileRemoved() : cette méthode n'est appelée que si l'utilisateur supprime votre carte.

Sélectionner un mode d'écoute

Votre TileService écoute en mode actif ou non actif. Nous vous recommandons d'utiliser le mode actif, que vous devrez déclarer dans le fichier manifeste de l'application. Sinon, TileService est le mode standard et n'a pas besoin d'être déclaré.

Ne partez pas du principe que votre TileService existera en dehors de la paire de méthodes onStartListening() et onStopListening().

Utilisez le mode actif pour un TileService qui écoute et surveille son état dans son propre processus. Un TileService en mode actif est lié à onTileAdded(), onTileRemoved(), aux événements d'appui et lorsqu'il est demandé par le processus de l'application.

Nous vous recommandons le mode actif si votre TileService est averti lorsque l'état de votre carte doit être mis à jour par son propre processus. Les tuiles actives limitent la charge sur le système, car elles n'ont pas besoin d'être liées chaque fois que le panneau des paramètres rapides devient visible pour l'utilisateur.

La méthode statique TileService.requestListeningState() peut être appelée pour demander le début de l'état d'écoute et recevoir un rappel à onStartListening().

Vous pouvez déclarer le mode actif en ajoutant META_DATA_ACTIVE_TILE au fichier manifeste de votre application.

<service ...>
    <meta-data android:name="android.service.quicksettings.ACTIVE_TILE"
         android:value="true" />
    ...
</service>

Mode inactif

Le mode non actif est le mode standard. Un TileService est en mode non actif s'il est lié chaque fois que votre carte est visible par l'utilisateur. Cela signifie que votre TileService peut être créé et lié à nouveau à des moments qui échappent à son contrôle. Il peut également être non lié et détruit lorsque l'utilisateur ne regarde pas la vignette.

Votre application reçoit un rappel à onStartListening() une fois que l'utilisateur a ouvert son panneau Paramètres rapides. Vous pouvez mettre à jour votre objet Tile autant de fois que vous le souhaitez entre onStartListening() et onStopListening().

Vous n'avez pas besoin de déclarer le mode non actif. Il vous suffit de ne pas ajouter META_DATA_ACTIVE_TILE au fichier manifeste de votre application.

Présentation des états des cartes

Une fois qu'un utilisateur a ajouté votre carte, elle se trouve toujours dans l'un des états suivants.

  • STATE_ACTIVE : indique un état activé. L'utilisateur peut interagir avec votre carte dans cet état.

    Par exemple, pour une carte d'application de fitness qui permet aux utilisateurs de lancer une séance d'entraînement chronométrée, STATE_ACTIVE signifie que l'utilisateur a lancé une séance d'entraînement et que le minuteur est en cours d'exécution.

  • STATE_INACTIVE : indique un état désactivé ou mis en veille. L'utilisateur peut interagir avec votre carte dans cet état.

    Pour reprendre l'exemple de la vignette de l'application de fitness, une vignette dans STATE_INACTIVE signifie que l'utilisateur n'a pas lancé de séance d'entraînement, mais qu'il pourrait le faire s'il le souhaitait.

  • STATE_UNAVAILABLE : indique un état temporairement indisponible. Dans cet état, l'utilisateur ne peut pas interagir avec votre vignette.

    Par exemple, une vignette dans STATE_UNAVAILABLE signifie que, pour une raison ou une autre, elle n'est pas disponible pour l'utilisateur.

Le système ne définit que l'état initial de votre objet Tile. Vous définissez l'état de l'objet Tile tout au long du reste de son cycle de vie.

Le système peut teinter l'icône et l'arrière-plan de la carte pour refléter l'état de votre objet Tile. Les objets Tile définis sur STATE_ACTIVE sont les plus sombres, tandis que STATE_INACTIVE et STATE_UNAVAILABLE sont de plus en plus clairs. La teinte exacte dépend du fabricant et de la version.

Bloc VPN teinté pour refléter les états des objets
Figure 4. Exemples de cartes teintées pour refléter l'état de la carte (états actif, inactif et indisponible, respectivement).

Modifier votre carte

Vous pouvez mettre à jour votre carte une fois que vous avez reçu un appel de onStartListening(). Selon le mode de la tuile, celle-ci peut être mise à jour au moins une fois jusqu'à ce qu'un rappel soit reçu pour onStopListening().

En mode actif, vous ne pouvez mettre à jour votre carte qu'une seule fois avant de recevoir un rappel à onStopListening(). En mode inactif, vous pouvez mettre à jour votre carte autant de fois que vous le souhaitez entre onStartListening() et onStopListening().

Vous pouvez récupérer votre objet Tile en appelant getQsTile(). Pour mettre à jour des champs spécifiques de votre objet Tile, appelez les méthodes suivantes :

Vous devez appeler updateTile() pour mettre à jour votre carte une fois que vous avez défini les champs de l'objet Tile sur les valeurs correctes. Le système analysera alors les données de tuile mises à jour et actualisera l'UI.

Kotlin

data class StateModel(val enabled: Boolean, val label: String, val icon: Icon)

override fun onStartListening() {
  super.onStartListening()
  val state = getStateFromService()
  qsTile.label = state.label
  qsTile.contentDescription = tile.label
  qsTile.state = if (state.enabled) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.icon = state.icon
  qsTile.updateTile()
}

Java

public class StateModel {
  final boolean enabled;
  final String label;
  final Icon icon;

  public StateModel(boolean e, String l, Icon i) {
    enabled = e;
    label = l;
    icon = i;
  }
}

@Override
public void onStartListening() {
  super.onStartListening();
  StateModel state = getStateFromService();
  Tile tile = getQsTile();
  tile.setLabel(state.label);
  tile.setContentDescription(state.label);
  tile.setState(state.enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setIcon(state.icon);
  tile.updateTile();
}

Gérer les gestes d'appui

Les utilisateurs peuvent appuyer sur votre carte pour déclencher une action si elle se trouve dans STATE_ACTIVE ou STATE_INACTIVE. Le système appelle ensuite le rappel onClick() de votre application.

Une fois que votre application a reçu un rappel pour onClick(), elle peut lancer une boîte de dialogue ou une activité, déclencher un travail en arrière-plan ou modifier l'état de votre vignette.

Kotlin

var clicks = 0
override fun onClick() {
  super.onClick()
  counter++
  qsTile.state = if (counter % 2 == 0) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.label = "Clicked $counter times"
  qsTile.contentDescription = qsTile.label
  qsTile.updateTile()
}

Java

int clicks = 0;

@Override
public void onClick() {
  super.onClick();
  counter++;
  Tile tile = getQsTile();
  tile.setState((counter % 2 == 0) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setLabel("Clicked " + counter + " times");
  tile.setContentDescription(tile.getLabel());
  tile.updateTile();
}

Lancer une boîte de dialogue

showDialog() réduit le panneau de configuration rapide et affiche une boîte de dialogue. Utilisez une boîte de dialogue pour ajouter du contexte à votre action si elle nécessite une saisie supplémentaire ou le consentement de l'utilisateur.

Lancer une activité

startActivityAndCollapse() démarre une activité tout en réduisant le panneau. Les activités sont utiles si vous souhaitez afficher des informations plus détaillées que dans une boîte de dialogue ou si votre action est très interactive.

Si votre application nécessite une interaction utilisateur importante, elle ne doit lancer une activité qu'en dernier recours. Envisagez plutôt d'utiliser une boîte de dialogue ou un bouton bascule.

Si l'utilisateur appuie de manière prolongée sur une vignette, l'écran Infos sur l'appli s'affiche. Pour remplacer ce comportement et lancer une activité permettant de définir des préférences, ajoutez un <intent-filter> à l'une de vos activités avec ACTION_QS_TILE_PREFERENCES.

À partir de l'API Android 28, le PendingIntent doit disposer du Intent.FLAG_ACTIVITY_NEW_TASK :

if (Build.VERSION.SDK_INT >= 28) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

Vous pouvez également ajouter l'option AndroidManifest.xml dans la section Activity spécifique.

Marquer votre carte comme activable/désactivable

Nous vous recommandons de marquer votre carte comme activable/désactivable si elle fonctionne principalement comme un bouton à deux états (ce qui est le comportement le plus courant des cartes). Cela permet de fournir des informations sur le comportement du bloc au système d'exploitation et d'améliorer l'accessibilité globale.

Définissez les métadonnées TOGGLEABLE_TILE sur true pour marquer votre tuile comme pouvant être activée ou désactivée.

<service ...>
  <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
    android:value="true" />
</service>

Effectuer uniquement des actions sécurisées sur les appareils verrouillés de manière sécurisée

Il est possible que votre carte s'affiche au-dessus de l'écran de verrouillage sur les appareils verrouillés. Si le bloc contient des informations sensibles, vérifiez la valeur de isSecure() pour déterminer si l'appareil est dans un état sécurisé. Votre TileService doit alors modifier son comportement en conséquence.

Si l'action de la tuile peut être effectuée en mode verrouillé, utilisez startActivity() pour lancer une activité au-dessus de l'écran de verrouillage.

Si l'action de la carte n'est pas sécurisée, utilisez unlockAndRun() pour inviter l'utilisateur à déverrouiller son appareil. En cas de succès, le système exécute l'objet Runnable que vous transmettez à cette méthode.

Inviter l'utilisateur à ajouter votre carte

Pour ajouter manuellement votre tuile, les utilisateurs doivent suivre plusieurs étapes :

  1. Balayez l'écran vers le bas pour ouvrir le panneau "Réglages rapides".
  2. Appuyez sur le bouton "Modifier".
  3. Faites défiler toutes les tuiles sur votre appareil jusqu'à ce que vous trouviez la vôtre.
  4. Appuyez de manière prolongée sur la vignette, puis faites-la glisser vers la liste des vignettes actives.

L'utilisateur peut également déplacer ou supprimer votre tuile à tout moment.

À partir d'Android 13, vous pouvez utiliser la méthode requestAddTileService() pour permettre aux utilisateurs d'ajouter beaucoup plus facilement votre carte à un appareil. Cette méthode invite les utilisateurs à ajouter rapidement votre bloc directement à leur panneau Paramètres rapides. L'invite inclut le nom de l'application, le libellé fourni et l'icône.

Invite de l&#39;API Quick Settings Placement
Figure 5 : Invite de l'API Quick Settings Placement.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

Le rappel contient des informations indiquant si le bloc a été ajouté ou non, s'il était déjà présent ou si une erreur s'est produite.

Faites preuve de discernement lorsque vous décidez quand et à quelle fréquence inviter les utilisateurs. Nous vous recommandons d'appeler requestAddTileService() uniquement dans le contexte, par exemple lorsque l'utilisateur interagit pour la première fois avec une fonctionnalité facilitée par votre carte.

Le système peut choisir d'arrêter de traiter les demandes pour un ComponentName donné si l'utilisateur l'a refusé un certain nombre de fois auparavant. L'utilisateur est déterminé à partir de Context utilisé pour récupérer ce service. Il doit correspondre à l'utilisateur actuel.