アプリからinputコマンド(擬似TouchEvent)を送信・実行する方法

4,071 views
Skip to first unread message

Masa

unread,
Jul 22, 2015, 7:55:52 PM7/22/15
to 日本Androidの会
初めて投稿します。Masaと申します。

他のアプリと連携する動作イメージを伝えるために、
画面上の一部にオーバーレイ表示させた自アプリから、
後ろにあるアプリに指定した座標のタッチイベントを送って動かすことができないかと考えています。

以下のサイトなどを参考にできそうな感じがしていたのですが、
アプリからinputコマンドを実行するとなるとうまく行きません。

・Android端末の操作自動化                http://techblog.qoncept.jp/?p=356
・アプリ内でADB コマンドを操作する     https://akira-watson.com/android/adb-commands.html
・XPERIA内部から自身へのadb接続    http://d.hatena.ne.jp/tarosay/20120708/1341737693

ProcessBuilder に input tap x y やinput swipe x1 y1 x2 y2 を渡していますが反応している気配がありません。

Terminal Emulator ではinputコマンドを打って実行することができるので
アプリからもできなくはないと思うのですが、具体的なアプローチがわからず悩んでおります。
テストで使用している端末はNEXUS 5 (rooted) Lolipop です。

似た内容の投稿がありましたが、今回はrootedであること、
Androidのバージョンも進んでいますので、実現できる方法があればご教授願います。

以上、宜しくお願い致します。

tach...@gmail.com

unread,
Jul 26, 2015, 1:09:23 PM7/26/15
to 日本Androidの会, heathphy...@gmail.com
signatureレベルのINJECT_EVENTパーミッションが必要だったはずです。
SecurityExceptionは出てませんか?
InputManagerあたりを読めば幸せになれるかも?



2015年7月23日木曜日 8時55分52秒 UTC+9 Masa:

Masa

unread,
Jul 27, 2015, 7:14:44 PM7/27/15
to 日本Androidの会, tach...@gmail.com
返信ありがとうございます。
パーミッションは入れていませんでしたが、SecurityException等WarningやErrorは出ていません。
INJECT_EVENTSを追加してみましたが、何も変化ありませんでした。

パーミッションを入れていなかったのにSecurityExceptionが出ていなかったということは
ProcessBuilderでタッチイベントが送れていないということでしょうか。

Masa

unread,
Jul 29, 2015, 3:05:16 PM7/29/15
to 日本Androidの会, heathphy...@gmail.com
デバッガで見たところ、ProcessBuilderからコマンドの送信はできているようです。
その結果として以下のエラーが出力されていました。
cannot bind 'tcp:5038'
*daemon not running. starting it now on port 5038*

自身へのadb接続がうまくできていない?
Terminal Emulator からは実行できるので、接続できているとは思うのですが・・・

河村潔広

unread,
Jul 29, 2015, 10:41:26 PM7/29/15
to android-g...@googlegroups.com
無いと思いますが、念のため
端末をTcp経由でadb接続する設定にしていますか?
していなければ、設定してください。

2015年7月30日木曜日、Masa<heathphy...@gmail.com>さんは書きました:
--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

Masa

unread,
Jul 30, 2015, 5:28:39 PM7/30/15
to 日本Androidの会, kyor...@gmail.com
kyorohiro様 ありがとうございます。
TCP経由でのadb接続はこちらを参考に設定しています。

・XPERIA内部から自身へのadb接続    http://d.hatena.ne.jp/tarosay/20120708/1341737693

ですので、PCから外した状態でも端末のTerminal Emulatorからはadbを実行できています。

Shin Miyazaki

unread,
Jul 30, 2015, 9:21:28 PM7/30/15
to android-g...@googlegroups.com

こんにちは。

具体的にProcessBuilderをどのように生成していますか?
自端末内のコマンドを起動するだけならadbは無関係なのですが、どうもadbにこだわって遠回りをしている気がします。

--

河村潔広

unread,
Jul 30, 2015, 11:12:43 PM7/30/15
to Masa, 日本Androidの会
たぶんですね。screenshotと、IMEからの文字入力を考えないならば、adbいらない。Runtimeクラスだけでいける。

以下のような感じ
Runtime r = Runtime.getRuntime();
Process process = r.exec("/system/bin/sh");// pathは端末依存
PrintWriter pwriter = new PrintWriter(process.getOutputStream());
InputStream input = new BufferedInputStream(process.getInputStream();
InputStream error = new BufferedInputStream(process.getErrorStream();

pwriter.println("input keyevent 82 ");

// 別スレットで、input と、error を出力する的な感じ

2015年7月31日 6:28 Masa <heathphy...@gmail.com>:

河村潔広

unread,
Jul 30, 2015, 11:29:34 PM7/30/15
to Masa, 日本Androidの会
僕のNexus7はこれで、Inputイベントを送れたよ!!

2015年7月31日 12:12 河村潔広 <kyor...@gmail.com>:

Masa

unread,
Aug 2, 2015, 8:21:11 PM8/2/15
to 日本Androidの会
shinm様 ありがとうございます。
参考にしたサイトからの切り貼りなので以下のようにしています。

        String[] commands = {"adb","shell","input","keyevent","3"};

        StringBuffer sBuffer = new StringBuffer();
        ProcessBuilder processBuilder = new ProcessBuilder(command);
 
        try {
            Process proc = processBuilder.start();
            InputStream iStream = proc.getInputStream();
            InputStreamReader isReader = new InputStreamReader(iStream);
            BufferedReader bufferedReader = new BufferedReader(isReader);

adbを使っているのは参考にしたサイトでadb shell input ・・・という使い方をされていたので
必要な物なのかと思っていました。

Masa

unread,
Aug 4, 2015, 1:43:38 AM8/4/15
to 日本Androidの会
Kyorohiro様 何度もありがとうございます。

色々と試してみたのですが動きません。
単純にボタン一つ配置して、それを押したらHomeボタンが押されたようにしようと
MainActivityに以下のように書いたのですが、ボタンを押しても無反応でした。
ManifestにINJECT_EVENTSは入れています。

            public void onClick(View v) {
                Runtime r = Runtime.getRuntime();
                Process process = null;
                try {
                    process = r.exec("/system/bin/sh");   //パスは同じでした
                } catch (IOException e) {
                    e.printStackTrace();
                }
                PrintWriter pwriter = new PrintWriter(process.getOutputStream());
                InputStream input = new BufferedInputStream(process.getInputStream());
                InputStream error = new BufferedInputStream(process.getErrorStream());
                pwriter.println("input keyevent 3");    //HOME_KEY
            }

Nexus5のほか、Nexus6, Xperia ZL2(ともに非rooted)もボタン無反応でした。
デバッグでも特にエラー等は出てなさそうなのですが、あまり深堀りできるスキルが無く・・・
何かが足りない?

河村潔広

unread,
Aug 4, 2015, 1:51:15 AM8/4/15
to android-g...@googlegroups.com
Input key event /n といった感じで、改行を追加してください。

2015年8月4日火曜日、Masa<heathphy...@gmail.com>さんは書きました:
--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。


--

Masa

unread,
Aug 5, 2015, 2:34:49 PM8/5/15
to 日本Androidの会
改行コード追加しましたが、相変わらず反応ありません・・・
(そもそも println は改行含むコマンドのはず???)

Nexus7があったのでトライしてみましたが、やはり反応ありません。

今のところ自分のプログラムではKEY_EVENTも送れていないのですが、
input tap x y のようなイベントもアプリから指示できるのでしょうか。

Masa

unread,
Aug 5, 2015, 5:26:49 PM8/5/15
to 日本Androidの会
ちなみにこれをするには rooted はmustでしょうか。

河村潔広

unread,
Aug 5, 2015, 6:46:43 PM8/5/15
to 日本Androidの会
rootedの必要がなかった気がするけど、自信はない。

Shell Terminal Emulator

とかで、試してみて、うまく動作するならばイケるんじゃない。


2015年8月6日 6:26 Masa <heathphy...@gmail.com>:
ちなみにこれをするには rooted はmustでしょうか。

--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

河村潔広

unread,
Aug 5, 2015, 6:47:16 PM8/5/15
to 日本Androidの会
> 改行コード追加しましたが、相変わらず反応ありません・・・
> (そもそも println は改行含むコマンドのはず???)
すまん、確かに。その通り。

2015年8月6日 3:34 Masa <heathphy...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

Masa

unread,
Aug 6, 2015, 10:56:56 PM8/6/15
to 日本Androidの会
以下の記述で自アプリ内であれば指定の(x,y)をタップできていました。

         public void onClick(View v) {
                Runtime r = Runtime.getRuntime();
                Process process = null;
                try {
                    process = r.exec("input tap x y");
                } catch (IOException e) {
                    e.printStackTrace();
                }
ただ、HOMEなどのkeyevent や自アプリ外に対する操作(notificationを引き出す等)は反応しません。

                    process = r.exec("/system/bin/sh");
にすると出力を取得するところで固まってしまいました。

                    process = r.exec("adb shell");
でadbに入ろうとすると、"ADB server didn't ACK"が出力されます。
(adbを自身に接続した設定とした場合でも、です)

Terminal Emulator等のアプリはどうやって自アプリ以外の領域に届くイベントを発行しているのでしょう・・・

河村潔広

unread,
Aug 6, 2015, 11:08:25 PM8/6/15
to 日本Androidの会
input コマンドは、最前面のアプリに対して、キーイベント、タッチイベントとかを送るものだと思います。
Terminal Emulator も同じだと思いますよ。


2015年8月7日 11:56 Masa <heathphy...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

Masa

unread,
Aug 7, 2015, 1:38:50 PM8/7/15
to 日本Androidの会
Terminal Emulator上で adb shell input keyevent 3 やinput swipe 100 10 100 500 等を入力すると
ホーム画面に切り替わったり、notification を引き出したりすることができます。

自アプリで入力テキスト"adb shell input swipe 100 10 100 500"を受け取って、
adbに接続して(今の自分のアプリでは"ADB server didn't ACK"と返ってくるのに)
debugでのinputを実行するという方法が何かしらある、ということだと思ったのです。

Terminal Emulatorもadbに接続しないとinputコマンドを自アプリ外に送ることはできないので
adbに接続するところをクリアできれば目的が達成できそうなところまで来ている気がします。

Masa

unread,
Aug 7, 2015, 8:37:22 PM8/7/15
to 日本Androidの会
解決しました!!

・permission "INTERNET" を記載   ・・・tcpipでadbに繋ぐのにこれが足りなかったようです(&android.permissionを大文字で書いていて嵌ってました)
・adbをループバックで自身に接続
・Runtimeで ”adb shell input ~” を送る
・ということでroot権も不要

これで自アプリ外に対してもdebug用inputを送ることが出来ました。
解けてみると複雑でも難解でも無く非常にシンプルな方法なのに、なかなか辿り着けないものですね・・・

皆様、色々とアドバイスありがとうございました!
特にKyorohiro様には何度もアドバイス頂きまして大変助かりました。

今回の件でRuntimeの使い方とかLinuxのinputとadbでのinputの違いもよく分かりましたし
ループバックでadb接続する危なさも。
Reply all
Reply to author
Forward
0 new messages