备注:
1.【项目的apk是跑在自己Android6.0主板设备上,上层是拥有Root权限的】;
2.【本次博客提到息屏/锁屏是指在BroadcastReceiver中接收到ACTION_SCREEN_ON的操作;亮屏/解锁是接收到Intent.ACTION_SCREEN_OFF操作】
;
业务需求
- 公司的一个设备是一个带显示屏
Android(6.0 Root)
板的智能终端,有人体感应头,现在需要在apk上层做逻辑是感应到人就点亮屏(这个easy),默认2分钟后如果没感应到人就息屏- 先说说我的最终
息屏
解决方式是Runtime
调用Linux-shell
发送命令"input keyevent 26"
模拟电源按键息屏;【项目的apk是跑在自己Android6.0主板设备上,上层是拥有Root权限的】
开工
- 先想到是直接用
PowerManager.WakeLock
的acquire()和release()配合一下就搞定了(当初就是这天真),结果是点屏幕是没问题的,但是就是不能息屏; 本人是菜鸡直接就是百度了,结果网上就是一波
PowerManager应用反射goToSleep(long time)
;如获至宝,然而goToSleep需要Requires signature permission
系统签名,还是很折腾的,自己搞不定继续百度希望有大佬贴出实现代码;在网上逛一圈发现关于
PowerManager息屏
基本上都是将理论,没有发现贴出来代码的,有些贴出来的可能是低版本系统上编译的吧,在我的AS上也是不能编译通过;后来看到用
DevicePolicyManager
实现的就是代码量有点大,而且还要申请系统管理权限,有点烦但是在网上copy出一个demo,在设备上run一下功能是Ok的于是学习一下API就开始往工程里塞了
- **
峰回路转
就在码农不辞辛苦的CV的时候,我技术老大(Android固件就是他搞的),跟我说你样去调用API去执行也是最终调用系统Service去灭屏,就是和ADB命令input keyevent 26模拟电源键息屏是一样的
;听他一说瞬间发现自己好傻逼啊(系统是roo
t过的可以直接调用Runtime调用Linux-shell发送ADB命令就可以啦);
#常见的模拟按键ADB命令
input keyevent 26 电源键
- input keyevent 24 音量+键
- input keyevent 25 音量-键
- input keyevent 3 Home键
- input keyevent 4 返回键
- input keyevent 5 呼叫键
- input keyevent 6 挂断键
- input keyevent 19 导航↑键
- input keyevent 20 导航↓键
- input keyevent 21 导航←键
- input keyevent 22 导航→键
- ……
部分命令记不清参考:adb shell 模拟按键,触摸事件
最后的结果就是只需要一个Utils类利用Runtime
调用Linux-shell
发送命令"input keyevent 26"
模拟电源按键息屏就搞定了息屏的需求:
Utils类:Android Root根权限的检查获取类(项目里有串口通信,所以就修改几行代码的事情了,成功的躲过了DevicePolicyManager中臃肿的代码量和授权)
于是简单修改了一下代码工具类贴出我的代码: 【需要注意的是在我的项目里apk是跑在自己的设备上,固件是自己定制(只是修改一些标签),系统也root过的下面代码在我的环境是正常的,那位小伙伴参考需要根据自己apk运行环境】
亮屏逻辑代码:
//亮屏逻辑代码
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
public void openScreenOn() {
if (powerManager == null) {
powerManager = (PowerManager) AppApplication.getApplicationContexts().getSystemService(Context.POWER_SERVICE);
}
if (wakeLock == null) {
wakeLock = powerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
}
boolean ifOpen = powerManager.isScreenOn();
if (!ifOpen) {
//屏幕会持续点亮
wakeLock.acquire();
//释放锁,屏幕熄灭。
wakeLock.release();
}
}
在需要调用息屏的逻辑调用代码:
//在需要调用息屏的逻辑调用代码
boolean root = AndroidRootUtils.checkDeviceRoot();
if(root){
AndroidRootUtils.execRootCmd("input keyevent 26");
}
Android Root根权限工具类:
//AndroidRootUtils Root根权限工具类
public class AndroidRootUtils {
/** * * 判断机器Android是否已经root,即是否获取root权限 */
public static boolean checkDeviceRoot() {
boolean resualt = false;
int ret = execRootCmdSilent("echo test"); // 通过执行测试命令来检测
if (ret != -1) {
Log.i("checkDeviceRoot", "this Device have root!");
resualt = true;
} else {
resualt = false;
Log.i("checkDeviceRoot", "this Device not root!");
}
return resualt;
}
/** * 执行命令并且输出结果 */
public static String execRootCmd(String cmd) {
String result = "";
DataOutputStream dos = null;
DataInputStream dis = null;
try {
Process p = Runtime.getRuntime().exec("su");// 经过Root处理的android系统即有su命令
dos = new DataOutputStream(p.getOutputStream());
dis = new DataInputStream(p.getInputStream());
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
String line = null;
while ((line = dis.readLine()) != null) {
result += line;
}
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
/** * 执行命令但不关注结果输出 */
public static int execRootCmdSilent(String cmd) {
int result = -1;
DataOutputStream dos = null;
try {
Process p = Runtime.getRuntime().exec("su");
dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
p.waitFor();
result = p.exitValue();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}