Creare riquadri delle Impostazioni rapide personalizzati per la tua app

Le Impostazioni rapide sono riquadri visualizzati nel riquadro Impostazioni rapide, che rappresentano azioni che gli utenti possono toccare per completare rapidamente le attività ricorrenti. La tua app può fornire un riquadro personalizzato agli utenti tramite la TileService classe e utilizzare un oggetto Tile per monitorare lo stato del riquadro. Ad esempio, potresti creare un riquadro che consenta agli utenti di attivare o disattivare una VPN fornita dalla tua app.

Riquadro Impostazioni rapide con il riquadro della VPN attivato
  e disattivato
Figura 1. Riquadro Impostazioni rapide con il riquadro VPN attivato e disattivato.

Decidere quando creare un riquadro

Ti consigliamo di creare riquadri per funzionalità specifiche a cui prevedi che gli utenti accedano spesso o a cui debbano accedere rapidamente (o entrambe le cose). I riquadri più efficaci sono quelli che soddisfano entrambe queste qualità, fornendo un accesso rapido alle azioni eseguite di frequente.

Ad esempio, potresti creare un riquadro per un'app di fitness che consenta agli utenti di avviare rapidamente una sessione di allenamento. Tuttavia, non ti consigliamo di creare un riquadro per la stessa app che consenta agli utenti di esaminare l'intera cronologia degli allenamenti.

Casi d'uso del riquadro dell'app di fitness
Figura 2. Esempi di riquadri consigliati e non consigliati per un'app di fitness.

Per migliorare la rilevabilità e la facilità d'uso del riquadro, ti consigliamo di evitare alcune pratiche:

  • Evita di utilizzare i riquadri per avviare un'app. Utilizza invece una scorciatoia dell'app o un launcher standard.

  • Evita di utilizzare i riquadri per le azioni utente una tantum. Utilizza invece una scorciatoia dell'app o una notifica.

  • Evita di creare troppi riquadri. Ti consigliamo di non superare il limite di due per app. Utilizza invece una scorciatoia dell'app.

  • Evita di utilizzare riquadri che mostrano informazioni, ma non sono interattivi per gli utenti. Utilizza invece una notifica o un widget.

Creare il riquadro

Per creare un riquadro, devi prima creare un'icona del riquadro appropriata, quindi creare e dichiarare il TileService nel file manifest dell'app.

L'esempio di Impostazioni rapide fornisce un esempio di come creare e gestire un riquadro.

Creare l'icona personalizzata

Dovrai fornire un'icona personalizzata, che viene visualizzata sul riquadro nel riquadro Impostazioni rapide. (Aggiungerai questa icona quando dichiari il TileService, come descritto nella sezione successiva.) L'icona deve essere bianca piena con uno sfondo trasparente, misurare 24 x 24 dp ed essere in formato VectorDrawable.

Esempio di risorsa drawable vettoriale
Figura 3. Esempio di un elemento disegnabile vettoriale.

Crea un'icona che suggerisca visivamente lo scopo del riquadro. In questo modo gli utenti possono identificare facilmente se il riquadro soddisfa le loro esigenze. Ad esempio, potresti creare un'icona di un cronometro per un riquadro di un'app di fitness che consenta agli utenti di avviare una sessione di allenamento.

Creare e dichiarare il TileService

Crea un servizio per il riquadro che estenda 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();
  }
}

Dichiara il TileService nel file manifest dell'app. Aggiungi il nome e l'etichetta del TileService, l'icona personalizzata creata nella sezione precedente e l'autorizzazione appropriata.

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

Gestire il TileService

Dopo aver creato e dichiarato il TileService nel manifest dell'app, devi gestirne lo stato.

TileService è un servizio associato. Il TileService è associato quando viene richiesto dalla tua app o se il sistema deve comunicare con esso. Un ciclo di vita tipico di un servizio associato contiene i seguenti quattro metodi di callback: onCreate(), onBind(), onUnbind() e onDestroy(). Questi metodi vengono richiamati dal sistema ogni volta che il servizio entra in una nuova fase del ciclo di vita.

Panoramica del ciclo di vita di TileService

Oltre ai callback che controllano il ciclo di vita del servizio associato, devi implementare altri metodi specifici del ciclo di vita di TileService. Questi metodi possono essere chiamati al di fuori di onCreate() e onDestroy() perché i metodi del ciclo di vita di Service e i metodi del ciclo di vita di TileService vengono chiamati in due thread asincroni separati.

Il ciclo di vita di TileService contiene i seguenti metodi, che vengono richiamati dal sistema ogni volta che il TileService entra in una nuova fase del ciclo di vita:

  • onTileAdded(): questo metodo viene chiamato solo quando l'utente aggiunge il riquadro per la prima volta e se l'utente rimuove e aggiunge di nuovo il riquadro. Questo è il momento migliore per eseguire qualsiasi inizializzazione una tantum. Tuttavia, questa operazione potrebbe non soddisfare tutte le inizializzazioni necessarie.

  • onStartListening() e onStopListening(): questi metodi vengono chiamati ogni volta che l'app aggiorna il riquadro e vengono chiamati spesso. Il TileService rimane associato tra onStartListening() e onStopListening(), consentendo alla tua app di modificare il riquadro e inviare gli aggiornamenti.

  • onTileRemoved(): questo metodo viene chiamato solo se l'utente rimuove il riquadro.

Selezionare una modalità di ascolto

Il TileService è in modalità attiva o non attiva. Ti consigliamo di utilizzare la modalità attiva, che dovrai dichiarare nel manifest dell'app. In caso contrario, il TileService è la modalità standard e non deve essere dichiarato.

Non dare per scontato che il TileService esista al di fuori della coppia di metodi onStartListening() e onStopListening().

Utilizza la modalità attiva per un TileService che ascolta e monitora il suo stato nel proprio processo. Un TileService in modalità attiva è associato a onTileAdded(), onTileRemoved(), agli eventi di tocco e quando viene richiesto dal processo dell'app.

Ti consigliamo la modalità attiva se il TileService riceve una notifica quando il suo stato deve essere aggiornato dal proprio processo. I riquadri attivi limitano il carico sul sistema perché non devono essere associati ogni volta che il riquadro Impostazioni rapide diventa visibile all'utente.

È possibile chiamare il metodo statico TileService.requestListeningState() per richiedere l'avvio dello stato di ascolto e ricevere un callback a onStartListening().

Puoi dichiarare la modalità attiva aggiungendo META_DATA_ACTIVE_TILE al tuo file manifest dell'app.

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

Modalità non attiva

La modalità non attiva è la modalità standard. Un TileService è in modalità non attiva se è associato ogni volta che il riquadro è visibile all'utente. Ciò significa che il TileService potrebbe essere creato e associato di nuovo in momenti al di fuori del suo controllo. Inoltre, potrebbe essere dissociato e distrutto quando l'utente non visualizza il riquadro.

La tua app riceve un callback a onStartListening() dopo che l'utente apre il riquadro Impostazioni rapide. Puoi aggiornare l'oggetto Tile tutte le volte che vuoi tra onStartListening() e onStopListening().

Non è necessario dichiarare la modalità non attiva: basta non aggiungere META_DATA_ACTIVE_TILE al file manifest dell'app.

Panoramica degli stati dei riquadri

Dopo che un utente ha aggiunto il tuo riquadro, questo esiste sempre in uno dei seguenti stati.

  • STATE_ACTIVE: indica uno stato di attivazione o abilitazione. L'utente può interagire con il riquadro in questo stato.

    Ad esempio, per un riquadro di un'app di fitness che consente agli utenti di avviare una sessione di allenamento a tempo, STATE_ACTIVE significa che l'utente ha avviato una sessione di allenamento e il timer è in esecuzione.

  • STATE_INACTIVE: indica uno stato di disattivazione o pausa. L'utente può interagire con il riquadro in questo stato.

    Per utilizzare di nuovo l'esempio del riquadro dell'app di fitness, un riquadro in STATE_INACTIVE significa che l'utente non ha avviato una sessione di allenamento, ma potrebbe farlo se lo desidera.

  • STATE_UNAVAILABLE: indica uno stato temporaneamente non disponibile. L'utente non può interagire con il riquadro in questo stato.

    Ad esempio, un riquadro in STATE_UNAVAILABLE significa che il riquadro non è attualmente disponibile per l'utente per qualche motivo.

Il sistema imposta solo lo stato iniziale dell'oggetto Tile. Imposta lo stato dell'oggetto Tile per il resto del suo ciclo di vita.

Il sistema potrebbe colorare l'icona e lo sfondo del riquadro per riflettere lo stato dell'oggetto Tile. Gli oggetti Tile impostati su STATE_ACTIVE sono i più scuri, mentre STATE_INACTIVE e STATE_UNAVAILABLE sono sempre più chiari. La tonalità esatta è specifica del produttore e della versione.

Riquadro VPN colorato per riflettere gli stati degli oggetti
Figura 4. Esempi di un riquadro colorato per riflettere lo stato del riquadro (rispettivamente stati attivo, inattivo e non disponibile).

Aggiornare il riquadro

Puoi aggiornare il riquadro dopo aver ricevuto un callback a onStartListening(). A seconda della modalità del riquadro, questo può essere aggiornato almeno una volta fino a quando non riceve un callback a onStopListening().

In modalità attiva, puoi aggiornare il riquadro esattamente una volta prima di ricevere un callback a onStopListening(). In modalità non attiva, puoi aggiornare il riquadro tutte le volte che vuoi tra onStartListening() e onStopListening().

Puoi recuperare l'oggetto Tile chiamando getQsTile(). Per aggiornare campi specifici dell'oggetto Tile, chiama i seguenti metodi:

Devi chiamare updateTile() per aggiornare il riquadro dopo aver impostato i campi dell'oggetto Tile sui valori corretti. In questo modo il sistema analizzerà i dati del riquadro aggiornati e aggiornerà 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();
}

Gestire i tocchi

Gli utenti possono toccare il riquadro per attivare un'azione se il riquadro è in STATE_ACTIVE o STATE_INACTIVE. Il sistema richiama quindi il callback dell'app onClick().

Una volta che l'app riceve un callback a onClick(), può avviare una finestra di dialogo o un'attività, attivare il lavoro in background o modificare lo stato del riquadro.

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

Avviare una finestra di dialogo

showDialog() comprime il riquadro Impostazioni rapide e mostra una finestra di dialogo. Utilizza una finestra di dialogo per aggiungere contesto all'azione se richiede input aggiuntivi o il consenso dell'utente.

Avviare un'attività

startActivityAndCollapse() avvia un'attività comprimendo il riquadro. Le attività sono utili se sono presenti informazioni più dettagliate da visualizzare rispetto a una finestra di dialogo o se l'azione è altamente interattiva.

Se l'app richiede un'interazione utente significativa, deve avviare un'attività solo come ultima risorsa. In alternativa, valuta la possibilità di utilizzare una finestra di dialogo o un pulsante di attivazione/disattivazione.

Un tocco prolungato su un riquadro visualizza la schermata Informazioni app per l'utente. Per sostituire questo comportamento e avviare invece un'attività per l'impostazione delle preferenze, aggiungi un <intent-filter> a una delle tue attività con ACTION_QS_TILE_PREFERENCES.

A partire dall'API Android 28, il PendingIntent deve avere Intent.FLAG_ACTIVITY_NEW_TASK:

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

In alternativa, puoi aggiungere il flag in AndroidManifest.xml nella sezione Activity specifica.

Contrassegnare il riquadro come attivabile/disattivabile

Ti consigliamo di contrassegnare il riquadro come attivabile/disattivabile se funziona principalmente come un interruttore a due stati (che è il comportamento più comune dei riquadri). In questo modo vengono fornite informazioni sul comportamento del riquadro al sistema operativo e viene migliorata l'accessibilità complessiva.

Imposta i metadati TOGGLEABLE_TILE su true per contrassegnare il riquadro come attivabile/disattivabile.

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

Eseguire solo azioni sicure sui dispositivi bloccati in modo sicuro

Il riquadro potrebbe essere visualizzato sopra la schermata di blocco sui dispositivi bloccati. Se il riquadro contiene informazioni sensibili, controlla il valore di isSecure() per determinare se il dispositivo è in uno stato sicuro e il TileService deve modificare il suo comportamento di conseguenza.

Se l'azione del riquadro è sicura da eseguire mentre è bloccato, utilizza startActivity() per avviare un'attività sopra la schermata di blocco.

Se l'azione del riquadro non è sicura, utilizza unlockAndRun() per chiedere all'utente di sbloccare il dispositivo. Se l'operazione va a buon fine, il sistema esegue l'oggetto Runnable che passi a questo metodo.

Categorizzare il riquadro

Per migliorare l'esperienza utente in Impostazioni rapide, puoi categorizzare il riquadro. Il sistema organizza i riquadri in categorie come Connettività, Display e Privacy. Il sistema utilizza queste categorie per ordinare e raggruppare i riquadri nella modalità di modifica di Impostazioni rapide, in modo che gli utenti possano trovarli e gestirli più facilmente.

Implementazione

Per specificare una categoria per il TileService, aggiungi un campo di metadati alla dichiarazione del servizio nel file AndroidManifest.xml:

  • In AndroidManifest.xml, all'interno dell'elemento <service> per TileService, aggiungi un elemento <meta-data>.
  • android:name: imposta questo valore su android.service.quicksettings.TILE_CATEGORY.
  • android:value: assegna una delle costanti di categoria predefinite, ad esempio android.service.quicksettings.CATEGORY_CONNECTIVITY o android.service.quicksettings.CATEGORY_DISPLAY.

Come mostrato nell'esempio seguente:

<service
    android:name=".MyConnectivityTileService"
    [...]
    >
    <meta-data android:name="android.service.quicksettings.TILE_CATEGORY"
        android:value="android.service.quicksettings.CATEGORY_CONNECTIVITY" />
</service>

L'API fornisce un insieme di categorie predefinite tra cui scegliere. Queste categorie sono definite come costanti stringa all'interno della classe TileService.

Se non viene specificata una categoria, il sistema assegna automaticamente una categoria predefinita:

  • Dalle app di sistema: per i riquadri che fanno parte di un'applicazione di sistema.
  • Dalle app che hai installato: per i riquadri delle applicazioni installate dall'utente.

Sebbene i dispositivi Google Pixel utilizzino le categorie in Impostazioni rapide, i produttori OEM possono utilizzare o ignorare queste informazioni sulle categorie nelle rispettive UI di sistema.

Chiedere all'utente di aggiungere il riquadro

Per aggiungere manualmente il riquadro, gli utenti devono seguire diversi passaggi:

  1. Scorri verso il basso per aprire il riquadro Impostazioni rapide.
  2. Tocca il pulsante Modifica.
  3. Scorri tutti i riquadri sul dispositivo finché non trovi il tuo riquadro.
  4. Tieni premuto il riquadro e trascinalo nell'elenco dei riquadri attivi.

L'utente può anche spostare o rimuovere il riquadro in qualsiasi momento.

A partire da Android 13, puoi utilizzare il metodo requestAddTileService() per semplificare notevolmente l'aggiunta del riquadro a un dispositivo da parte degli utenti. Questo metodo chiede agli utenti di aggiungere rapidamente il riquadro direttamente al riquadro Impostazioni rapide. Il prompt include il nome dell'applicazione, l'etichetta fornita e l'icona.

Prompt dell&#39;API di posizionamento delle Impostazioni rapide
Figura 5. Prompt dell'API Posizionamento Impostazioni rapide.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

Il callback contiene informazioni che indicano se il riquadro è stato aggiunto, non aggiunto, se era già presente o se si è verificato un errore.

Utilizza la tua discrezione quando decidi quando e con quale frequenza chiedere agli utenti. Ti consigliamo di chiamare requestAddTileService() solo nel contesto, ad esempio quando l'utente interagisce per la prima volta con una funzionalità facilitata dal riquadro.

Il sistema può scegliere di interrompere l'elaborazione delle richieste per un determinato ComponentName se l'utente lo ha rifiutato un numero sufficiente di volte in precedenza. L' utente viene determinato dal Context utilizzato per recuperare questo servizio, che deve corrispondere all'utente attuale.