Androidに対しての画面入力時のイベントを取得する方法についてまとめます。
以下の3通りに分けてまとめていきたいと思います。
- 同一アプリ内から取得する方法
- 別アプリから取得する方法
- Systemから取得する方法
アプリ内から取得する方法
Android Frameworkの場合、例えば以下のような順番でTouchEventが処理されていきます。
- Activity.dispatchTouchEvent()
- ViewGroup.dispatchTouchEvent()
- View.dispatchTouchEvent()
- View.onTouchEvent()
- ViewGroup.onTouchEvent()
- Activity.onTouchEvent()
いずれかの処理でタッチイベントが消費された時(return true)、それ以降のタッチイベントは処理されない仕組みになっています。
よって、対象をActivityとした場合、そのActivityのdispatchTouchEvent()をOverrideし、falseを返せば、タッチ処理時に処理を挟むことができます。
別アプリから取得する方法
Overlay Dummy Window
透明なFull ScreenのDummy Windowをスクリーン一番手前に生成してTouchEventを拾う方法です。
TouchEventが下のレイヤーのアプリに伝わらないので使えませんでした。
Zero Size Dummy Window
サイズ0のWindowを一番手前に作成します。
その際にFLAG_WATCH_OUTSIDE_TOUCHというフラグを与えると、Window外のTouchEventを消費することなく拾うことができます。
ただし、注意点が2つあります。
- Dummy Windowと検証用の画面は同一のセキュリティポリシーであること
(詳細はAndroid Security Policyをご覧くださいをご覧ください。) - FLAG_WATCH_OUTSIDE_TOUCHフラグはタッチ開始時のEventしか拾うことができない
(スワイプや離す時のイベントは拾えない)
> https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_WATCH_OUTSIDE_TOUCH
FLAG_WATCH_OUTSIDE_TOUCH
Window flag: if you have set FLAG_NOT_TOUCH_MODAL, you can set this flag to receive a single special MotionEvent with the action
MotionEvent.ACTION_OUTSIDE for touches that occur outside of your window.
Systemから直接取得する方法
Linux Input Subsystem
Linux Kernelは入力デバイスのInput APIをInput Subsystemで提供しています。
AndroidはこのInput Subsystemを使って入力デバイスを制御しています。
Input SubsystemはLinuxデバイスファイルから制御することができ、デバイス毎に /dev/input/XXX に存在します。
利用する際はlinux/input.hのプロトコルに従って制御することができます。
アクセスするためには、ADBのユーザ権限が必要です。
Reference: https://source.android.com/devices/input/overview.html
geteventコマンド
Android内のコマンドとして、geteventコマンドが存在します。
このコマンドは上記のLinux Input Subsystemを利用して実装されています。
Reference: https://source.android.com/devices/input/getevent.html
Android Security Policy
AndroidアプリケーションはSandboxによってアプリケーションを分離しています。
AndroidのSandboxはLinux user-base Protectionによって動作しており、Linux Kernelが提供している以下の機能を利用しています。
- ユーザベースの権限モデル
- プロセス分離
- IPC
- SELinux
よって、Aユーザ - Bユーザ(アプリA - アプリB)間では、
ファイル、メモリ、CPUリソース、デバイス情報等には一切アクセスすることはできません。
通常、アプリケーションがインストールされる段階で一意のユーザIDが割り当てられます。
割り当てられるユーザIDはManifestファイル内のandroid:sharedUserId属性で指定することも可能です。
同じユーザIDで起動した複数アプリケーションは同じセキュリティポリシーとなるので、アプリケーション間のリソースに自由にアクセスすることができます。
最後に
今後のAndroidのバージョン、セキュリティポリシーによってこれらの方法が使えなくなる可能性がありますのでご留意ください。