Android中apk中息屏、亮屏新思路

备注:

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实现息屏操作了

猜你喜欢

转载自blog.csdn.net/black_bird_cn/article/details/79717245