App中可能存在一些高频使用的功能,例如扫一扫、开启收付款码等。如果能够在不先打开App的情况下快速使用这些功能,将显著提升用户体验。
在上一篇文章Android 下拉栏中的快捷设置(一)--- 创建添加中介绍了如何创建快捷设置并在下拉栏中添加。本文将进一步介绍快捷设置的状态更新与事件处理部分。
状态更新与事件处理
更新快捷设置状态
快捷设置包含下列三种状态,当用户添加了快捷设置之后,它只会在这三种状态中切换。
Tile.STATE_ACTIVE
:启用状态,此状态下用户可以与快捷设置进行交互。Tile.STATE_INACTIVE
:关闭或暂停状态,此状态下用户可以与快捷设置进行交互。Tile.STATE_UNAVAILABLE
:暂时不可用,此状态下用户无法与快捷设置进行交互。
切换状态
可以通过代码切换快捷设置的状态,示例代码如下:
- ExampleTileService
kotlin
class ExampleTileService : TileService() {
......
override fun onStartListening() {
super.onStartListening()
// 此处使用SharedPreferences记录要切换的状态
if (!SpUtils.isInit()) {
SpUtils.init(this)
}
val nextState = SpUtils.getInt("TileStatus", -1)
if (nextState != -1) {
// 除了更新state之外
// 还可以更新Tile的Icon、Label、SubTitle等,根据实际需求选用
qsTile.state = nextState
// 调用update方法后设置才会生效
qsTile.updateTile()
}
}
......
}
- TileExampleActivity
kotlin
class TileExampleActivity : AppCompatActivity() {
private var currentStatus = Tile.STATE_ACTIVE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = LayoutTileExmpleActivityBinding.inflate(layoutInflater).also {
setContentView(it.root)
}
if (!SpUtils.isInit()) {
SpUtils.init(this)
}
binding.btnChangeStatus.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
when (currentStatus) {
Tile.STATE_ACTIVE -> {
currentStatus = Tile.STATE_INACTIVE
SpUtils.put("TileStatus", currentStatus)
}
Tile.STATE_INACTIVE -> {
currentStatus = Tile.STATE_UNAVAILABLE
SpUtils.put("TileStatus", currentStatus)
}
Tile.STATE_UNAVAILABLE -> {
currentStatus = Tile.STATE_ACTIVE
SpUtils.put("TileStatus", currentStatus)
}
}
TileService.requestListeningState(this, ComponentName(this, ExampleTileService::class.java))
}
}
}
}
如果快捷设置主要作为开关使用,官方建议在AndroidManifest
中添加可切换标志,示例代码如下:
xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
......
>
<service
......
>
<meta-data
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
android:value="true" />
......
</service>
</application>
</manifest>
PS:示例代码中快捷设置的监听模式为Active mode
演示效果
禁用快捷设置
如果由于某些原因用户无法再使用快捷设置了,通过PackageManager.setComponentEnabledSetting()
方法禁用对应的服务,示例代码如下:
kotlin
class TileExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = LayoutTileExmpleActivityBinding.inflate(layoutInflater).also {
setContentView(it.root)
}
binding.btnDisableTile.setOnClickListener {
packageManager.setComponentEnabledSetting(ComponentName(this, ExampleTileService::class.java), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
}
}
}
演示效果
处理点击
当快捷设置处于Tile.STATE_ACTIVE
和Tile.STATE_INACTIVE
状态下时,用户点击时会回调TileService
的onClick()
方法,可以根据需求进行处理。
打开弹窗
如果使用弹窗就能满足需求,可以调用TileService
的showDialog()
方法打开弹窗,示例代码如下:
kotlin
class ExampleTileService : TileService() {
......
override fun onClick() {
super.onClick()
showDialog(AlertDialog.Builder(this)
.setTitle("Tile Example")
.setMessage("This is a tile example dialog")
.setPositiveButton("ok") { dialog, _ ->
dialog?.dismiss()
}
.create())
}
......
}
PS:实测中使用androidx.appcompat.app.AlertDialog
会崩溃。
演示效果
打开页面
如果弹窗无法满足需求,那么可以调用TileService
的startActivityAndCollapse()
方法打开Activity
,示例代码如下:
kotlin
class ExampleTileService : TileService() {
......
override fun onClick() {
super.onClick()
// 此方法提示过时,但是在实测中,我的Google Pixel 3a XL只能使用此方法
// 使用下面那个方法会报错。
startActivityAndCollapse(Intent(this, CameraActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
// 此方法为当前推荐使用的方法。
// 实测小米14可以通过此方法打开页面。
startActivityAndCollapse(PendingIntent.getActivity(this, this.hashCode(), Intent(this, CameraActivity::class.java), PendingIntent.FLAG_IMMUTABLE))
}
......
}
演示效果
检验是否安全
在部分设备上,锁屏状态下也可以使用下拉栏的快捷设置,如果功能涉及敏感信息,那么就不应该锁屏状态时可以直接使用。可以使用TileService
的isSecure()
方法判断是否安全,如果返回false则可以使用TileService
的unlockAndRun()
方法让用户解锁后使用功能,示例代码如下:
kotlin
class ExampleTileService : TileService() {
......
override fun onClick() {
super.onClick()
if (isSecure) {
handleClick()
} else {
unlockAndRun { handleClick() }
}
}
private fun handleClick() {
showDialog(AlertDialog.Builder(this)
.setTitle("Tile Example")
.setMessage("This is a tile example dialog")
.setPositiveButton("ok") { dialog, _ ->
dialog?.dismiss()
}
.create())
}
......
}
演示效果
完整示例代码
所有演示代码已在示例Demo中添加。