Создайте собственные плитки быстрых настроек для своего приложения.

Быстрые настройки — это плитки, отображаемые на панели быстрых настроек , представляющие действия, которые пользователи могут нажимать для быстрого выполнения повторяющихся задач. Ваше приложение может предоставлять пользователям настраиваемую плитку через класс TileService и использовать объект Tile для отслеживания состояния плитки. Например, вы можете создать плитку, которая позволяет пользователям включать или выключать VPN, предоставляемый вашим приложением.

Панель быстрых настроек с включенной и выключенной плиткой VPN
Рисунок 1. Панель быстрых настроек с включенной и выключенной плиткой VPN.

Решите, когда создавать плитку

Мы рекомендуем создавать плитки для определенных функций, к которым, как вы ожидаете, пользователи будут часто обращаться или к которым им нужен быстрый доступ (или и то, и другое). Наиболее эффективными плитками являются те, которые соответствуют обоим этим качествам, обеспечивая быстрый доступ к часто выполняемым действиям.

Например, вы можете создать плитку для фитнес-приложения, которая позволит пользователям быстро начать сеанс тренировки. Однако мы не рекомендуем создавать плитку для того же приложения, которая позволит пользователям просматривать всю историю тренировок.

Варианты использования плитки фитнес-приложения
Рисунок 2. Примеры рекомендуемых и нерекомендуемых плиток для фитнес-приложения.

Чтобы улучшить заметность и удобство использования вашей плитки, мы рекомендуем избегать определенных практик:

  • Избегайте использования плиток для запуска приложения. Вместо этого используйте ярлык приложения или стандартный лаунчер.

  • Избегайте использования плиток для одноразовых действий пользователя. Вместо этого используйте ярлык приложения или уведомление .

  • Избегайте создания слишком большого количества плиток. Мы рекомендуем не более двух на приложение. Вместо этого используйте ярлык приложения.

  • Избегайте использования плиток, которые отображают информацию, но не являются интерактивными для пользователей. Вместо этого используйте уведомление или виджет .

Создайте свою плитку

Чтобы создать плитку, вам необходимо сначала создать соответствующий значок плитки, а затем создать и объявить TileService в файле манифеста вашего приложения.

Пример быстрых настроек демонстрирует, как создавать и управлять плиткой.

Создайте свой собственный значок

Вам нужно будет предоставить пользовательский значок, который будет отображаться на плитке на панели быстрых настроек. (Вы добавите этот значок при объявлении TileService , как описано в следующем разделе.) Значок должен быть сплошным белым с прозрачным фоном, иметь размер 24 x 24dp и иметь форму VectorDrawable .

Пример векторного рисунка
Рисунок 3. Пример векторного рисунка.

Создайте значок, который визуально намекает на цель вашей плитки. Это поможет пользователям легко определить, соответствует ли ваша плитка их потребностям. Например, вы можете создать значок секундомера для плитки фитнес-приложения, позволяющего пользователям начать сеанс тренировки.

Создайте и объявите свой TileService

Создайте службу для вашей плитки, которая расширяет класс TileService .

Котлин

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

Ява

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

Объявите ваш TileService в файле манифеста вашего приложения. Добавьте имя и метку вашего TileService , пользовательский значок, созданный вами в предыдущем разделе, и соответствующее разрешение.

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

Управляйте своим TileService

После создания и объявления TileService в манифесте приложения вам необходимо управлять его состоянием.

TileService — это привязанная служба . Ваша TileService привязана, когда ее запрашивает ваше приложение или если системе необходимо связаться с ней. Типичный жизненный цикл привязанной службы содержит следующие четыре метода обратного вызова: onCreate() , onBind() , onUnbind() и onDestroy() . Эти методы вызываются системой каждый раз, когда служба переходит в новую фазу жизненного цикла.

Обзор жизненного цикла TileService

В дополнение к обратным вызовам, которые управляют жизненным циклом привязанной службы, необходимо реализовать другие методы, специфичные для жизненного цикла TileService . Эти методы могут быть вызваны вне onCreate() и onDestroy() , поскольку методы жизненного цикла Service и методы жизненного цикла TileService вызываются в двух отдельных асинхронных потоках.

Жизненный цикл TileService содержит следующие методы, которые вызываются системой каждый раз, когда ваш TileService переходит в новую фазу жизненного цикла:

  • onTileAdded() : Этот метод вызывается только тогда, когда пользователь добавляет вашу плитку в первый раз, и если пользователь удаляет и добавляет вашу плитку снова. Это лучшее время для выполнения любой одноразовой инициализации. Однако это может не удовлетворить всю необходимую инициализацию.

  • onStartListening() и onStopListening() : эти методы вызываются всякий раз, когда ваше приложение обновляет плитку, и вызываются часто. TileService остается связанным между onStartListening() и onStopListening() , позволяя вашему приложению изменять плитку и отправлять обновления.

  • onTileRemoved() : этот метод вызывается только в том случае, если пользователь удаляет вашу плитку.

Выберите режим прослушивания

Ваш TileService прослушивает в активном или неактивном режиме. Мы рекомендуем использовать активный режим, который вам нужно будет объявить в манифесте приложения. В противном случае TileService является стандартным режимом и не требует объявления.

Не думайте, что ваш TileService будет существовать за пределами пары методов onStartListening() и onStopListening() .

Используйте активный режим для TileService , который слушает и отслеживает свое состояние в своем собственном процессе. TileService в активном режиме привязан к onTileAdded() , onTileRemoved() , событиям нажатия и по запросу процесса приложения.

Мы рекомендуем активный режим, если ваш TileService уведомлен, когда состояние вашей плитки должно быть обновлено его собственным процессом. Активные плитки ограничивают нагрузку на систему, поскольку их не нужно привязывать каждый раз, когда панель быстрых настроек становится видимой для пользователя.

Статический метод TileService.requestListeningState() можно вызвать для запроса начала состояния прослушивания и получения обратного вызова onStartListening() .

Вы можете объявить активный режим, добавив META_DATA_ACTIVE_TILE в файл манифеста вашего приложения.

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

Неактивный режим

Неактивный режим — это стандартный режим. TileService находится в неактивном режиме, если он привязан, когда ваша плитка видна пользователю. Это означает, что ваша TileService может быть создана и привязана снова в моменты, не зависящие от нее. Она также может быть отвязана и уничтожена, когда пользователь не просматривает плитку.

Ваше приложение получает обратный вызов onStartListening() после того, как пользователь открывает панель быстрых настроек. Вы можете обновлять свой объект Tile столько раз, сколько захотите между onStartListening() и onStopListening() .

Вам не нужно объявлять неактивный режим — просто не добавляйте META_DATA_ACTIVE_TILE в файл манифеста вашего приложения.

Обзор состояний плитки

После того, как пользователь добавит вашу плитку, она всегда будет находиться в одном из следующих состояний.

  • STATE_ACTIVE : Указывает на включенное или включенное состояние. Пользователь может взаимодействовать с вашей плиткой, находясь в этом состоянии.

    Например, для плитки фитнес-приложения, позволяющей пользователям инициировать сеанс тренировки с заданным временем, STATE_ACTIVE будет означать, что пользователь инициировал сеанс тренировки и таймер запущен.

  • STATE_INACTIVE : Указывает на выключенное или приостановленное состояние. Пользователь может взаимодействовать с вашей плиткой, находясь в этом состоянии.

    Если снова использовать пример плитки фитнес-приложения, плитка в STATE_INACTIVE будет означать, что пользователь не инициировал сеанс тренировки, но может сделать это, если захочет.

  • STATE_UNAVAILABLE : Указывает на временно недоступное состояние. Пользователь не может взаимодействовать с вашей плиткой, находясь в этом состоянии.

    Например, плитка в STATE_UNAVAILABLE означает, что по какой-то причине плитка в данный момент недоступна пользователю.

Система устанавливает только начальное состояние вашего объекта Tile . Вы устанавливаете состояние объекта Tile на протяжении всего его оставшегося жизненного цикла.

Система может подкрашивать значок плитки и фон, чтобы отразить состояние вашего объекта Tile . Объекты Tile , установленные в STATE_ACTIVE , являются самыми темными, а STATE_INACTIVE и STATE_UNAVAILABLE становятся все светлее. Точный оттенок зависит от производителя и версии.

Плитка VPN окрашена для отражения состояний объектов
Рисунок 4. Примеры плитки, тонированной для отображения ее состояния (активное, неактивное и недоступное состояния соответственно).

Обновите свою плитку

Вы можете обновить свою плитку, как только получите обратный вызов onStartListening() . В зависимости от режима плитки, ваша плитка может быть обновлена ​​по крайней мере один раз до получения обратного вызова onStopListening() .

В активном режиме вы можете обновить плитку ровно один раз, прежде чем получить обратный вызов onStopListening() . В неактивном режиме вы можете обновить плитку столько раз, сколько захотите между onStartListening() и onStopListening() .

Вы можете получить свой объект Tile , вызвав getQsTile() . Чтобы обновить определенные поля вашего объекта Tile , вызовите следующие методы:

Вы должны вызвать updateTile() для обновления плитки после того, как закончите установку полей объекта Tile на правильные значения. Это заставит систему проанализировать обновленные данные плитки и обновить пользовательский интерфейс.

Котлин

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

Ява

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

Ручка крана

Пользователи могут нажать на вашу плитку, чтобы вызвать действие, если ваша плитка находится в состоянии STATE_ACTIVE или STATE_INACTIVE . Затем система вызывает обратный вызов onClick() вашего приложения.

Как только ваше приложение получает обратный вызов onClick() , оно может запустить диалог или действие, запустить фоновую работу или изменить состояние вашей плитки.

Котлин

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

Ява

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

Начать диалог

showDialog() сворачивает панель быстрых настроек и показывает диалог. Используйте диалог, чтобы добавить контекст к вашему действию, если оно требует дополнительного ввода или согласия пользователя.

Запустить деятельность

startActivityAndCollapse() запускает активность при сворачивании панели. Активности полезны, если нужно отобразить более подробную информацию, чем в диалоговом окне, или если ваше действие очень интерактивно.

Если ваше приложение требует значительного взаимодействия с пользователем, приложение должно запускать активность только в крайнем случае. Вместо этого рассмотрите возможность использования диалога или переключателя.

Долгое нажатие на плитку вызывает экран App Info для пользователя. Чтобы переопределить это поведение и вместо этого запустить действие для настройки предпочтений, добавьте <intent-filter> к одному из ваших действий с ACTION_QS_TILE_PREFERENCES .

Начиная с Android API 28, PendingIntent должен иметь Intent.FLAG_ACTIVITY_NEW_TASK :

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

Вы также можете добавить флаг в AndroidManifest.xml в определенном разделе Activity .

Отметьте свою плитку как переключаемую

Мы рекомендуем пометить плитку как переключаемую, если она в основном функционирует как двухпозиционный переключатель (что является наиболее распространенным поведением плиток). Это помогает предоставить операционной системе информацию о поведении плитки и улучшить общую доступность.

Установите для метаданных TOGGLEABLE_TILE значение true , чтобы отметить плитку как переключаемую.

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

Выполняйте только безопасные действия на надежно заблокированных устройствах.

Ваша плитка может отображаться поверх экрана блокировки на заблокированных устройствах. Если плитка содержит конфиденциальную информацию, проверьте значение isSecure() чтобы определить, находится ли устройство в безопасном состоянии, и ваш TileService должен изменить свое поведение соответствующим образом.

Если действие плитки безопасно выполнять на заблокированном экране, используйте startActivity() для запуска действия поверх экрана блокировки.

Если действие плитки небезопасно, используйте unlockAndRun() чтобы предложить пользователю разблокировать свое устройство. В случае успеха система выполняет объект Runnable , который вы передаете в этот метод.

Предложите пользователю добавить вашу плитку

Чтобы вручную добавить плитку, пользователям необходимо выполнить несколько шагов:

  1. Проведите пальцем вниз, чтобы открыть панель быстрых настроек.
  2. Нажмите кнопку «Изменить».
  3. Прокрутите все плитки на своем устройстве, пока не найдете вашу плитку.
  4. Удерживайте плитку и перетащите ее в список активных плиток.

Пользователь также может переместить или удалить вашу плитку в любой момент.

Начиная с Android 13, вы можете использовать метод requestAddTileService() , чтобы пользователям было намного проще добавлять плитку на устройство. Этот метод предлагает пользователям запрос на быстрое добавление плитки непосредственно на панель быстрых настроек. Запрос включает имя приложения, предоставленную метку и значок.

Запрос API для быстрого размещения настроек
Рисунок 5. Запрос API для размещения быстрых настроек.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

Обратный вызов содержит информацию о том, была ли плитка добавлена, не добавлена, была ли она уже там или произошла какая-либо ошибка.

Используйте свое усмотрение при принятии решения о том, когда и как часто запрашивать пользователей. Мы рекомендуем вызывать requestAddTileService() только в контексте — например, когда пользователь впервые взаимодействует с функцией, которую обеспечивает ваша плитка.

Система может остановить обработку запросов для данного ComponentName , если он был отклонен пользователем достаточно много раз до этого. Пользователь определяется из Context используемого для получения этой службы — он должен соответствовать текущему пользователю.