Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Androidの表示レイヤーと画面常駐型アプリの話

17,675 views

Published on

Published in: Technology
  • Be the first to comment

Androidの表示レイヤーと画面常駐型アプリの話

  1. 1. Androidの表示レイヤーと画面常駐型アプリの話
  2. 2. 今回の話  表示レイヤーとは?  任意のレイヤーにViewを表示させる  Viewの挙動を設定する  実装時の注意点
  3. 3. 表示レイヤーとは?    Androidの画面は複数の表示レイヤーによって構成されている。 通常のアプリを表示するレイヤーの他にトースト表示用のレイヤーや着 信画面用のレイヤーなどがある。 レイヤーによって表示順やフォーカスが当てられるかなど挙動が決まっ ている。  通知バーやロック画面より上に表示されるレイヤーもある。  アプリから任意のレイヤーにViewを置く事も出来る。
  4. 4. 主なレイヤーの種類 (WindowManager.LayoutParamsの定数参照)  TYPE_APPLICATION(アプリが通常表示されるレイヤー)  TYPE_PHONE(着信画面のレイヤー)  TYPE_TOAST(トーストを表示するレイヤー。タッチイベントを拾えない?)  TYPE_SYSTEM_ALERT(バッテリー不足時の警告などに使用されているレイヤー)  TYPE_SYSTEM_OVERLAY(画面の一番上に表示されるレイヤー。ロック画面にも 干渉するためフォーカスを取得出来ない) 下に書いたものほど上位のレイヤーです。 ただしレイヤーの順序は明確には決まっていないのか機種やバージョンに異なる場合があるようなので注意。 ※手持ちのGalaxyS3とエミュレータでも挙動が違った・・・。(バグ?)
  5. 5. 任意のレイヤーにViewを表示させる      任意のレイヤーにViewを追加するにはWindowManagerクラスの addView(View view, LayoutParams params)を呼ぶ。 addViewを呼ぶと画面に新しいViewを追加する事が出来る。 viewと一緒に渡すWindowManager.LayoutParamsのコンストラクタ引 数で表示レイヤーを指定出来る。 ServiceからViewを追加する事で、アプリがバックグラウンドにいる時 でも常に画面にViewを表示させ、Serviceから操作出来るようにする。 Viewを消す時はremoveView(View view)を呼ぶ。
  6. 6. WindowManager.LayoutParams  WindowManager.LayoutParamsの引数は   (int w, int h, int _type, int _flags, int _format)   _typeで指定した値によってViewの表示レイヤーを指定する事が出来る。 _flagsで指定した値によってViewをタッチ出来るかなどの挙動を指定する 事が出来る。
  7. 7. 実装例 mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.window, null); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); mWindowManager.addView(view, params); ※ServiceのonStartとかで
  8. 8. 実装例 mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.window, null); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); mWindowManager.addView(view, params);  このへんがポイント レイヤーはTYPE_TOASTかTYPE_SYSTEM_ALERT辺りを使うのが無難?
  9. 9. 動作例 <?xml version="1.0" encoding="utf-8"?> <LinearLayout -省略- > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="はろーうぃんどう" android:padding="16dp" android:textColor="#000000" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="閉じる" android:textColor="#000000" /> <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="EditText" > </EditText> </LinearLayout>
  10. 10. Viewの挙動を設定する    ViewにButtonなどを置きリスナーを登録すれば普通のActivityのように 様々な動作を行える。 ただしイベントを拾えるかはレイヤーの種類と_flagで設定した値による。 先の実装例ではTYPE_SYSTEM_ALERTだが、FLAG_NOT_TOUCHABLE を設定しているため、Viewはイベントを拾わずタッチは後ろのレイヤーに すり抜ける。         →画面にマスクをかけるようなアプリを作れる。
  11. 11. 主なFLAGの種類 (WindowManager.LayoutParamsの定数参照)    FLAG_NOT_TOUCHABLE(Viewはイベントを拾うことが出来ない) FLAG_NOT_FOCUSABLE(Viewはキー入力イベントのフォーカスを得る事が出来 ない。タッチは拾える) FLAG_KEEP_SCREEN_ON(Viewがある限り画面のバックライトを維持する) 他にもいろいろあるけど説明がややこしくてよく分からなかったので割愛しま した!!
  12. 12. キーイベントのフォーカスについて    TYPE_SYSTEM_ALERTなどでは特にFLAGを指定しなければEditTextなど でキーイベントのフォーカスを得る(ソフトキーボードを出す)事が出来ま す。 ただしViewにフォーカスが付いている状態ではタッチイベントを背後のレ イヤーを触れなくなるため、Viewをウィンドウ表示させてる意味が無く なってしまいます。 そこで私の作ったアプリでは通常時はFLAG_NOT_FOCUSABLEを設定し たLayoutParamsを使い、EditTextを触った時のみLayoutParamsを入れ 替えるという処理を行っています。(もっと良い方法あるのかな?)
  13. 13. 実装例 @Override public boolean onTouch(View v, MotionEvent event) { if (v.getId() == mView.getId()) { mWindowManager.updateViewLayout(mView, mNotFocusableParams); } else if (v.getId() == R.id.editText1) { mWindowManager.updateViewLayout(mView, mFocusableParams); } return false; }
  14. 14. 実装時の注意点     レイヤーを利用したアプリにはSYSTEM_ALERT_WINDOWのパーミッ ションが必要。 ちゃんとViewを消すような処理を書かないと、設定からアプリを強制終了 するまでViewを消せなくなってしまう可能性がある。 下手な実装をすると端末を何も操作出来ないような状態にも出来てしま う。特に通知バーやロック画面より上にViewを表示させるような場合は細 心の注意が必要。 実装の際はドキュメントをよく読み、多くのバージョンや端末でテストし 問題が起こらないかを確認しましょう。

×