为您的应用创建自定义“快捷设置”图块

“快捷设置”是显示在“快捷设置”面板中的图块, 代表操作,用户只需点按这些按钮即可快速完成周期性任务。 应用可以通过 TileService 向用户提供自定义功能块 类,并使用 Tile 对象跟踪功能块的状态。例如: 您可以创建一个功能块 让用户能够开启您的应用提供的 VPN 关闭。

已打开 VPN 功能块的“快捷设置”面板
  开启和关闭
图 1. 已打开 VPN 功能块的“快捷设置”面板 和关闭场景。

决定何时创建功能块

我们建议您针对您期望用户的特定功能创建功能块 经常访问和/或需要快速访问的用户。最有效 即同时符合这两种特征的图块,方便您快速访问 频繁执行的操作。

例如,您可以为健身应用创建功能块,以便用户执行以下操作: 快速开始锻炼课程。不过,我们不建议您 同一应用,并且允许用户查看其全部锻炼历史记录。

健身应用功能块用例
图 2. 健身应用的推荐功能块与不推荐功能块示例。

为帮助提高功能块的可检测性和易用性,我们建议您 避免某些做法:

  • 避免使用功能块来启动应用。使用应用快捷方式或标准快捷方式 启动器。

  • 避免将功能块用于一次性用户操作。使用应用快捷方式或 notification

  • 避免创建过多功能块。我们建议每个应用最多设置 2 个。使用 应用快捷方式。

  • 避免使用显示信息,但对以下内容无互动功能的功能块: 用户。请改用通知或 widget

创建功能块

如要创建功能块,您需要先创建适当的功能块图标,然后 在应用的清单文件中创建并声明 TileService

“快捷设置”示例举例说明了如何创建 以及管理卡片

创建自定义图标

您需要提供一个自定义图标,该图标会显示在 快速启动 设置面板。(您将在声明 TileService 时添加此图标, 具体说明。)该图标必须为纯白色,并带有 透明背景,尺寸为 24 x 24dp,采用 VectorDrawable

矢量可绘制对象示例
图 3. 矢量可绘制对象示例。

创建一个在视觉上暗示功能块用途的图标。这有助于用户 轻松识别您的功能块是否符合他们的需求。例如,您可以创建一个 一个健身应用的秒表板块,该板块允许用户启动 锻炼课程。

创建并声明 TileService

为功能块创建一项扩展 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();
  }
}

在应用的清单文件中声明 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”的绑定时间 或者系统需要与应用进行通信典型 bound-serviceLifecycle 包含以下四个回调方法: 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 对象。设置为 STATE_ACTIVETile 对象最暗, STATE_INACTIVESTATE_UNAVAILABLE 越来越轻。确切色调 因制造商和版本而异

已调节 VPN 图块的色调,以反映对象状态
图 4. 着色以反映功能块状态(分别是有效、无效和不可用状态)的功能块示例。

更新您的功能块

收到 onStartListening() 的回调后,您可以更新功能块。 取决于板块的模式,您的板块可以至少更新一次,直到 收到对 onStopListening() 的回调。

在活动模式下,你只需对功能块更新一次,即可收到 对 onStopListening() 的回调。在非活动模式下,你可以将板块更新为 您可以在 onStartListening()onStopListening() 之间随意操作。

您可以通过调用 getQsTile() 来检索 Tile 对象。更新 Tile 对象的特定字段,请调用以下方法:

设置完毕后,您必须调用 updateTile() 来更新功能块 Tile 对象的字段更改为正确的值。这样,系统会 解析更新后的功能块数据并更新界面。

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

处理点按操作

如果您的功能块位于以下位置,用户可以点按您的功能块以触发操作 STATE_ACTIVESTATE_INACTIVE。然后,系统会调用您应用的 onClick() 回调。

应用收到对 onClick() 的回调后,即可启动对话框或 触发后台工作或更改功能块的状态。

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

启动对话框

showDialog() 可收起“快捷设置”面板并显示一个对话框。 如果操作需要额外输入,请使用对话框为操作添加上下文 或征得用户同意。

启动 activity

startActivityAndCollapse() 在收起 面板。如果有更详细的信息可以显示,那么 activity 非常有用 还是在对话框内操作 或你的操作互动性很高的话

如果您的应用需要用户互动,则应启动 只作为最后的补救手段。请考虑改用对话框或切换开关。

长按功能块会提示用户进入应用信息界面。覆盖 并改为启动一个 activity 来设置偏好设置,添加一个 <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() 在锁定屏幕上启动 activity。

如果图块操作不安全,请使用 unlockAndRun() 提示用户 解锁设备。如果成功,系统会执行 Runnable 对象, 方法。

提示用户添加功能块

如要手动添加功能块,用户必须按以下步骤操作:

  1. 向下滑动以打开“快捷设置”面板。
  2. 点按“修改”按钮。
  3. 滚动浏览孩子设备上的所有板块,直到他们找到您的板块。
  4. 按住您的功能块,然后将其拖动到有效功能块列表中。

用户还可以随时移动或移除您的功能块。

从 Android 13 开始,您可以使用 requestAddTileService() 方法 以便用户更轻松地将您的功能块添加到设备。此方法 提示用户请求快速将您的功能块直接添加到他们的“快速” 设置面板。提示信息包括应用名称、所提供的标签 和图标

<ph type="x-smartling-placeholder">
</ph> Quick Settings Placement API 提示
图 5.Quick Settings Placement API 提示。
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

该回调包含有关是否添加了功能块(而非功能块)的信息 或该文件是否已经存在,或者是否发生了任何错误。

您可以自行决定何时以及以何种频率提示用户。周三 建议仅在上下文中调用 requestAddTileService(),例如 当用户首次与您的功能块提供的功能互动时触发。

对于指定的 ComponentName(如果用户之前已多次拒绝请求)。通过 由Context用于检索此 服务 - 它必须与当前用户相匹配。