Androidの通知でアニメーションアイコンを表示する方法

Androidの通知でアニメーションを表示できるのでしょうか？
できるとすればアイコンですよね。

AndroidのNotificationでは `SmallIcon` と `LargeIcon` の2種類のアイコンを設定できます。

```kotlin
val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(R.drawable.ic_android)
    .setLargeIcon(Icon.createWithResource(this, R.drawable.ic_android))
    .setContentTitle("Title")
    .setContentText("Text")
    .build()
notificationManager.notify(1, notification)
```

ステータスバーに表示されるのが `SmallIcon`
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/547b21bc-62b1-ff13-5950-470afa8962ac.png)

これは通知の先頭にも表示されます。`LargeIcon`は通知の右側に表示されます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/76cb586d-bac1-b62e-b5d9-fae818e73d10.png)

# SmallIcon/LargeIcon のアニメーション

`SmallIcon` と `LargeIcon` は指定方法が異なります。
`SmallIcon` は ResourceID もしくは `IconCompat`
`LargeIcon` は `Icon` もしくは `Bitmap`
Bitmapはアニメーション情報を持たせることはできませんが、 アニメーションリソースを ResourceID として指定したり、そこから作った Icon を渡すことはできます。

`SmallIcon` のアニメーションはAndroidユーザーのほとんどの方が見たことがあるはずです。
そのアイコンは、システムリソースに用意されていて、どのアプリからでも使えるようになっています。 `android.R.drawable.stat_sys_download` です。

これを指定してみましょう。

```kotlin
val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(android.R.drawable.stat_sys_download)
    .setLargeIcon(Icon.createWithResource(this, android.R.drawable.stat_sys_download))
    .setContentTitle("Title")
    .setContentText("Text")
    .build()
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e70cd1ac-0e3f-f0e4-ffc0-ec218e355d09.gif)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/7fd18182-1864-ca91-6a2e-da0cefaba572.gif)

はい、ダウンロード中に表示されるアレですね。
これの実体は、 `AnimationDrawable` で以下のような定義になっています。
Drawableを複数枚つかったパラパラ漫画ですね。

```xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
    <item android:drawable="@drawable/stat_sys_download_anim0" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim1" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim2" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim3" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim4" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim5" android:duration="200" />
</animation-list>
```

`SmallIcon` と `LargeIcon` は `AnimationDrawable` を指定することでアニメーションを表示させることができました。
また、　minSdk　に注意が必要ですが、 `AnimatedVectorDrawable` を使うことも可能です。ただし、こちらの場合はループ再生はできないみたいです。

# RemoteViews にアニメーションアイコンを表示させる

　Notification　には　`RemoteViews` を使ったカスタムViewを表示させることができます。

```kotlin
val remoteViews = RemoteViews(packageName, R.layout.notification)
val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(R.drawable.ic_android)
    .setStyle(NotificationCompat.DecoratedCustomViewStyle())
    .setCustomContentView(remoteViews)
    .build()
```

RemoteViews は通常の View とは異なり、使用可能な View の種類が限定され、 View に対して行える操作も限定的になります。
以下のように複数の画像を表示させることはできますが

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
</LinearLayout>
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e783c225-6987-fb9f-c180-8e8e94c7b61d.png)

アニメーション表示されません。
AnimationDrawable は ImageView に貼り付けただけではアニメーションされず、drawableの `start()` メソッドを呼び出す必要がありますが、 RemoteViews の仕組みではこのメソッドを実行することはできません。

では、どうするか？ですが、じつは、 RemoteViews に使える View で勝手にアニメーションしてくれる View があります。
ProgressBar です。

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/57670a0d-0fad-8398-9d8f-5af79efe189c.gif)

そして、　ProgressBar　のクルクルアニメーションのリソースは `android:indeterminateDrawable` で別のアニメーションに差し替えることが可能です。

ということで、以下のようにレイアウトを作ると

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
</LinearLayout>
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/97018360-fa1f-2660-2754-8dbc6eb3c959.gif)

のような形で、自由度の高いレイアウトで、アニメーションを表示させることができます。

---

通知でのアニメーションは、下手に使うとユーザーに煩わしい印象を持たれてしまいマイナスになりかねませんので、ご利用は計画的に、よく考える必要があります。
ダウンロード中のアイコンのように短時間のステータス表示に使うとか、何か特別なイベントでの演出、のような工夫として使ってみるのであればありかもしれません。

以上です。