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

Быстрые настройки — это плитки, отображаемые на панели быстрых настроек и представляющие действия, которые пользователи могут использовать для быстрого выполнения повторяющихся задач. Ваше приложение может предоставить пользователям пользовательскую плитку через класс 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() запускает действие при сворачивании панели. Действия полезны, если нужно отобразить более подробную информацию, чем в диалоговом окне, или если ваше действие очень интерактивно.

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

Длительное нажатие на плитку открывает экран информации о приложении для пользователя. Чтобы переопределить это поведение и вместо этого запустить действие для настройки предпочтений, добавьте <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 , используемого для получения этой службы — он должен соответствовать текущему пользователю.