皆さんGoogle Homeは購入しましたか?

自分は miniだけ購入して、音楽再生や天気を教えてもらうなどデフォルトの機能を使っています。

音楽再生にはSpotifyで連携しています。Google Homeで再生中のとき、スマホに再生中の通知が表示されます。

今回のテーマはその通知です。
Google Homeが表示する通知が地味にリッチなので真似出来ないかなと思い、実装方法を調査しました。

こんな通知。展開したり折りたたむと、アニメーションします。

spotify.gif

NotificationCompat.Style

通知の種類はいくつか用意されています。

BigTextStyle などは馴染みがあると思いますが、今回のSpotfiyの通知は MediaStyle というものでした。

音楽系のサービスで利用されている MediaStyle と、通知領域をカスタムできる DecoratedCustomViewStyleDecoratedMediaCustomViewStyle について紹介します。

Style を変更するには NoficationCompat.BuilderStyle を設定します。

builder.setStyle(NotificationCompat.BigTextStyle().also { 
    // Styleならではの記述
})

MediaStyle

MediaStyle はSupport Library 26.0.0から v4 media-compat library に移ったようです。なので依存関係に追加が必要です。

implementation "com.android.support:support-media-compat:27.0.2"

Styleは以下のようになります。 android.support.v4.media.appからimportするので注意が必要です。android.support.v4.appNotificationCompat が被ります。

builder.setStyle(android.support.v4.media.app.NotificationCompat.MediaStyle()
                        .setShowActionsInCompactView(0)
                )

MediaSession が必要かと思いきや、無くても利用可能です。

通常の通知と異なり、 NotificationCompat.Builder#addAction追加したActionは、通知領域の中に表示されます。

MediaStyle#setShowActionsInCompactView の引数で、compact 状態のときに表示するActionを指定できます。追加したAction順にintで指定します。

以下の例は、 setShowActionsInCompactView(0) で、Actionを3つ追加したものです。

media.gif

DecoratedCustomViewStyle

通知のViewは RemoteViews を使うことでカスタムできますが、バージョン間や端末による違いなどを考慮する必要がでてきます。また、Actionが正しく表示されなくなります

これらの問題を解決しつつ、カスタムできるStyleが DecoratedCustomViewStyle です。

builder.setStyle(NotificationCompat.DecoratedCustomViewStyle())

カスタムViewを適応できる状態は3種類あります。

  • ContentView

    • 通知領域で折りたたまれてる状態です。
    • こちらを変更するにはNotificationCompat.Builder#setCustomContentViewを使います。
    • NotificationCompat.Builder#setContent は内部的には Deprecated になっているので利用しないようにしましょう。
  • BigContentView

    • 通知領域で展開されてる状態です。
    • こちらを変更するにはNotificationCompat.Builder#setCustomBigContentViewを使います。
  • HeadsUpContentView

    • HeadsUp通知で表示されてる状態です。
    • こちらを設定していない場合は ContentView が表示されます。
    • こちらを変更するにはNotificationCompat.Builder#setCustomHeadsUpContentViewを使います。
    • HeadUp通知の最大領域は、Nougat以降では148dpになるようです。
      • それ以上カスタムViewで表示させようとすると見切れます。

比較するとわかりますが、デフォルトで用意される領域は残しつつカスタムViewが適応できる形です。

DecoratedCustomViewStyle デフォルト
decorate.png no_decorate.png

DecoratedMediaCustomViewStyle

DecoratedMediaCustomViewStyleMediaStyle と同様に、 v4 media-compat library から利用します。

Styleは以下のようになります。

builder.setStyle(android.support.v4.media.app.NotificationCompat.DecoratedMediaCustomViewStyle()
                        .setShowActionsInCompactView(0)
                )

変更できる3つのViewを設定した状態が次のような状態です。

decorate_media.gif

Actionがアイコンで表示されるため、若干テキストで表示できる領域が大きいです。

OSバージョンによる違い

エミュレータで試した結果なので利用する端末によっては違う可能性があります。

L M N O
color_lollipop.png color_marshmallow.png color_nougat.png color_oreo.png

HeadsUp通知の条件

Oreoでは、Channelの設定でIMPORTANCE_HIGHになってないと通知のPriorityを変えたり、LEDや通知音を設定してもHeadsUpとして表示されません

背景色の変更

OreoからはViewのカスタムをしなくても背景色を変更できます。
NotificationCompat.Builder#setColorized で変更できますが、以下のどちらかを満たす必要があります。

  • ServiceからのForeground通知
  • MediaStyle or DecoratedMediaCustomViewStyleMediaSession を設定する

逆にNougatだと、どちらを設定しても背景色はそのままです。カスタムViewで背景色を変更すれば可能です。

Marshmallowだと、 NotificationCompat.Builder#setColor だけで背景色がつきます。

Lollipopだと、Marshmallowと挙動似ていますがHeads Up通知には背景色がつきません。

Heads Up通知の文字色

カスタムViewを当てた場合、MarshmallowとLollipopだと、Heads Up通知はデフォルトで白になる ので変更する際は注意が必要です。

mipmapを使うとクラッシュする

Oreoで NotificationCompat.Builder#setSsmallIconmipmap のリソースを利用するとSystem UIがクラッシュします。

System UIを再起動しても、通知が残っている限りクラッシュし続けます。

まとめ

Inboxのアプリ以外でも InboxStyle を使っても良いように、メディア再生を伴わないアプリで MediaStyle を使っても問題ありません。

通知領域からアイコンでユーザにアクションを促したい場合などはうまく使えると思います。NougatからActionで画像が利用できなくなったので、代替出来ると思います。

DecoratedなStyleを利用すれば、OSに馴染みつつカスタマイズできます。しかし、乱用してオレオレUIにして、ただただ他のアプリより目立つ風にしてしまうではなく、デザインガイドラインを読んで、意義に成り立つようなUIを設計してください。

リポジトリはこちらです。

https://github.com/sakebook/NotificationAnimationSample

参考

Revision 26.0.0 Release / Recent Support Library Revisions | Android Developers

Android N の通知 / Google Developers Japan

Heads-up notifications
/ Android Developers

Android 8.0 の機能と API / Android Developers

Android Oreo Notification Crashes System UI / Stack Overflow

Patterns– Notifications / Material Design