2012年1月2日月曜日

オーバーレイ表示の方法

ディスプレイ上にViewをオーバーレイ表示する方法。
ssFlickerでもオーバーレイ起動(旧スワイプ起動)で利用しており、これが使えるようになるとアプリの表現の幅が広がると思う。
ただし、使い方を誤るとオーバーレイ画面がディスプレイを占有してしまい、何も操作できなくなってしまうので注意。




WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

LinearLayout ll = new LinearLayout(this);
ll.setLayoutParams(new LayoutParams(0, 0));
ll.setBackgroundColor(Color.RED);

WindowManager.LayoutParams wmLP = new WindowManager.LayoutParams(
  100,
  100,
  WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
  WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
  WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
  WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
  PixelFormat.TRANSLUCENT);

wm.addView(ll, wmLP);

あと、AndroidManifestに以下のpermissionを追加する必要がある。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

WindowManager.LayoutParamsの第3引数について少しだけ調べてみたのでメモしておく。
この値によって表示されるレイヤが変わる。
どうも2.xとICSにて異なるようなので試してみた。
設定できる値はいくつもあるのだけど、実際に試す事ができたのは以下6種類。
検証機種は初代XPERIA2.1とGN4.0。3.xでは試していない。

□2.xの場合
TYPE_SYSTEM_OVERLAY
===ロック画面===
TYPE_SYSTEM_ERROR(※)
TYPE_SYSTEM_ALERT
TYPE_PRIORITY_PHONE
===ステータスバー===
TYPE_TOAST
TYPE_PHONE

□4.0の場合
TYPE_SYSTEM_ERROR
TYPE_SYSTEM_OVERLAY
===ロック画面===
===ステータスバー===
TYPE_SYSTEM_ALERT
TYPE_PRIORITY_PHONE
TYPE_TOAST
TYPE_PHONE

(※)2012/1/4訂正。ロック画面の上に記載していたが誤り。正しくはロック画面の下。

違いは以下2点。なぜ変更したのかは調べていない。
・TYPE_SYSTEM_ERRORの順位が異なる。(4.0ではトップレイヤになっている)
・ロック画面とステータスバーの間のレイヤが異なる。(4.0では存在しない)

他にもtypeは存在するのでこれだけで結論付けるのはちょっと早計な気もするけど、他のtypeではうまく表示ができなかった。
他のtypeはリファレンスを参照のこと。コチラ

なお、ssFlickerの現バージョン(v0.7.7)では、オーバーレイポインタをTYPE_SYSTEM_ALERTで表示しているため、4.0ではステータスバーに隠れてしまうことがある。TYPE_SYSTEM_ERRORに変更しようかな。


===2012/1/4追記===

ブログを書いたときから薄々感付いてはいたんだけど、やっぱりこの機能を安易に利用するのは大変危険。
先に結論から言えば、TYPE_SYSTEM_ERRORにリスナを付けるのは避けるべき。
別のタイプでも危険性はあるんだけど、これは絶対に避けるべき。
ICSではTYPE_SYSTEM_ERRORがトップレイヤになっている。これはパターンロックの解除画面よりも上位に表示されることを意味する。
WindowManagerのサイズが大きいとパターンロックの解除画面を邪魔してしまい、ロック解除ができなくなってしまう。
WindowManagerのサイズを小さくすれば問題ないけれど、Android端末は機種によって画面サイズがまちまちなので将来を考えると「絶対に邪魔しない」とは言い切れない。
なお、TYPE_SYSTEM_OVERLAYはリスナが付与できないので問題ない。
うーん、TYPE_SYSTEM_ERRORがトップレイヤになっていること自体が疑問だったんだけど、Androidのバグじゃないだろうか?

2 件のコメント:

  1. Thanks for posting.
    I struggled on same problem with ICS.
    This article was really helpful :)

    返信削除
  2. You're welcome.
    I'm glad to helpful.

    返信削除