Android 9.0で通知の音を変更(無音化)しようとしたらハマったので対処法をメモ

# 概要

普段Android 8.1の実機およびエミュレータでアプリの動作確認をすることが多いのですが、先日ふとAndroid 9.0のエミュレータで開発中のアプリを動作確認していたところ、以前よりも妙に通知オンが鳴ることに気づきました。

通知を頻繁に出すアプリのため「ピコンピコン」音がなり続けるのは許容できず、対処方を探していたところ少しハマりポイントがあったのでメモします。サクッと調査しただけなので、もっと良い対処方法あったらコメントいただきたいです :pray: 

# 従来のNotification無音化(Soundの変更)

説明のため、下記に通知表示用のサンプルコードを記載します。(Android 8.0以降を想定)

```kotlin

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val name = "channel_name_sample"
        val id = "channel_id_sample"

        if (notificationManager.getNotificationChannel(id) == null) {
            notificationManager.createNotificationChannel(
                    NotificationChannel(
                            id,
                            name,
                            NotificationManager.IMPORTANCE_DEFAULT
                    )
            )
        }
        val notification = NotificationCompat
                .Builder(this, id)
                .apply {
                    setSmallIcon(R.drawable.ic_launcher_background)
                    setContentTitle("title")
                    setContentText("content")
                    //setSound(Uri.parse("android.resource://" + packageName + "/" + R.raw.sample))
                    //setDefaults(0) 
                }.build()

        notificationManager.notify(1, notification)
```

今回、Android 9.0で通知オンがオフにできていないことに気づく前は、上記コードのコメントアウトをしている箇所で、通知の音を設定していました。
(NotificationCompat.Builderを用いて、音を変更したい場合はsetSound(~)を、音を消したい場合はsetDefaultsメソッドに0を渡す)
setDefaultsはSoundに限ったメソッドではないため、通知の音を消したい場合、setSound()メソッドに無音の音源を渡すといった対処をしている記事もネット上で見かけます。

# Android 9.0での対処方法

今までは上記の対処で通知音が気にならなかったはずが、Android 9.0のデバイスでは上記の対処では思った通りの動作をしませんでした。

NotificationManagerのIMPORTANCEを変えてみたり、NotificationCompat.Builderに無音ファイルを渡してあげるなど、試行錯誤をしてもなかなか解決しなかったのですが、Notification周りを調べていたところ、下記の対処で音の無音化、変更ができました。

```kotlin
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val name = "channel_name_sample"
        val id = "channel_id_sample"

        if (notificationManager.getNotificationChannel(id) == null) {
            val notificationChannel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT).apply {
                setSound(null, null)
                //setSound(Uri.parse("android.resource://" + packageName + "/" + R.raw.sample), null)
            }
            notificationManager.createNotificationChannel(notificationChannel)
        }
        val notification = NotificationCompat
                .Builder(this, id)
                .apply {
                    setSmallIcon(R.drawable.ic_launcher_background)
                    setContentTitle("title")
                    setContentText("content")
                }.build()

        notificationManager.notify(1, notification)
```

異なる点は、NotificationCompat生成時に設定しているか、NotificationChannel生成時に設定しているかの違いです。
通知を無音化したい場合は、無音化したい通知のチャンネルにsetSound(null, null)を指定してあげると無音化されます。(通知音を変更したい場合は、setSoundメソッド)

NotificationChannel生成時に設定するIMPORTANCEの違いによっても、上記の挙動は変わりませんでした。通知単体に音を設定する方法はなさそうなので、今後は音を変えたい場合や特定の通知を消したい場合は、通知チャンネルを分けていくことになりそうです。 

# 余談
Android8.0で通知チャンネルが登場してだいぶ経っていますが、Android8.0やAndroid8.1の端末では起きていなかった事象だと思うので、Android9.0から発生した現象ということで良いのでしょうか・・・？。

ちなみに、通知はServiceのstartForegroundメソッドでも利用をするかと思いますが、こちらAndroid9.0からパーミッションの明記が必要になったんですね。

``` kotlin
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
```