Androidのシステム設定を取得する、設定画面を開く

# はじめに

アプリで独自に用意している設定のうち、システム設定(設定アプリ上の設定)に依存するものはアプリ側でシステム設定画面に誘導したいことがあります。

例えば通知に関しては、Android 5からシステム設定でアプリ別に通知を無効化できるようになり、Android 8から優先度(priority)など様々な設定がシステム設定で制御できるようになりました。
そのためアプリ内で通知周りの設定を独自で用意していると、システム設定によっては機能しないことがあります。

このような場合、Intent Actionを用いてシステム設定画面に遷移させることで、ユーザーに設定の確認を促すことができます。

## 注意

基本的に暗黙的Intentで遷移させる手法なので、OSバージョンやメーカーによって目的の画面に遷移できないことがあります。

# システム設定画面に遷移する

例えばアプリ個別のシステム通知設定画面に遷移するには、次のようにIntent Actionに`Settings.ACTION_APP_NOTIFICATION_SETTINGS`を指定し、Extraにパッケージ名を設定します。 (Android 8以上のとき)

```kotlin:minSdkVersion=26
val intent = Intent()
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
startActivity(intent)
```

参照: [android.provider.Settings#ACTION_APP_NOTIFICATION_SETTINGS](https://developer.android.com/reference/android/provider/Settings.html#ACTION_APP_NOTIFICATION_SETTINGS)

Android 5以上をサポートする場合は、以下のようにします。

```kotlin:minSdkVersion=21
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"

// for SDK in 21 until 26
intent.putExtra("app_package", packageName)
intent.putExtra("app_uid", applicationInfo.uid)

// for SDK above 26
intent.putExtra("android.provider.extra.APP_PACKAGE", packageName)

startActivity(intent)
```

他の画面を開くActionも同様にSettingクラスの定数として定義されていて、通知チャンネル([ACTION_CHANNEL_NOTIFICATION_SETTINGS](https://developer.android.com/reference/android/provider/Settings.html#ACTION_CHANNEL_NOTIFICATION_SETTINGS))や、ディスプレイ設定([ACTION_DISPLAY_SETTINGS](https://developer.android.com/reference/android/provider/Settings.html#ACTION_DISPLAY_SETTINGS))などがあります。

## リファレンスにない画面に遷移する

リファレンスには全ての画面に対応するActionが定義されている訳ではなく、一部はHidden APIといってSDKから参照できないものもあります。

ただActionは単なるStringで定義されているので、[Androidのソースコード](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/provider/Settings.java)を見ればリファレンスに載っていない画面にも遷移させることができます。
(例えば`ACTION_APP_NOTIFICATION_SETTINGS`は[ここ](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/provider/Settings.java#1595)で定義されている)

※ Hidden APIはSDKでサポートされていないので、実際に遷移できるかどうかは期待しない方が良いです

# システム設定を取得する

例えばシステム全体の画面の輝度を取得するには以下のようにします。

```kotlin
val brightness = runCatching {
    Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS)
}.getOrNull()
```

参照: [android.provider.Settings.System#SCREEN_BRIGHTNESS](https://developer.android.com/reference/android/provider/Settings.System#SCREEN_BRIGHTNESS)

設定値が見つからない場合、`Settings.SettingNotFoundException`を返すので必ず例外処理が必要です。

他の設定値も[Setting.System](https://developer.android.com/reference/android/provider/Settings.System)や[Settings.Global](https://developer.android.com/reference/android/provider/Settings.Global)などに定義されています。
先ほどのように[Androidのソースコード](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/provider/Settings.java#3546)を見てリファレンスに載っていない設定値を直接Stringを与えて取得する方法もあります。

# システム設定を書き換える

一部の設定は値を書き換えることもできます。

## 1. 権限を得る
まずAndroid Manifestに以下の権限を追加します。

```xml
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
```

Target APIが23以降であれば、さらにユーザー自身がアプリに権限を与えるように設定する必要があります。

```kotlin
val intent = Intent()
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.action = Settings.ACTION_MANAGE_WRITE_SETTINGS
intent.data = Uri.parse("package:$packageName")
startActivity(intent)
```

通常の権限とは異なり、アプリ内でダイアログを表示して許可させることはできません。
アプリにシステム設定の変更を許可させる画面に遷移させ、ユーザーに許可してもらうという流れです。

## 2. 設定値を変更する

例えば画面の輝度を最大にするには以下のようにします。

```kotlin
val brightness = 255
Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL)
Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness)
```

なお、一般的には表示しているWindowの輝度だけを変更する[WindowManager.LayoutParams.screenBrightness](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#screenBrightness)を使うようです。
この方法で変更すると、ホーム画面など別のアプリでも輝度が維持されます。

# 参考文献

- [設定画面のインテントアクションまとめ - Qiita](https://qiita.com/nein37/items/087ef3ab6a11d6bbf9e6)
- [Runtime Permission とは別の特別なパーミッションたちとその扱い方 - Qiita](https://qiita.com/KeithYokoma/items/b434db6b501f369d3d20)
- [Any way to link to the Android notification settings for my app? - Stack OverFlow](https://stackoverflow.com/questions/32366649/any-way-to-link-to-the-android-notification-settings-for-my-app)