#「他のアプリより上に重ねて表示」の権限
Android11より前では「他のアプリより上に重ねて表示」の権限を許可するために「Settings.ACTION_MANAGE_OVERLAY_PERMISSION」のインテントアクションで、直接、そのアプリの「他のアプリより上に重ねて表示」の権限を許可する設定画面が開けていましたが、Android11からは、「他のアプリより上に重ねて表示」できるアプリ一覧画面にしか飛べなくなりました。つまり…、ユーザには、その画面からわざわざ該当アプリを探してもらって、「他のアプリより上に重ねて表示」の権限を許可する設定画面に遷移してもらわないといけなくなったんです。
####えっ、ちょっと待って、それじゃ、ユーザにリストからアプリを探して選択させて、許可をしてもらって、さらに2画面分前に戻らないと、元のアプリまで戻れないじゃん!Googleさん勘弁してくださいよぉ。
って感じで、今まで1画面で完結してたんで、大したことはなかったのですが、これはちょっとユーザ負担が大きくなりますね…
#調査
ただ、「ユーザにリストからアプリを探して選択させて」って部分は、どうにも回避することは出来なさそう…、なんとか、許可後に2画面戻るという手間をなんと回避できないものかと考えていたところ。同じように、「他のアプリより上に重ねて表示」の権限を求めているアプリがあったので操作してみたら、期限許可のスイッチをオンにした瞬間に元のアプリ画面に戻ったではありませんかっ!
えっ、どうやってのこれ!「Settings.ACTION_MANAGE_OVERLAY_PERMISSION」のインテントアクションでstartActivityするときに、権限のチェックをスレッドでポーリングでもしてるんかしらと思ったんですが、調べたらありました。
#解決法
以下のようにAppOpsManager.startWatchingModeなるものを使えば、権限の変化を監視できるようです。このAppOpsManager.startWatchingModeは、これに限らず、他の権限についても監視できるようです。Androidの開発歴は結構長いのですが、私はこれを知りませんでした…
これを使って、監視をして、変化(許可)があったら、元のアクティビティを起動するようにすれば、許可後に2画面戻るという手間は回避できました。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
if (!Settings.canDrawOverlays(this)) { //権限が許可されていないか
val uri = Uri.parse("package:" + packageName)
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, uri)
startActivity(intent)
val appOpsManager = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
appOpsManager.startWatchingMode(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, packageName, object : AppOpsManager.OnOpChangedListener {
override fun onOpChanged(op: String?, packageName: String?) {
appOpsManager.stopWatchingMode(this) //監視を止める
//許可されたら行いたい処理を書く
}
})
}
}