Androidのアプリの中には、 何かのアプリを起動中もずっと画面上に残り続けるアプリがあると思います。
今回は、上記のように他のアプリケーション上で、
自分のアプリケーションのViewを表示する方法について試して見ました。
Androidのviewは、複数のレイヤーによって構成されており、
通常のアプリケーションのレイヤーは、他のアプリケーションの画面上に乗せることができません。
常に画面上に自分のアプリケーションのViewを表示し、
他のアプリケーションが起動中も自分のアプリのViewを画面上に表示するためには、WindowManager
を使ってレイヤーを指定する必要があります。
通常のアプリケーションの上に載せられるレイヤーには、
幾つか種類がありますが、今回は、画面上のViewに対してタッチイベントを取得したかったので、WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
を使用しました。
※
Androidのレイヤーについては、下記の参考リンクにて詳しく説明されているので、ご参照ください。
使い方は、
以下のようにまずWindowManager
のインスタンスを取得し、
画面上に出したいViewをWindowManagerに対してaddView()
します。
その際に、LayoutParamsにWindowManager.LayoutParams.TYPE_SYSTEM_ALERT
を指定することで、
通常のアプリケーションよりも上にViewを表示することが可能となります。
WindowManager.LayoutParams Params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // アプリケーションのTOPに配置 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // フォーカスを当てない(下の画面の操作がd系なくなるため) WindowManager.LayoutParams.FLAG_FULLSCREEN | // OverlapするViewを全画面表示 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // モーダル以外のタッチを背後のウィンドウへ送信 PixelFormat.TRANSLUCENT); // viewを透明にする WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.addView([OverlapView], mOverlapViewParams);
※
通常のアプリケーションよりも上にViewを表示するため、
使用後は、removeView()
でViewを削除しないと、
画面上にずっと出続けてしまう危険がありますので注意が必要です。
[サンプル]
以下のサンプルでは、
ActivityからServiceをBindし、ServiceからWindowmanagerに対して、
ViewをaddView()
しています。
アプリケーションが終了したタイミングで、
画面上に表示しているViewも一緒に削除されるようにServiceのunbindのタイミングで、
removeView()
を呼び画面からViewを削除しています。
■ OverlapService.java
public class OverlapService extends Service { private WindowManager mWindowManager; private FrameLayout mOverlapView; private WindowManager.LayoutParams mOverlapViewParams; // Serviceに接続するためのBinderクラスを実装する public class LocalBinder extends Binder { //Serviceの取得 OverlapService getService() { return OverlapService.this; } } // Binderの生成 private final IBinder mBinder = new LocalBinder(); @Override public IBinder onBind(Intent intent) { // Service接続時に呼び出される // 戻り値として、Serviceクラスとのbinderを返す。 Log.i("", "onBind" + ": " + intent); return mBinder; } @Override public void onRebind(Intent intent){ // Unbind後に再接続する場合に呼ばれる Log.i("", "onRebind" + ": " + intent); } @Override public boolean onUnbind(Intent intent){ // Service切断時に呼び出される // onUnbindをreturn trueでoverrideすると次回バインド時にonRebildが呼ばれる return true; } @Override public void onCreate() { super.onCreate(); mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); LayoutInflater layoutInflater = LayoutInflater.from(this); mOverlapView = new FrameLayout(getApplicationContext()); ((FrameLayout)mOverlapView).addView(layoutInflater.inflate(R.layout.Overlap_content_view, null)); mOverlapViewParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // アプリケーションのTOPに配置 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // フォーカスを当てない(下の画面の操作がd系なくなるため) WindowManager.LayoutParams.FLAG_FULLSCREEN | // OverlapするViewを全画面表示 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // モーダル以外のタッチを背後のウィンドウへ送信 PixelFormat.TRANSLUCENT); // viewを透明にする mWindowManager.addView(mOverlapView, mOverlapViewParams); } @Override public void onDestroy() { // ServiceがunbindされるタイミングでViewも削除して上げる mWindowManager.removeView(mOverlapView); super.onDestroy(); } }
■ MainActivity(呼び出し元)
public class MainActivity extends Activity { // Serviceとのインターフェースクラス private ServiceConnection mConnection = new ServiceConnection() { OverlapService mBindService; public void onServiceConnected(ComponentName className, IBinder service) { // Serviceとの接続確立時に呼び出される。 // service引数には、Onbind()で返却したBinderが渡される mBindService = ((OverlapService.LocalBinder)service).getService(); //必要であればmBoundServiceを使ってバインドしたServiceへの制御を行う } public void onServiceDisconnected(ComponentName className) { // Serviceとの切断時に呼び出される。 mBindService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bindBtn = (Button) findViewById(R.id.bind_service_button); bindBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(MainActivity.this,OverlapService.class); bindService(i, mConnection, Context.BIND_AUTO_CREATE); } }); Button unbindBtn = (Button) findViewById(R.id.unbind_service_button); unbindBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceをunbindする unbindService(mConnection); } }); } @Override protected void onDestroy() { super.onDestroy(); // Serviceをunbindする unbindService(mConnection); } }
(参考リンク)
http://techbooster.org/android/ui/13182/
http://matsuhilog.blogspot.jp/2011/06/typesystemalert.html