新换的手机,屏幕有点大,操作起来有点费劲,找了一些虚拟按键类的软件,都不是很简洁,最后想写个虚拟返回按钮。
Instrumentation inst=new Instrumentation(); inst.sendKeyDownUpSync(KeyCode);
这段代码在非UI线程调用可以达到返回键的效果,但是不能跨进程(怒!不能跨进程要你何用)。严格来讲不是不能,而是比较麻烦。
http://www.cnblogs.com/TerryBlog/archive/2012/06/07/2539866.html 这篇帖子看似给出方案。用ndk封装的方式忽略。第二种修改为系统进程的方式需要源码环,拿到公钥等,除了自己编译的rom,其他的rom不可能拿到这些。
还有一种方式是:
private void sendKeyEvent(int keyCode) { int eventCode = keyCode; long now = SystemClock.uptimeMillis(); try { KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0); KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0); (IWindowManager.Stub .asInterface(ServiceManager.getService("window"))) .injectInputEventNoWait(down); (IWindowManager.Stub .asInterface(ServiceManager.getService("window"))) .injectInputEventNoWait(up); } catch (RemoteException e) { Log.i(TAG, "DeadOjbectException"); } }
这种方式在1.6版本以后就被放弃了删掉了,新版系统源码中根本就没有这个类
最终的解决办法:
上述帖子三楼给出了模拟系统协议的方式。这种方式可以跨进程,但是需要root
大部分虚拟按键类软件都是这么做的。
这个开源项目就是一个很好的例子:国人开发的
https://code.google.com/p/assistivetouch/
提取其中关键类和代码 如下:
RootContext.java
package com.leon.assistivetouch.main.util; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import android.content.Context; /** * 类名 RootContext.java * 说明 获取root权限 * 创建日期 2012-8-21 * 作者 LiWenLong * Email [email protected] * 更新时间 $Date$ * 最后更新者 $Author$ */ public class RootContext { private static RootContext instance = null; private static Object mLock = new Object(); String mShell; OutputStream o; Process p; private RootContext(String cmd) throws Exception { this.mShell = cmd; init(); } public static RootContext getInstance() { if (instance != null) { return instance; } synchronized (mLock) { try { instance = new RootContext("su"); } catch (Exception e) { while (true) try { instance = new RootContext("/system/xbin/su"); } catch (Exception e2) { try { instance = new RootContext("/system/bin/su"); } catch (Exception e3) { e3.printStackTrace(); } } } return instance; } } private void init() throws Exception { if ((this.p != null) && (this.o != null)) { this.o.flush(); this.o.close(); this.p.destroy(); } this.p = Runtime.getRuntime().exec(this.mShell); this.o = this.p.getOutputStream(); system("LD_LIBRARY_PATH=/vendor/lib:/system/lib "); } private void system(String cmd) { try { this.o.write((cmd + "\n").getBytes("ASCII")); return; } catch (Exception e) { while (true) try { init(); } catch (Exception e1) { e1.printStackTrace(); } } } public void runCommand(String cmd) { system(cmd); } /** * 判断是否已经root了 * */ public static boolean hasRootAccess(Context ctx) { final StringBuilder res = new StringBuilder(); try { if (runCommandAsRoot(ctx, "exit 0", res) == 0) return true; } catch (Exception e) { } return false; } /** * 以root的权限运行命令 * */ public static int runCommandAsRoot(Context ctx, String script, StringBuilder res) { final File file = new File(ctx.getCacheDir(), "secopt.sh"); final ScriptRunner runner = new ScriptRunner(file, script, res); runner.start(); try { runner.join(40000); if (runner.isAlive()) { runner.interrupt(); runner.join(150); runner.destroy(); runner.join(50); } } catch (InterruptedException ex) { } return runner.exitcode; } private static final class ScriptRunner extends Thread { private final File file; private final String script; private final StringBuilder res; public int exitcode = -1; private Process exec; public ScriptRunner(File file, String script, StringBuilder res) { this.file = file; this.script = script; this.res = res; } @Override public void run() { try { file.createNewFile(); final String abspath = file.getAbsolutePath(); Runtime.getRuntime().exec("chmod 777 " + abspath).waitFor(); final OutputStreamWriter out = new OutputStreamWriter( new FileOutputStream(file)); if (new File("/system/bin/sh").exists()) { out.write("#!/system/bin/sh\n"); } out.write(script); if (!script.endsWith("\n")) out.write("\n"); out.write("exit\n"); out.flush(); out.close(); exec = Runtime.getRuntime().exec("su"); DataOutputStream os = new DataOutputStream(exec.getOutputStream()); os.writeBytes(abspath); os.flush(); os.close(); InputStreamReader r = new InputStreamReader( exec.getInputStream()); final char buf[] = new char[1024]; int read = 0; while ((read = r.read(buf)) != -1) { if (res != null) res.append(buf, 0, read); } r = new InputStreamReader(exec.getErrorStream()); read = 0; while ((read = r.read(buf)) != -1) { if (res != null) res.append(buf, 0, read); } if (exec != null) this.exitcode = exec.waitFor(); } catch (InterruptedException ex) { if (res != null) res.append("\nOperation timed-out"); } catch (Exception ex) { if (res != null) res.append("\n" + ex); } finally { destroy(); } } public synchronized void destroy() { if (exec != null) exec.destroy(); exec = null; } } }
模拟按键指令:
RootContext.getInstance().runCommand("input keyevent " + KeyEvent.KEYCODE_BACK);
ps:缺点,反应慢。想想这也是市面上找不到像样的虚拟按键类软件的原因吧,体验太差。
最后的最后,放弃了。凑合着用吧。