“快捷设置”是指显示在“快捷设置”面板中的功能块,表示用户可以点按这些图块来快速完成周期性任务。应用可以通过 TileService
类向用户提供自定义功能块,并使用 Tile
对象跟踪功能块的状态。例如,您可以创建一个功能块,让用户能够开启或关闭您的应用提供的 VPN。
决定何时创建功能块
我们建议您针对您希望用户经常访问和/或需要快速访问的特定功能创建功能块。最有效的功能块是同时具备这两种特征的功能块,可让您快速访问频繁执行的操作。
例如,您可以为健身应用创建一个功能块,让用户能够快速开始锻炼时段。不过,我们不建议为同一应用创建可让用户查看其整个锻炼历史记录的功能块。
为了帮助提高功能块的可检测性和易用性,我们建议您避免某些做法:
避免使用功能块启动应用。请改用应用快捷方式或标准启动器。
避免使用功能块执行一次性用户操作。请改用应用快捷方式或通知。
避免创建过多的功能块。我们建议每个应用最多设置两个。请改用应用快捷方式。
避免使用会显示信息但对用户无互动的功能块。而改用通知或微件。
创建功能块
如需创建功能块,您需要先创建适当的功能块图标,然后在应用的清单文件中创建并声明 TileService
。
“快捷设置”示例提供了如何创建和管理功能块的示例。
创建自定义图标
您需要提供一个自定义图标,该图标会显示在“快捷设置”面板的图块上。(您将在声明 TileService
时添加此图标,如下一部分所述。)该图标必须是具有透明背景的纯白色,尺寸为 24 x 24dp,并且采用 VectorDrawable
的形式。
创建一个视觉提示功能块用途的图标。这有助于用户轻松确定您的功能块是否符合其需求。例如,您可以为健身应用功能块创建一个秒表图标,以便用户开始锻炼时段。
创建并声明您的 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
。典型的绑定服务生命周期包含以下四种回调方法: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()
的回调。您可以在 onStartListening()
和 onStopListening()
之间根据需要多次更新 Tile
对象。
您无需声明非活动模式,只要不要将 META_DATA_ACTIVE_TILE
添加到应用的清单文件中即可。
图块状态概览
用户添加功能块后,功能块会始终处于以下状态之一。
STATE_ACTIVE
:表示开启或启用状态。在该状态下,用户可以与您的功能块互动。例如,对于允许用户发起定时锻炼时段的健身应用功能块,
STATE_ACTIVE
表示用户已发起锻炼时段且计时器正在运行。STATE_INACTIVE
:表示关闭或暂停状态。在该状态下,用户可以与您的功能块互动。我们再次以健身应用功能块为例,
STATE_INACTIVE
中的功能块表示用户尚未启动锻炼时段,但可以根据需要启动锻炼时段。STATE_UNAVAILABLE
:表示暂时不可用状态。在此状态下,用户无法与您的功能块互动。例如,
STATE_UNAVAILABLE
中的功能块表示由于某种原因,用户当前无法使用该功能。
系统仅设置 Tile
对象的初始状态。您可以在 Tile
对象的整个生命周期的剩余时间内设置其状态。
系统可能会对功能块图标和背景进行色调调节,以反映 Tile
对象的状态。设置为 STATE_ACTIVE
的 Tile
对象最暗,STATE_INACTIVE
和 STATE_UNAVAILABLE
颜色越来越浅。确切的色调因制造商和版本而异。
更新你的功能块
收到对 onStartListening()
的回调后,您便可以更新功能块。在收到对 onStopListening()
的回调之前,功能块至少可以更新一次,具体取决于功能块的模式。
在活动模式下,您可以在收到对 onStopListening()
的回调之前只更新功能块一次。在非活动模式下,您可以在 onStartListening()
到 onStopListening()
之间无限次更新功能块。
您可以通过调用 getQsTile()
来检索 Tile
对象。如需更新 Tile
对象的特定字段,请调用以下方法:
将 Tile
对象的字段设置为正确的值后,您必须调用 updateTile()
来更新功能块。这将使系统解析更新后的功能块数据并更新界面。
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_ACTIVE
或 STATE_INACTIVE
中,用户可以点按功能块来触发操作。然后,系统会调用应用的 onClick()
回调。
应用收到对 onClick()
的回调后,便可启动对话框或 activity、触发后台工作或更改功能块的状态。
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 非常有用。
如果您的应用需要大量用户互动,则在万不得已的情况下,才应启动 activity。不妨考虑使用对话框或切换开关。
长按功能块会提示用户打开应用信息界面。如需替换此行为并启动用于设置偏好设置的 activity,请使用 ACTION_QS_TILE_PREFERENCES
将 <intent-filter>
添加到其中一个 activity。
将功能块标记为可切换
如果功能块主要用作双状态开关(这是功能块最常见的行为),我们建议您将功能块标记为可切换。这有助于向操作系统提供有关功能块行为的信息,并改进整体可访问性。
将 TOGGLEABLE_TILE
元数据设为 true
,可将功能块标记为可切换。
<service ...>
<meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
android:value="true" />
</service>
请仅在已安全锁定的设备上执行安全操作
在锁定的设备上,您的功能块可能会显示在锁定屏幕顶部。如果该功能块包含敏感信息,请检查 isSecure()
的值以确定设备是否处于安全状态,并且您的 TileService
应相应地更改其行为。
如果功能块操作在锁定时可以安全执行,请使用 startActivity()
在锁定屏幕上启动 activity。
如果功能块操作不安全,请使用 unlockAndRun()
提示用户解锁设备。如果成功,系统会执行您传入此方法的 Runnable
对象。
提示用户添加卡片
要手动添加您的板块,用户必须执行以下几个步骤:
- 向下滑动以打开“快捷设置”面板。
- 点按“编辑”按钮。
- 滚动浏览设备上的所有板块,直到找到你的板块。
- 按住板块,并将其拖到活动板块的列表。
用户还可以随时移动或移除您的功能块。
从 Android 13 开始,您可以使用 requestAddTileService()
方法,让用户更轻松地将功能块添加到设备。此方法会提示用户将功能块直接快速添加到他们的“快捷设置”面板中。提示包括应用名称、提供的标签和图标。
public void requestAddTileService (
ComponentName tileServiceComponentName,
CharSequence tileLabel,
Icon icon,
Executor resultExecutor,
Consumer<Integer> resultCallback
)
回调包含以下方面的信息:功能块是否已添加、未添加、功能块是否已存在,或者是否发生了任何错误。
您可以自行决定提示用户的时间和频率。建议仅在上下文中调用 requestAddTileService()
,例如当用户首次与功能块支持的功能互动时。
如果给定 ComponentName
之前已被用户拒绝的次数达到上限,则系统可以选择停止处理该请求。系统会根据用于检索此服务的 Context
确定用户,而且该用户必须与当前用户匹配。