Androidのクイック設定タイルでは、一部の端末機能のON/OFFを変更できます。
以下のように、マイク・カメラ・位置情報は概ねどの端末でも設定できるかと思います。
ここで機能をOFFにされると、アプリとしてランタイムパーミッションを獲得していても、当該機能へのアクセスができなくなります。
それを判定するには、ContextCompat.checkSelfPermissionではなく、PermissionChecker.checkSelfPermission を利用します。
さて、ランタイムパーミッションの変化を判定する場合、onRequestPermissionsResultやそれに相当するコールバックや、別経路から設定された場合も想定して、onResumeで再評価を行うのが常套手段です。
しかし、クイック設定タイルで機能のON/OFFを行う場合、アプリのライフサイクルはRESUME状態から変化しない場合があります。
クイック設定タイルで機能のON/OFF
クイック設定タイルで機能のON/OFFとは、AppOpsの変更を行っていることになります。
この変更はAppOpsMAnagerで監視することができます。
startWatchingModeで監視開始、stopWatchingModeで監視停止です。停止しないとコールバックがリークしてしまいますので、必ず停止しましょう。
位置情報の変更を監視するには以下のようにします。
val appOpsManager = getSystemService<AppOpsManager>() ?: return
val callback = AppOpsManager.OnOpChangedListener { op, packageName ->
lifecycleScope.launch {
checkLocationPermission()
}
}
appOpsManager.startWatchingMode(AppOpsManager.OPSTR_COARSE_LOCATION, packageName, callback)
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
appOpsManager.stopWatchingMode(callback)
}
})
OnOpChangedListenerは、Binderスレッドで呼ばれるため、メインスレッドにディスパッチしてからパーミッションの判定を行います。
コールバックスレッド上で判定を行うと、OFFは判定できますが、ONが判定できませんでした。
なお上記では、AppOpsManager.OPSTR_COARSE_LOCATIONを使用していますが、以下のようにパーミッション文字列から取得することもできます。
val op = AppOpsManager.permissionToOp(Manifest.permission.ACCESS_COARSE_LOCATION) ?: return
これでアプリを表示したまま、クイック設定タイルで設定変更された場合も変更を即座に反映することができます。