Android12以降でスプラッシュ画面のアイコンが表示されない場合がある

:::note info
SplashScreen API ([androidx.core.splashscreen](https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen)) を利用したスプラッシュ画面の実装を前提とします
:::

Android 12 以降において `startActivity() + Intent.FLAG_ACTIVITY_NEW_TASK`で Activity を新たに起動する場合、スプラッシュ画面のアイコンが表示されません。

| before | after |  
|:---:|:----:|  
|![splash_demo_before.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/aeb5d83e-1ccf-f16a-a6c8-32ded83151b8.gif)|![splash_demo_after.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/50b1b2f5-2806-5093-9bd7-5bca0b2dc449.gif)|  


# TL;DR

Activity の起動方法によらず常にスプラッシュ画面でアイコンを表示させるには以下の対応が必要です。


### Android 13 以降

themes で静的に指定できます

```diff_xml:themes.xml
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- 対象のActivityに適用するテーマ -->
     <style name="MySplash" parent="Theme.SplashScreen">
         <item name="windowSplashScreenBackground">@color/splash_background</item>
         <item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
+        <item name="android:windowSplashScreenBehavior" tools:targetApi="33">icon_preferred</item>
     </style>
 </resources>
```

### Android 12

Activityを起動するコードからオプション指定が必要です。ただし AndroidStudio から起動する場合にアイコンが表示されない問題は解決できません。

```diff_kotlin
    val intent = Intent(context, MyActivity::class.java)
-   startActivity(intent)
+   if (Build.VERSION.SDK_INT in listOf(31, 32)) {
+       val options = bundleOf("android.activity.splashScreenStyle" to 1)
+       startActivity(intent, options)
+   } else {
+       startActivity(intent)
+   }
```    


# 詳説

検証に使用したソースはこちら

https://github.com/Seo-4d696b75/android-splash-demo

## AndroidX ライブラリ

Android 12 においてOS側のスプラッシュ画面の挙動が大幅に変更され、同時に従来のスプラッシュ画面をAndroid 12 以降も一貫的に実装できるライブラリが提供されました。 SplashScreen API の詳細はここでは割愛します。

https://qiita.com/irgaly/items/7ebba96f16462158579d

https://developer.android.com/develop/ui/views/launch/splash-screen/migrate?hl=ja

## Android 12 以降の問題

SplashScreen API によるスプラッシュ画面が表示されるのは、

- コールドスタート	
  （例） アプリが完全に終了している状態でランチャーアプリから起動したとき
- ウォームスタート	
  （例） システムによりbackgroundのアプリが破棄された状態からforegroundに復帰したとき

一方で起動済み＆表示中のアプリから新たにActivityを起動すると、Android 12 以降に限りスプラッシュ画面自体は表示されますがアイコンが表示されません。具体的には以下のようなコードが該当します。


```kotlin
fun onRestartClicked() {
    val intent = Intent(context, MyActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    startActivity(intent)
}    
```  

## windowSplashScreenBehavior属性

:::note warn
API 33 (Android 13) 以降でのみ使用できます
:::


スプラッシュ画面を設定する`themes.xml`において`windowSplashScreenBehavior`属性でアイコン表示有無を制御できます。Activityの起動方法によらず常に表示させるには`icon_preferred`を指定します。

https://developer.android.com/develop/ui/views/launch/splash-screen?hl=ja#set-theme

```xml:res/values-v33/themes.xml
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- MyActivityに適用するテーマ -->
     <style name="MySplash" parent="Theme.SplashScreen">
         <item name="windowSplashScreenBackground">@color/splash_background</item>
         <item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
         <item name="android:windowSplashScreenBehavior">icon_preferred</item>
     </style>
 </resources>
```

コードから指定する場合は、
```diff_kotlin
    val intent = Intent(context, MyActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
-   startActivity(intent)
+   if (Build.VERSION.SDK_INT >= 33) {
+       val options = ActivityOptions.makeBasic().apply {
+           splashScreenStyle = SplashScreen.SPLASH_SCREEN_STYLE_ICON
+       }.toBundle()
+       startActivity(intent, options)
+   } else {
+       startActivity(intent)
+   }
```         

## Android 12 対応



`windowSplashScreenBehavior`属性はAndroid 13 で導入されたため、Android 12 では使用できません。スマートな方法が見つからず、みんな同じ問題で困っているようでした....


https://issuetracker.google.com/issues/205021357#comment14

開発側の回答にて以下のようなワークアラウンドが提案されています。`Bundle`だったら文字列でkeyを直接指定できるって発想ですね。


```diff_kotlin
    val intent = Intent(context, MyActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
+   if (Build.VERSION.SDK_INT in listOf(31, 32)) {
+       val options = bundleOf("android.activity.splashScreenStyle" to 1)
+       context.startActivity(intent, options)
    } else if (Build.VERSION.SDK_INT >= 33) {
```    


:::note warn
AndroidStudio から Run ボタンでアプリ起動する場合、Android 12 でアイコンが表示されない問題はこの方法でも回避できません。
:::