新换的手机,屏幕有点大,操作起来有点费劲,找了一些虚拟按键类的软件,都不是很简洁,最后想写个虚拟返回按钮。
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 lendylongli@gmail.com
* 更新时间 $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:缺点,反应慢。想想这也是市面上找不到像样的虚拟按键类软件的原因吧,体验太差。
最后的最后,放弃了。凑合着用吧。