WebViewのAlertDialogでImmersiveモードを維持する

Android の上部にあるツールバーと下部にあるナビゲーションバーを隠しフルスクリーンで表示する「Immersive モード」を使ってハイブリッドアプリを開発している際に、WebView 内の JavaScript で confirm を呼び出すと、全画面表示が解除されてツールバー及びナビゲーションバーが再び表示されてしまうという問題に直面したので調べました。

元々は confirm のボタンラベル名を拡張すべく WebChromeClient 内でこのようなコードを使っていました。

@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result)  {
  new AlertDialog.Builder(MainActivity.this)
    .setMessage(message)
    .setPositiveButton("確認",
      new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
          result.confirm();
        }
      })
    .setNegativeButton("消去",
      new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
          result.cancel();
        }
      })
    .setCancelable(false).create().show();
  return true;
};

この問題の根本にある原因はダイアログがフォーカスを持ってしまうことにあるようなので、参考にした文献のコードを利用し(ワンライナーフェチとしては少し残念な) AlertDialog を一旦 alertToShow に入れるようにして addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) を追加しました。

@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result)  {
  AlertDialog alertToShow = new AlertDialog.Builder(MainActivity.this)
(中略)
  alertToShow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
  alertToShow.show();
  return true;
};

今回の失敗談を一つ紹介すると、MainActivity に次のような全画面設定関数を用意して setPositiveButtonsetNegativeButton のそれぞれの onClick で呼び出したのですが、案の定ボタンを押した後に Immersive モードを再開するという間抜けな結果になり、上述したコードで不要になりました汗。

@SuppressLint("NewApi")
private void enableImmersiveMode() {
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
  }
}

この例は JavaScript の confirm でしたが、もちろん alert でも同じような処理で解決できると思います。更に調べているとテキストフォーム入力時の input にフォーカスした際に下部からニュッと現れるソフトキーボードと共に Immersive モードが解除されるという問題について Stackoverflow で多く議論されていることが分かりました。こちらも原因は同様なのですが WebView と連携した場合にどうなるのか、別投稿で紹介したいと思います。

参考:

投稿者: hkitago

個人事業主でウェブと iOS, Android アプリの開発者で一児の父親。JavaScript, ActionScript, AppleScript, PHP, SQL, ObjC, Swift, Java の読書実行試験運用管理を生業とし、Bind, Postfix, Apache を MacOS で使い、エディタは Vi, mi, Kod, Smultron, TextWrangler を経て Coda, Xcode, Android Studio といった IDE と CotEditor を重用しています。