Android 下拉栏中的快捷设置(二)— 状态更新与事件处理

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_ACTIVETile.STATE_INACTIVE状态下时,用户点击时会回调TileServiceonClick()方法,可以根据需求进行处理。

打开弹窗

如果使用弹窗就能满足需求,可以调用TileServiceshowDialog()方法打开弹窗,示例代码如下:

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会崩溃。

演示效果

打开页面

如果弹窗无法满足需求,那么可以调用TileServicestartActivityAndCollapse()方法打开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))
    }
    
    ......
}

演示效果

检验是否安全

在部分设备上,锁屏状态下也可以使用下拉栏的快捷设置,如果功能涉及敏感信息,那么就不应该锁屏状态时可以直接使用。可以使用TileServiceisSecure()方法判断是否安全,如果返回false则可以使用TileServiceunlockAndRun()方法让用户解锁后使用功能,示例代码如下:

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中添加。

ExampleDemo github

ExampleDemo gitee

相关推荐
JasonYin~29 分钟前
HarmonyOS NEXT 实战之元服务:静态案例效果---手机查看电量
android·华为·harmonyos
zhangphil38 分钟前
Android adb查看某个进程的总线程数
android·adb
抛空1 小时前
Android14 - SystemServer进程的启动与工作流程分析
android
Gerry_Liang3 小时前
记一次 Android 高内存排查
android·性能优化·内存泄露·mat
天天打码4 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
爱数学的程序猿7 小时前
Python入门:6.深入解析Python中的序列
android·服务器·python
brhhh_sehe7 小时前
重生之我在异世界学编程之C语言:深入文件操作篇(下)
android·c语言·网络
zhangphil7 小时前
Android基于Path的addRoundRect,Canvas剪切clipPath简洁的圆形图实现,Kotlin(2)
android·kotlin
Calvin8808288 小时前
Android Studio 的革命性更新:Project Quartz 和 Gemini,开启 AI 开发新时代!
android·人工智能·android studio
敲代码敲到头发茂密9 小时前
【大语言模型】LangChain 核心模块介绍(Memorys)
android·语言模型·langchain