Creare riquadri delle Impostazioni rapide personalizzati per la tua app

Le Impostazioni rapide sono riquadri visualizzati nel pannello delle 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 classe TileService 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 VPN attivato
  e disattivato
Figura 1. Il 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 devono accedere rapidamente (o entrambe le cose). I riquadri più efficaci sono quelli che corrispondono a 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 consigliamo di creare un riquadro per la stessa app che consenta agli utenti di rivedere l'intera cronologia degli allenamenti.

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

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

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

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

  • Evita di creare troppi riquadri. Consigliamo un massimo di due per app. Utilizza una scorciatoia dell'app.

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

Crea il tuo riquadro

Per creare un riquadro, devi prima creare un'icona appropriata, poi creare e dichiarare il tuo 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 nel riquadro Impostazioni rapide. Aggiungerai questa icona quando dichiarerai la TileService, descritta nella sezione successiva. L'icona deve essere bianca a tinta unita con uno sfondo trasparente, misurare 24 x 24 dp e avere la forma di un VectorDrawable.

Esempio di risorsa drawable vettoriale
Figura 3. Esempio di risorsa drawable vettoriale.

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

Creare e dichiarare il TileService

Crea un servizio per il riquadro che estende 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 TileService nel file manifest dell'app. Aggiungi il nome e l'etichetta del tuo TileService, l'icona personalizzata che hai creato 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 TileService

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

TileService è un servizio associato. Il tuo TileService viene associato quando richiesto dalla tua app o se il sistema deve comunicare con lui. Un tipico ciclo di vita del 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 per il ciclo di vita di TileService. Questi metodi possono essere chiamati al di fuori di onCreate() e onDestroy() perché i metodi del ciclo di vita Service e i metodi del ciclo di vita 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 TileService entra in una nuova fase del ciclo di vita:

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

  • onStartListening() e onStopListening(): questi metodi vengono chiamati ogni volta che l'app aggiorna il riquadro e vengono chiamati spesso. L'intent TileService rimane vincolato tra onStartListening() e onStopListening(), consentendo all'app di modificare il riquadro e inviare aggiornamenti.

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

Selezionare una modalità di ascolto

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

Non dare per scontato che il tuo TileService non rientri nella coppia di metodi onStartListening() e onStopListening().

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

Consigliamo la modalità attiva se il tuo TileService riceve una notifica quando lo stato del riquadro deve essere aggiornato dal proprio processo. I riquadri attivi limitano il carico sul sistema perché non devono essere associati ogni volta che il pannello delle 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 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 tuo TileService potrebbe essere creato e associato di nuovo in momenti al di fuori del suo controllo. Inoltre, può essere scollegato e distrutto quando l'utente non visualizza il riquadro.

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

Non devi dichiarare la modalità non attiva: è sufficiente 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 si trova sempre in uno dei seguenti stati.

  • STATE_ACTIVE: indica uno stato attivo o abilitato. 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 significherebbe 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 per il fitness, un riquadro in STATE_INACTIVE significa che l'utente non ha avviato una sessione di allenamento, ma potrebbe farlo se lo volesse.

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

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

Il sistema imposta solo lo stato iniziale dell'oggetto Tile. Imposti 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. Tile gli oggetti 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, non attivo e non disponibile).

Aggiornare il riquadro

Puoi aggiornare il riquadro una volta che ricevi una richiamata al numero onStartListening(). A seconda della modalità del riquadro, questo può essere aggiornato almeno una volta fino a quando non ricevi una richiamata al numero onStopListening().

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

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

Devi chiamare updateTile() per aggiornare il riquadro una volta impostati i campi dell'oggetto Tile sui valori corretti. In questo modo, il sistema analizzerà i dati del riquadro aggiornati e aggiornerà l'interfaccia utente.

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 tuo riquadro per attivare un'azione se il riquadro si trova in STATE_ACTIVE o STATE_INACTIVE. Il sistema richiama quindi il callback onClick() della tua app.

Una volta che l'app riceve un callback a onClick(), può avviare una finestra di dialogo o un'attività, attivare un 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 pannello. Le attività sono utili se ci sono informazioni più dettagliate da visualizzare rispetto a una finestra di dialogo o se l'azione è altamente interattiva.

Se la tua app richiede un'interazione significativa con l'utente, 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.

Se tieni premuto a lungo un riquadro, viene visualizzata la schermata Informazioni app per l'utente. Per ignorare questo comportamento e avviare un'attività per impostare le preferenze, aggiungi un <intent-filter> a una delle tue attività con ACTION_QS_TILE_PREFERENCES.

A partire dall'API Android 28, 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 specifica Activity.

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, è possibile fornire informazioni sul comportamento del riquadro al sistema operativo e migliorare 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 tuo TileService dovrebbe modificare il suo comportamento di conseguenza.

Se l'azione del riquadro può essere eseguita in sicurezza mentre il dispositivo è 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. In caso di esito positivo, il sistema esegue l'oggetto Runnable che passi a questo metodo.

Chiedere all'utente di aggiungere il tuo 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 fino a quando non trova il tuo.
  4. Tieni premuto il riquadro e trascinalo nell'elenco dei riquadri attivi.

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

A partire da Android 13, puoi utilizzare il metodo requestAddTileService() per consentire agli utenti di aggiungere molto più facilmente il tuo riquadro a un dispositivo. Questo metodo chiede agli utenti di aggiungere rapidamente il tuo riquadro direttamente al pannello delle 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 di posizionamento delle impostazioni rapide.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

Il callback contiene informazioni sull'aggiunta o meno del riquadro, se era già presente o se si è verificato un errore.

Utilizza il tuo giudizio per decidere quando e con quale frequenza richiedere agli utenti di fornire il consenso. Ti consigliamo di chiamare requestAddTileService() solo in un contesto, ad esempio quando l'utente interagisce per la prima volta con una funzionalità facilitata dal tuo riquadro.

Il sistema può scegliere di interrompere l'elaborazione delle richieste per un determinato ComponentName se è stato rifiutato dall'utente un numero sufficiente di volte in precedenza. L'utente viene determinato in base al Context utilizzato per recuperare questo servizio e deve corrispondere all'utente corrente.