备注:
1.【项目的apk是跑在自己Android6.0主板
设备上,上层是拥有Root权限
的】
2.【本文中提到息屏
是指在BroadcastReceiver
中接收到ACTION_SCREEN_ON
的操作;
亮屏
是接收到Intent.ACTION_SCREEN_OFF
操作】;
业务需求
- 公司的设备是一个带显示屏
Android(6.0 Root)
板的智能终端,有人体感应头,现在需要在apk上层做逻辑是:感应到人就点亮屏(这个easy),默认2分钟后如果没感应到人就息屏- 先说说我的最终
息屏
解决方式是利用Runtime
调用Linux-shell
发送ADB命令"input keyevent 224"
模拟电源按键息屏;【项目的apk是跑在自己Android6.0主板设备上,拥有Root权限】
开工
- 先想到是直接用
PowerManager.WakeLock
的acquire()和release()配合一下就搞定了(当初就是这么天真),结果是点屏幕是没问题的,但是就是不能息屏; 本人是菜鸡直接就是百度了,结果网上就是一波
PowerManager应用反射goToSleep(long time)
;
如获至宝,然而goToSleep需要Requires signature permission
系统签名【Android权限等级见下表】,还是很折腾的,自己搞不定继续百度希望有大佬贴出实现代码;在网上逛一圈发现关于
PowerManager息屏
基本上都是讲理论,没有发现贴出来代码的,有些贴出来的可能是低版本系统上编译的吧,在我的AS上buildToolsVersion:”26.0.1”编译不过;后来看到用
DevicePolicyManager
实现的就是代码量有点大,而且还要申请系统管理权限
,有点烦但是在网上copy了一个demo,在设备上run一下功能是Ok的,于是学习一下API就开始往工程里塞了
- Android权限等级protectionLevel :
protectionLevel normal 任何应用都可以申请,在mainfest中直接添加的uses-permission,在安装应用时,不会直接提示给用户,点击全部才会展示 dangerous 任何应用都可以申请,在安装应用时,会直接提示给用户 signature 俩个相同的私钥签名 apk之间才可以申请的权限 signatureOrSystem 系统级别Signature :在/system/app下和声明该权限的apk使用相同的私钥签名的apk才可以申请
峰回路转
就在我这个码农不辞辛苦CV的时候,我技术老大(Android固件就是他搞的),跟我说:
调用DevicePolicyManagerAPI
去执行也是最终调用系统Service去灭屏
,和你在Terminal输入ADB命令input keyevent 26
模拟电源键息屏
是一样的;
听他一说瞬间发现自己好傻逼啊【apk拥有root权限
可以直接调用Runtime
调用Linux-shell
发送ADB
命令就可以啦】;
常见的模拟按键ADB命令
- reboot 重启
- input keyevent 26 电源键
- input keyevent 224 息屏
- input keyevent 223 亮屏
- input keyevent 82 菜单锁
- input keyevent 24 音量+键
- input keyevent 25 音量-键
- input keyevent 3 Home键
- input keyevent 4 返回键
- input keyevent 5 呼叫键
- input keyevent 6 挂断键
- ……
ADB命令解锁操作,先将手机连上ADB后,手机息屏并锁屏[密码]后 ,在Terminal 或cmd命令板中:
- 先输入:
input keyevent 223
命令 [亮屏]- 再输入:
input text ****
命令;[****
:开锁密码 ,可以实现亮屏自动解锁
]
最后的结果就是只需要一个Utils类利用Runtime
调用Linux-shell
发送命令"input keyevent 224"
模拟电源按键息屏就搞定了息屏的需求:
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();
//释放锁,以便2分钟后熄屏。
wakeLock.release();
}
}
在需要调用息屏的逻辑调用代码:
//在需要调用息屏的逻辑调用代码
boolean root = AndroidRootUtils.checkDeviceRoot();
if(root){
AndroidRootUtils.execRootCmd("input keyevent 224");
}
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;
}
}
最后特别说明:
我的代码是跑在root
过的设备上的,我的所有代码在设备上是没有任何问题的,并且已经在实际应用了;但是利用Runtime
调用Linux-shell
发送adb命令实现息屏以及其他功能需要结合自身的情况而定,思路可以借鉴,但需要自己验证,最早之前是用input keyevent 26
,模拟电源键
息屏的,自己查看了一下adb模拟按键命令后发现;Android中还专门有提供息屏亮屏的按键即224息屏和223亮屏
,于是就改用224替换原来是26实现息屏操作了