Android之禁用系统栏(StatusBar)

场景

手机管理软件的一部分:在某个时候需要输入自定义密码才能使用手机。这时候要禁用 Home 键,可以采取策略

  • AccessibilityService的onKeyEvent屏蔽 Home
  • 一个附件在WindowManager上的浮层

然后下一步是屏蔽用户用手势下拉系统栏(StatusBar)

目标

在限制模式下,禁止用户下拉显示状态栏从而进行其他操作

决策

全局窗口 - 失败

Activity全屏,这样确实可以遮挡住系统栏,但是却无法阻止下拉手势唤出它

另外,5.0的沉浸模式,感觉照样白扯,无法屏蔽

AccessibilityService方案 - 失败

首先,利用 AccessibilityService 的 onGesture 函数,这个要求手机进入 Touch Exploration ModeFLAG_REQUEST_TOUCH_EXPLORATION_MODE

经测试,这个确实可以截获各种手势,但是进入 Touch Exploration Mode onGesture 返回值没什么作用,无论返回什么结果,都会是一种现象:手势全部被截获,虽然无法拉出系统栏了,但是 完全触摸模式下滑动桌面,点击都没效果了。

后来逐渐解决其他问题

  • 锁屏界面也是触摸模式 - 检测进入锁屏后关闭触摸模式
  • 界面无法点击 - 检测 TYPE_VIEW_HOVER_ENTER 之后模拟点击
  • 输入法不能用(也是点击相关) - 没方案

知道我看到了一句话 when FLAG_REQUEST_TOUCH_EXPLORATION_MODE is being used there is a need to swipe with 2 fingers or double click and swipe 来自 AccessibilityService with FLAG_REQUEST_TOUCH_EXPLORATION_MODE cause device to stuck !!!,才开始后悔没啥没有早看文档 - Touch Exploration Mode 模式下,双击果然是单击,两个指头滑动果然他妈的能是手势有效果,自然也就可以滑下来系统栏了

后来检查一个 AccessibilityService 的 onKeyEvent 函数,大喜,然后大悲,这个可以截获键盘操作,但是对触摸操作无能为力

再后来,放弃了

悬浮窗口解决方案

    public static int getNotifyBarHeight(Context context) {
        int result = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
        WindowManager manager = ((WindowManager) getApplicationContext()
                .getSystemService(Context.WINDOW_SERVICE));

        WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
        localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
        localLayoutParams.gravity = Gravity.TOP;
        localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

        localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        localLayoutParams.height = getNotifyBarHeight(this);
        localLayoutParams.format = PixelFormat.TRANSPARENT;

        View view = new View(this);

        manager.addView(view, localLayoutParams);

注意加权限

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

在有些已经被改的烂七八糟的系统,例如MIUI上,需要安装APP后自己开启允许悬浮窗口选项

然后,世界清净了

localLayoutParams.flags设置的三个参数奥妙无穷,可以自己体会一下

另外,还有一种笨方案

还是利用 AccessibilityService, 检测到系统栏滑下来之后 赶紧关闭它, 例如模拟后退键,模拟Home键,但这个一个是会有系统栏闪动,一个是隐藏系统栏的方法比较难统一,所以也就放弃了

其他

参考还提供了一种很炫的方案

Disable:

service call activity 42 s16 com.android.systemui

Enable:

am startservice -n com.android.systemui/.SystemUIService

经过测试,4.*的机器上可用,又说5.0上不能用的,还是有即使4.0上也会导致桌面背景消失等奇怪的现象

参考

http://stackoverflow.com/questions/21371802/permanently-hide-android-status-bar

你可能感兴趣的:(Android之禁用系统栏(StatusBar))