防止状态栏扩展

Ye *_*Min 21 android statusbar lockscreen

反正是否阻止用户滑动状态栏(展开)或折叠回来?

我正在尝试更换锁屏,看起来它是必备功能.有没有可能的方法来做到这一点而不需要root权限?

Kri*_*lsh 18

实际上,您可以阻止状态栏扩展,而无需root电话.看到这个链接.这会将窗口绘制为状态栏的高度并消耗所有触摸事件.

在onCreate()之后调用以下代码.

public static void preventStatusBarExpansion(Context context) {
    WindowManager manager = ((WindowManager) context.getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));

    Activity activity = (Activity)context;
    WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
    localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
    localLayoutParams.gravity = Gravity.TOP;
    localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|

    // this is to enable the notification to recieve touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

    // Draws over status bar
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
    //https://stackoverflow.com/questions/1016896/get-screen-dimensions-in-pixels
    int resId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
    int result = 0;
    if (resId > 0) {
        result = activity.getResources().getDimensionPixelSize(resId);
    }

    localLayoutParams.height = result;

    localLayoutParams.format = PixelFormat.TRANSPARENT;

    customViewGroup view = new customViewGroup(context);

    manager.addView(view, localLayoutParams);
}

public static class customViewGroup extends ViewGroup {

    public customViewGroup(Context context) {
        super(context);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.v("customViewGroup", "**********Intercepted");
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案效果很好,但将目标sdk级别从23更改为26后,出现错误“ android.view.WindowManager $ BadTokenException:无法添加窗口android.view.ViewRootImpl$W@632ab9c-权限被拒绝对于窗口类型2010”。该应用程序已经具有“ <uses-permission android:name =“ android.permission.SYSTEM_ALERT_WINDOW” />“有什么想法怎么解决? (3认同)

Tom*_*Tom 17

简短的回答:这是不可能的!

你现在应该有兴趣知道为什么这是不可能的:

操作系统状态栏EXPAND_STATUS_BARSTATUS_BAR有两种权限.前者可以由任何应用程序请求,但后者保留给使用平台签名(系统应用程序,而不是第三方)签名的应用程序.这是可能的展开/折叠系统状态栏(请参阅"如何打开或意图通过拓展状态栏?"),但要注意,反射必需的,因为StatusBarManager类不是SDK的一部分.如果没有上述STATUS_BAR权限,应用程序将无法访问禁用方法(Android拨号程序用于阻止状态栏展开).

资料来源:个人经历:-)


PoO*_*oOk 15

首先,如果您的应用未通过手机的rom认证签名,则无法修改状态栏,如果您尝试修改它,您将获得安全例外.

更新:在新API中,方法是"collapsePanels"而不是"collapse".

我经过几个小时的工作后找到的唯一方法是覆盖活动的"onWindowFocusChanged"方法,当它失去焦点时(可能用户触摸了通知栏),强行折叠StatusBar,这里是代码(在Defy + 2.3.5上工作).

您需要在清单上声明以下权限:

 <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/> 
Run Code Online (Sandbox Code Playgroud)

并覆盖以下方法:

public void onWindowFocusChanged(boolean hasFocus)
{
        try
        {
           if(!hasFocus)
           {
                Object service  = getSystemService("statusbar");
                Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusbarManager.getMethod("collapse");
                collapse .setAccessible(true);
                collapse .invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}
Run Code Online (Sandbox Code Playgroud)

更新:您必须通过覆盖它们的onWindowFocusChanged方法来使用您自己的自定义警报对话框,因为警报对话框有自己的焦点.


Gra*_*hew 13

这实际上可以通过我意外发现的一个小黑客来完成,但需要获得许可android.permission.SYSTEM_ALERT_WINDOW:

您所做的是使用覆盖状态栏的某些参数将状态栏的确切大小直接添加到WindowManager,并阻止其接收触摸事件:

View disableStatusBarView = new View(context);

WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.FILL_PARENT,
    <height of the status bar>,
    // This allows the view to be displayed over the status bar
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    // this is to keep button presses going to the background window
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
    // this is to enable the notification to recieve touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
    // Draws over status bar
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
    PixelFormat.TRANSLUCENT);

handleParams.gravity = Gravity.TOP;
context.getWindow().addView(disableStatusBarView, handleParams);
Run Code Online (Sandbox Code Playgroud)

这将基本上在状态栏上创建一个透明视图,该视图将接收所有触摸事件并阻止事件到达状态栏,从而阻止其展开.

注意:此代码未经测试,但概念有效.

  • 这可行,我可以确认一下.通过一些调整,调用系统资源来检索确切的高度,默认回退这个工作就像一个魅力. (2认同)
  • 你们可以放一些工作代码片段吗?谢谢! (2认同)

Abd*_*man 8

我尝试了GrantLandPoOk提到的解决方案,但两者都不适用于我的情况.虽然,另一个解决方案清除/隐藏最近的任务列表为我做了伎俩.我正在编写一个启动器应用程序,我不得不禁用最近的应用程序菜单,因此用户无法从中打开锁定的应用程序.此外,我不得不防止通知栏扩展,这个技巧让我实现了两者.在您的活动中覆盖OnWindowFocusChanged方法,并检查这是否是您想要的.

public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

        Log.d("Focus debug", "Focus changed !");

    if(!hasFocus) {
        Log.d("Focus debug", "Lost focus !");

        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        sendBroadcast(closeDialog);
    }
}
Run Code Online (Sandbox Code Playgroud)


Bas*_*der -4

requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
Run Code Online (Sandbox Code Playgroud)