Cómo crear tarjetas de Configuración rápida personalizadas para tu app

Los parámetros de Configuración rápida son mosaicos que se muestran en el panel de Configuración rápida y representan acciones, que los usuarios pueden presionar para completar rápidamente tareas recurrentes. Tu app puede proporcionar una tarjeta personalizada a los usuarios a través de la clase TileService y usar un objeto Tile para hacer un seguimiento del estado de la tarjeta. Por ejemplo, puedes crear una tarjeta que les permita a los usuarios activar o desactivar una VPN que proporciona tu app.

Panel de Configuración rápida con la tarjeta de VPN activada y
  desactivada
Figura 1: Panel de Configuración rápida con la tarjeta de VPN activada y desactivada.

Cómo decidir cuándo crear una tarjeta

Te recomendamos crear tarjetas para funcionalidades específicas a las que esperas que los usuarios accedan con frecuencia o a las que necesiten un acceso rápido (o a ambas). Las tarjetas más eficaces son las que coinciden con estas dos cualidades, lo que proporciona acceso rápido a las acciones que se realizan con frecuencia.

Por ejemplo, podrías crear una tarjeta para una app de fitness que permita a los usuarios iniciar rápidamente una sesión de entrenamiento. Sin embargo, no recomendamos crear una tarjeta para la misma app que permita a los usuarios revisar todo su historial de entrenamiento.

Casos de uso de tarjetas de apps de fitness
Figura 2: Ejemplos de tarjetas recomendadas frente a no recomendadas para una app de fitness.

Para ayudar a mejorar la visibilidad y la facilidad de uso de tu tarjeta, te recomendamos que evites ciertas prácticas:

  • Evita usar tarjetas para iniciar una app. En su lugar, usa un acceso directo a la app o un selector estándar.

  • Evita usar tarjetas para acciones únicas del usuario. En su lugar, usa un acceso directo a la app o una notificación.

  • Evita crear demasiados mosaicos. Te recomendamos que uses un máximo de dos por app. En su lugar, usa un acceso directo a la app.

  • Evita usar tarjetas que muestren información, pero que no son interactivas para los usuarios. En su lugar, usa una notificación o un widget.

Cómo crear tu tarjeta

Para crear una tarjeta, primero debes crear un ícono de tarjeta adecuado y, luego, crear y declarar tu TileService en el archivo de manifiesto de tu app.

En el ejemplo de Configuración rápida, se proporciona un ejemplo de cómo crear y administrar una tarjeta.

Crea tu ícono personalizado

Deberás proporcionar un ícono personalizado, que se mostrará en la tarjeta en el panel de Configuración rápida. Agregarás este ícono cuando declares el TileService, como se describe en la siguiente sección. El ícono debe ser de color blanco sólido con un fondo transparente, medir 24 × 24 dp y tener la forma de VectorDrawable.

Ejemplo de un elemento de diseño vectorial
Figura 3: Ejemplo de un elemento de diseño vectorial.

Crea un ícono que sugiera visualmente el propósito de la tarjeta. Esto ayuda a los usuarios a identificar fácilmente si tu tarjeta se ajusta a sus necesidades. Por ejemplo, puedes crear un ícono de cronómetro para una tarjeta en una app de fitness que permita a los usuarios iniciar una sesión de entrenamiento.

Crea y declara tu TileService

Crea un servicio para tu tarjeta que extienda la clase 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();
  }
}

Declara tu TileService en el archivo de manifiesto de tu app. Agrega el nombre y la etiqueta de tu TileService, el ícono personalizado que creaste en la sección anterior y el permiso correspondiente.

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

Cómo administrar tu TileService

Una vez que hayas creado y declarado tu TileService en el manifiesto de la app, debes administrar su estado.

TileService es un servicio vinculado. Tu TileService está vinculado cuando tu app lo solicita o si el sistema necesita comunicarse con él. Un ciclo de vida de servicio vinculado típico contiene los siguientes cuatro métodos de devolución de llamada: onCreate(), onBind(), onUnbind() y onDestroy(). El sistema invoca estos métodos cada vez que el servicio entra en una nueva fase del ciclo de vida.

Descripción general del ciclo de vida de TileService

Además de las devoluciones de llamada que controlan el ciclo de vida del servicio vinculado, debes implementar otros métodos específicos para el ciclo de vida de TileService. Se puede llamar a estos métodos fuera de onCreate() y onDestroy() porque los métodos de ciclo de vida de Service y los métodos de ciclo de vida de TileService se llaman en dos subprocesos asíncronos separados.

El ciclo de vida de TileService contiene los siguientes métodos, que el sistema invoca cada vez que tu TileService ingresa a una nueva fase del ciclo de vida:

  • onTileAdded(): Se llama a este método solo cuando el usuario agrega la tarjeta por primera vez y si la quita y vuelve a agregar. Este es el mejor momento para realizar una inicialización única. Sin embargo, es posible que esto no satisfaga toda la inicialización necesaria.

  • onStartListening() y onStopListening(): Se llama a estos métodos cada vez que tu app actualiza la tarjeta y se los llama con frecuencia. La TileService permanece vinculada entre onStartListening() y onStopListening(), lo que permite que tu app modifique la tarjeta y envíe actualizaciones.

  • onTileRemoved(): Solo se llama a este método si el usuario quita la tarjeta.

Selecciona un modo de reproducción

Tu TileService escucha en modo activo o no activo. Te recomendamos que uses el modo activo, que deberás declarar en el manifiesto de la app. De lo contrario, TileService es el modo estándar y no es necesario declararlo.

No supongas que tu TileService vivirá fuera del par de métodos onStartListening() y onStopListening().

Usa el modo activo para un TileService que escuche y supervise su estado en su propio proceso. Un TileService en modo activo está vinculado para onTileAdded(), onTileRemoved(), eventos de presión y cuando el proceso de la app lo solicite.

Recomendamos el modo activo si tu TileService recibe una notificación cuando su propio proceso debe actualizar el estado de la tarjeta. Las tarjetas activas limitan la sobrecarga del sistema, ya que no tienen que vincularse cada vez que el panel de Configuración rápida se vuelve visible para el usuario.

Se puede llamar al método estático TileService.requestListeningState() para solicitar el inicio del estado de escucha y recibir una devolución de llamada a onStartListening().

Para declarar el modo activo, agrega META_DATA_ACTIVE_TILE al archivo de manifiesto de tu app.

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

Modo no activo

El modo no activo es el modo estándar. Una TileService está en modo no activo si se vincula cada vez que tu tarjeta es visible para el usuario. Esto significa que tu TileService podría crearse y vincularse de nuevo en momentos fuera de su control. También se puede desvincular y destruir cuando el usuario no esté viendo la tarjeta.

Tu app recibe una devolución de llamada a onStartListening() después de que el usuario abre su panel de Configuración rápida. Puedes actualizar tu objeto Tile tantas veces como desees entre onStartListening() y onStopListening().

No es necesario declarar el modo no activo; simplemente no agregues el META_DATA_ACTIVE_TILE al archivo de manifiesto de tu app.

Descripción general de los estados de los mosaicos

Después de que un usuario agrega tu tarjeta, siempre existe en uno de los siguientes estados.

  • STATE_ACTIVE: Indica un estado activado o habilitado. El usuario puede interactuar con tu tarjeta en este estado.

    Por ejemplo, para una tarjeta de app de fitness que permita a los usuarios iniciar una sesión de entrenamiento cronometrada, STATE_ACTIVE significaría que el usuario inició una sesión de entrenamiento y el temporizador se está ejecutando.

  • STATE_INACTIVE: Indica un estado desactivado o de pausa. El usuario puede interactuar con tu tarjeta en este estado.

    Para volver a usar el ejemplo de tarjeta de la app de fitness, una tarjeta en STATE_INACTIVE significaría que el usuario no inició una sesión de entrenamiento, pero podría hacerlo si lo desea.

  • STATE_UNAVAILABLE: Indica un estado no disponible temporalmente. El usuario no puede interactuar con la tarjeta en este estado.

    Por ejemplo, una tarjeta en STATE_UNAVAILABLE significa que, por algún motivo, la tarjeta no está disponible para el usuario en este momento.

El sistema solo establece el estado inicial de tu objeto Tile. Debes establecer el estado del objeto Tile durante el resto de su ciclo de vida.

El sistema puede ajustar el tono del ícono y del fondo de la tarjeta para que reflejen el estado de tu objeto Tile. Los objetos Tile establecidos en STATE_ACTIVE son los más oscuros, y STATE_INACTIVE y STATE_UNAVAILABLE son cada vez más claros. El tono exacto es específico del fabricante y la versión.

Se modificó el tono de la tarjeta de VPN para reflejar los estados de los objetos
Figura 4: Ejemplos de mosaicos cuyo tono refleja el estado del mosaico (estado activo, inactivo y no disponible, respectivamente).

Cómo actualizar tu tarjeta

Podrás actualizar tu tarjeta una vez que recibas una devolución de llamada a onStartListening(). Según el modo de la tarjeta, esta se puede actualizar al menos una vez hasta recibir una devolución de llamada a onStopListening().

En el modo activo, puedes actualizar la tarjeta exactamente una vez antes de recibir una devolución de llamada a onStopListening(). En el modo no activo, puedes actualizar tu tarjeta tantas veces como desees entre onStartListening() y onStopListening().

Para recuperar tu objeto Tile, llama a getQsTile(). Para actualizar campos específicos del objeto Tile, llama a los siguientes métodos:

Debes llamar a updateTile() para actualizar tu tarjeta una vez que termines de configurar los campos del objeto Tile en los valores correctos. De esta manera, el sistema analizará los datos actualizados de la tarjeta y actualizará la IU.

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

Maneja las presiones

Los usuarios pueden presionar la tarjeta para activar una acción si está en STATE_ACTIVE o STATE_INACTIVE. Luego, el sistema invoca la devolución de llamada onClick() de tu app.

Una vez que tu app reciba una devolución de llamada a onClick(), podrá iniciar un diálogo o una actividad, activar trabajos en segundo plano o cambiar el estado de la tarjeta.

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

Iniciar un diálogo

showDialog() contrae el panel de Configuración rápida y muestra un diálogo. Usa un diálogo para agregar contexto a tu acción si requiere una entrada adicional o el consentimiento del usuario.

Cómo iniciar una actividad

startActivityAndCollapse() inicia una actividad mientras contrae el panel. Las actividades son útiles si hay información más detallada para mostrar que en un diálogo o si tu acción es altamente interactiva.

Si tu app requiere una interacción significativa del usuario, debe iniciar una actividad solo como último recurso. En su lugar, te recomendamos usar un diálogo o un botón de activación.

Si mantienes presionado un mosaico, se mostrará la pantalla Información de la app del usuario. Si deseas anular este comportamiento y, en su lugar, iniciar una actividad para configurar preferencias, agrega un <intent-filter> a una de tus actividades con ACTION_QS_TILE_PREFERENCES.

Marca tu tarjeta como que se puede activar o desactivar

Recomendamos marcar tu tarjeta para que se pueda activar o desactivar si funciona principalmente como un interruptor de dos estados (que es el comportamiento más común de las tarjetas). Esto ayuda a proporcionar información sobre el comportamiento de la tarjeta al sistema operativo y mejorar la accesibilidad general.

Establece los metadatos de TOGGLEABLE_TILE en true para marcar tu mosaico como un elemento que se puede activar o desactivar.

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

Realiza solo acciones seguras en dispositivos bloqueados de forma segura

Es posible que tu tarjeta aparezca en la parte superior de la pantalla de bloqueo en dispositivos bloqueados. Si la tarjeta contiene información sensible, verifica el valor de isSecure() para determinar si el dispositivo está en un estado seguro, y tu TileService debe cambiar su comportamiento en consecuencia.

Si es seguro realizar la acción de la tarjeta mientras el dispositivo está bloqueado, usa startActivity() para iniciar una actividad en la pantalla de bloqueo.

Si la acción de la tarjeta no es segura, usa unlockAndRun() para solicitarle al usuario que desbloquee su dispositivo. Si se ejecuta de forma correcta, el sistema ejecuta el objeto Runnable que pasas a este método.

Pídele al usuario que agregue tu tarjeta

Para agregar la tarjeta manualmente, los usuarios deben seguir varios pasos:

  1. Desliza el dedo hacia abajo para abrir el panel de Configuración rápida.
  2. Presiona el botón de edición.
  3. Desplázate por todas las tarjetas en su dispositivo hasta que encuentre la tuya.
  4. Mantén presionada la tarjeta y arrástrala a la lista de mosaicos activos.

El usuario también puede mover o quitar tu tarjeta en cualquier momento.

A partir de Android 13, puedes usar el método requestAddTileService() para facilitar que los usuarios agreguen tu tarjeta a un dispositivo. Este método les solicita a los usuarios que agreguen rápidamente tu tarjeta directamente a su panel de Configuración rápida. El mensaje incluye el nombre de la aplicación, la etiqueta proporcionada y el ícono.

Mensaje de la API de posiciones de configuración rápida
Figura 5: Mensaje de la API de Quick Settings Placement
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

La devolución de llamada contiene información sobre si la tarjeta se agregó o no, si ya estaba allí o si se produjo algún error.

Sé prudente cuando decidas cuándo y con qué frecuencia quieres que los usuarios se lo soliciten. Te recomendamos que llames a requestAddTileService() solo en contexto, como cuando el usuario interactúa por primera vez con una función que tu tarjeta facilita.

El sistema puede optar por detener el procesamiento de solicitudes para un ComponentName determinado si el usuario lo rechazó varias veces antes. El usuario se determina a partir del Context que se usa para recuperar este servicio y debe coincidir con el usuario actual.