Lollipop以降での通知(DroidKaigiアプリにContributeしたポイント)


過日、[DroidKaigi 2016](https://droidkaigi.github.io/2016/)が開催され、[@konifar](https://twitter.com/konifar)さんの手により開発が始まった[公式アプリ](https://github.com/konifar/droidkaigi2016/)も公開されました。
私も通知機能関係でいくつかPRを出したので、簡単にその解説をしてみます。

## 関連資料

私のPRはTechBoosterの同人誌にLollipopの通知の記事を書いた時に一通り調べた情報が元になっています。
機能概要だけ知るにはLT資料を読むといいです。

- **[書いた本]** TechBooster - 甘味アンドロイドパーク  
  http://techbooster.github.io/c87/#park
- **[原稿用メモ]** Android 5.0 LollipopでのNotificationについて - Qiita  
  http://qiita.com/mstssk/items/099a22976dd2dccdd1ea
- **[LT資料]** アプリの通知をLollipop対応しよう / shibuya.apk 2015-05-22 LT  
  https://speakerdeck.com/mstssk/shibuya-dot-apk-2015-05-22-lt  
  ※資料内でDroidKaigiに触れてますが、2015年の話です。

## Pull Requests

アプリの基本的な[通知機能](https://github.com/konifar/droidkaigi2016/pull/120)や[設定機能](https://github.com/konifar/droidkaigi2016/pull/189)は[punchdrunker](https://github.com/punchdrunker)さんが実装されました。
更にLollipop以降の新しい通知関係のfeatureに対応させるためのPRを私が出しました。


### Support Lollipop notification feature

https://github.com/konifar/droidkaigi2016/pull/228

以下の4点を実装するPRです。

#### ■優先モードのため`category`を設定する

Lollipopで[category](https://developer.android.com/intl/ja/reference/android/app/Notification.html#category)というフィールドがNotificationクラスに増えました。
端末が優先モードの場合、ユーザが設定したカテゴリの通知のみ通知音・バイブが行われます。
MarshmallowだとQuick Settingsで「優先する通知のみ」って表示されるモードです。

今回は[CATEGORY_EVENT](https://developer.android.com/intl/ja/reference/android/app/Notification.html#CATEGORY_EVENT)を設定しました。

ちなみに、メッセージや電話着のカテゴリの場合は、優先度の判定のため[addPerson](https://developer.android.com/intl/ja/reference/android/app/Notification.Builder.html#addPerson(java.lang.String))メソッドで連絡先情報を通知に追加することも出来ます。

※同人誌の執筆当時、このモードを私は重要モードと訳していたのですが、今は日本語版公式ドキュメントがあり「優先」モードと記載されていたので合わせておきます。

<img height="480" src="https://qiita-image-store.s3.amazonaws.com/0/25045/d7ce152a-4e65-ff9e-6f14-2dd1a5e7e14c.png">
※Lollipopでのスクリーンショット

#### ■ロック画面に表示するため`visibility`を設定する

Lollipopで[visibility](https://developer.android.com/intl/ja/reference/android/app/Notification.html#visibility)というフィールドがNotificationクラスに増えました。
端末の設定が「プライベートな通知内容を非表示にする」の場合、`visibility`に応じてロック画面に表示する通知内容が切り替わります。

ロック画面でも確認できるよう今回は[VISIBILITY_PUBLIC](https://developer.android.com/intl/ja/reference/android/app/Notification.html#VISIBILITY_PUBLIC)を設定しました。

例えばメールの通知など、プライベートな情報が含まれる場合は[VISIBILITY_PRIVATE](https://developer.android.com/intl/ja/reference/android/app/Notification.html#VISIBILITY_PRIVATE)または[VISIBILITY_SECRET](https://developer.android.com/intl/ja/reference/android/app/Notification.html#VISIBILITY_SECRET)を設定するべきです。
`VISIBILITY_PRIVATE`の通知には[公開用の別の通知を設定](https://developer.android.com/intl/ja/reference/android/app/Notification.Builder.html#setPublicVersion(android.app.Notification))する事ができます。

<img height="480" src="https://qiita-image-store.s3.amazonaws.com/0/25045/a0a3c774-0336-326b-5361-84de79c0876d.png">


#### ■ヘッドアップ通知のため`priority`を設定する

Jelly Beanで[priority](https://developer.android.com/intl/ja/reference/android/app/Notification.html#priority)というフィールドがNotificationクラスに増えていました。
Lollipopからはヘッドアップ通知を表示するかどうかの条件の1つとして`priority`を使用します。
Androidは通知の`priority`がHIGH以上かつ着信音/バイブが設定されいるとヘッドアップ通知として表示します。
※別の条件として、fullScreenIntentの場合もヘッドアップ通知になります。

別のことに気を取られたりしていてもヘッドアップ通知でユーザが気付けるよう今回は[PRIORITY_HIGH](https://developer.android.com/intl/ja/reference/android/app/Notification.html#PRIORITY_HIGH)を設定しました。

<img height="480" src="https://qiita-image-store.s3.amazonaws.com/0/25045/29fcf97e-8c21-e5db-4a0d-b67be3f89203.png">


#### ■ヘッドアップ通知のON/OFFのため設定画面へ項目を追加

ヘッドアップ通知はユーザに確実に重要な情報を知らせるために有用ですが、かなり煩わしいです。
そこで、ヘッドアップ通知のON/OFFをする設定項目を追加しました。
実装上は、設定内容にあわせて`priority`に設定する値を切り替えているだけです。

<img height="480" src="https://qiita-image-store.s3.amazonaws.com/0/25045/93360b1d-ec37-45c2-e781-d1d96cba61ac.png">

ただし、この実装がいいかというとそうではありません。この辺はヘッドアップ通知の闇っぽい所だと思ってます。
今回のアプリはエンジニアが使うものなので、ヘッドアップ通知という用語で設定項目を表現し簡単に済ませてあります。
設定項目をちゃんと作るなら着信音・バイブのそれぞれのON/OFFを作るべきですが、一方でエンドユーザは「`priority`がHIGH以上かつ着信音/バイブが設定されいる」なんて条件わかりませんし、ヘッドアップ通知なんて名前も知ったこっちゃありません。
Marshmallowで本体設定側にある個々のアプリ別のヘッドアップ通知ON/OFF項目は、「通知の瞬間表示を許可」「現在の画面で特定の通知をスライド表示することをこのアプリに許可する」なんて表記になっていて、苦しい感じが伝わってきます。
私が勉強不足なだけで、この辺のベストプラクティスがもうあったりしたらすみません。


### Support `NOTIFICATION_PREFERENCES` intent category.

https://github.com/konifar/droidkaigi2016/pull/289

Lollipopで[NOTIFICATION_PREFERENCES](https://developer.android.com/intl/ja/reference/android/app/Notification.html#INTENT_CATEGORY_NOTIFICATION_PREFERENCES)というintentカテゴリが増えました。
通知の設定画面activityのintent-filterにこのカテゴリを設定しておくと、通知を長押しした時に設定画面へ遷移する歯車アイコンが表示されるようになります。

今回のアプリは設定画面を個別のActivityにせずFragmentとして作っていたので、MainActivityのonCreateでintentの内容を見て表示するFragmentを切り替えるようにしました。

<img height="480" src="https://qiita-image-store.s3.amazonaws.com/0/25045/94bea914-0631-7c09-9b44-2da5e6472ec8.png">

この機能、開発ドキュメントあたりには全く載っていなくて、クラスリファレンスにしれっと定数が追加されているだけでした。[クラスのdiff](https://developer.android.com/sdk/api_diff/21/changes/android.app.Notification.html)見てなければ絶対知らないままだった…

### Set accent color to notifications.

https://github.com/konifar/droidkaigi2016/pull/326

Lollipopで[color](https://developer.android.com/intl/ja/reference/android/app/Notification.html#color)というフィールドがNotificationクラスに増えました。
Lollipopから通知アイコンは白単色が強制されるようになりましたが、`color`を設定しておくと通知ドロワ内で表示される通知アイコンの周囲の色を変更できます。

今回はDroidKaigi 2016のテーマ色を設定しました。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/25045/2048b4a1-3b6d-9f15-fcc7-05cec09743e7.png">

## その他

ロック画面にメディア再生コントロールが表示されなくなった替わりに[MediaStyle](http://developer.android.com/intl/ja/reference/android/app/Notification.MediaStyle.html)なんてのが増えていたり、[tickerText](http://developer.android.com/intl/ja/reference/android/app/Notification.html#tickerText)の役割が変わったりしています。
関連資料も見てみてください。