フルスクリーン(全画面モード)でコンテンツを提供することに適したアプリケーションがあります。
例えば、動画プレーヤー、ゲーム、電子書籍リーダ、画像エディター、スライドショーなどです。
アンドロイドはフルスクリーンを3つのモードに分類しています。
目次
フルスクリーンモード(全画面モード)
フルスクリーンは用途の違いにより、3つのモードに分類できます。
| モード | 適したコンテンツ | 再表示する方法 (画面の操作) | アプリ例 | 
|---|---|---|---|
| 鑑賞モード | 画面を頻繁に操作しない | タップ | 動画プレーヤー スライドショー | 
| 没入モード | 画面を頻繁に操作する | 上下端からスワイプ | ゲーム (キャラ移動を画面操作) 電子書籍リーダ (ページ送りで画面操作) | 
| アプリ優先型 没入モード | 画面を頻繁に操作する | 上下端からスワイプ ・黒の半透明 ・一定時間後に非表示 ・アプリでも処理 | 画像エディター (領域選択で画面操作) | 
フルスクリーンはSystem Barが非表示なので、携帯端末はそのアプリケーションのみを実行しているように振舞います。
しかし、通知のチェックやちょっとした検索など、ユーザの要求に応じた処理も行わなければなりません。
その時はフルスクリーンを終了し、システムにアクセスが可能な状態へ移行するため、System Barを再表示させます。
通常、System Barを再表示させる方法は画面の操作で行われ、モードに適したものが割り当てられます。
鑑賞モード(Lead back mode)
画面を頻繁に操作しないコンテンツに適したモードです。
System Barを再表示する画面の操作は、簡素な「画面のタッチ」になります。
これは、System Barを再表示する画面の操作のみを考慮すればよいためです。
※System Barを非表示にする制御は次の記事を参照してください。
  System Bar:表示・非表示の制御(<Api30)
  System Bar:表示・非表示の制御(≧Api30)
    override fun onResume() {
        super.onResume()
        hideSysBarInLeadBack()
    }
    // --------------------------------------------------------------
    private fun hideSysBarInLeadBack() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_TOUCH
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_FULLSCREEN
                            or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }
    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }

没入モード(Immersive mode)
画面を頻繁に操作するコンテンツに適したモードです。
System Barを再表示する画面の操作は、複雑さを持たせた「画面の上下端からのスワイプ」になります。
これは、コンテンツの操作とSystem barを再表示する操作を区別(同じにならないように)する必要があるためです。
System Barを非表示にする制御は次の記事を参照してください。
  System Bar:表示・非表示の制御(<Api30)
  System Bar:表示・非表示の制御(≧Api30)
    override fun onResume() {
        super.onResume()
        hideSysBarInImmersive()
    }
    // --------------------------------------------------------------
    private fun hideSysBarInImmersive() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_SWIPE
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_IMMERSIVE
                            or SYSTEM_UI_FLAG_FULLSCREEN
                            or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }
    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }

アプリ優先型没入モード(Sticky immersive mode)
画面を頻繁に操作するコンテンツに適したモードです。
System Barを再表示する画面の操作は、複雑さを持たせた「画面の上下端からのスワイプ」になります。
ただし、コンテンツの操作とSystem barを再表示する操作を区別しません。両者に対する操作として受け付けます。
コンテンツの操作が優先して行われ、フルスクリーンが継続されます。フルスクリーンの表示を妨げないように、System Bar(黒の半透明)は一時的な再表示になります。
System Barを非表示にする制御は次の記事を参照してください。
  System Bar:表示・非表示の制御(<Api30)
  System Bar:表示・非表示の制御(≧Api30)
    override fun onResume() {
        super.onResume()
        hideSysBarInStickImmersive()
    }
    // --------------------------------------------------------------
    private fun hideSysBarInStickImmersive() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior =
                    BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        or View.SYSTEM_UI_FLAG_FULLSCREEN
                        or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }
    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }

バックグラウンドから復帰でフルスクリーン
フルスクリーンの状態からActivityがバックグラウンドへ遷移すると、System Barの非表示は解除されてしまいます。ダイアログが表示された場合などが、これに当てはまります。
よって、再びフォアグラウンドに復帰した時、フルスクリーンになりません。

これを回避し、フルスクリーンを維持したければ、フォアグラウンドへ復帰する時点でSystem Barの非表示を再指定します。
回避方法1:onResumeで非表示を指定
フォアグラウンドへ復帰する時は必ずonResume( )が呼ばれるので、ここで非表示の指定を実行します。
    override fun onResume() {
        super.onResume()
        hideSysBarInXXX()	// System Barを非表示
    }
回避方法2:onWindowFocusChangedで非表示を指定
フォアグラウンドのViewが切り替わる時は必ずフォーカスの移動(変更)が伴います。このフォーカスの移動をトリガにして、非表示の指定を実行します。
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if(hasFocus) {
            hideSysBarInXXX()	// System Barを非表示
        }
    }
System Barの表示・非表示のイベント処理
System Barが表示・非表示になった時のイベント処理をしたければ、リスナーを登録します。
「≧Api30」と「<Api30」で使えるリスナーが異なっているので注意してください。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.setOnApplyWindowInsetsListener(
                object : OnApplyWindowInsetsListener {
                    override fun onApplyWindowInsets(v: View, insets: WindowInsets)
                            : WindowInsets {
                        val _flag = (WindowInsets.Type.statusBars() or 
						                  WindowInsets.Type.navigationBars())
                        if(insets.isVisible(_flag)) // systemBars()は使用不可
                            // System Barが表示の時
                        else
                            // System Barが非表示の時
                        return v.onApplyWindowInsets(insets) // 下位へ実行を伝搬させる
                    }
                })
        }
        else {
            window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
                val _flag = (SYSTEM_UI_FLAG_FULLSCREEN or 
				                       SYSTEM_UI_FLAG_HIDE_NAVIGATION)
                if(visibility and _flag == 0)
                    // System Barが表示の時
                else
                    // System Barが非表示の時
            }
        }
「≧Api30」のリスナー登録
OnApplyWindowInsetsListenerを使います。「≧Api30」で追加になったクラスです。
WindowInsets#isVisible( )メソッドを用いてSystem Barの表示・非表示がチェックできます。
注意1:onApplyWindowInsets( )を実行
OnApplyWindowInsetsListenerを登録すると、onApplyWindowInsets( )の実行が子Viewへ伝搬しなくなります。
これは、登録した側のonApplyWindowInsets( )の実行が優先され、Viewが持つonApplyWindowInsets( )が実行されなくなるためです。
なので、リスナー中でViewが持つonApplyWindowInsets( )実行して伝搬を施します。
注意2:systemBars( )は使用不可
WindowInsets#isVisible( )の引数へsystemBars( )を用いると、System Barの表示・非表示に関係なくfalseが返ります。
なので、statusBars( )またはnavigationBars( )を用いるようにします。
「<Api30」のリスナー登録
OnSystemUiVisibilityChangeListenerを用います。「≧Api30」で非推奨になったクラスです。
System Barの表示・非表示の状態をvisibilityが持っています。
関連記事:
