防止状态栏扩展

发布于 2024-12-05 04:02:11 字数 92 浏览 3 评论 0原文

是否有办法防止用户滑动状态栏(展开)或向后折叠?

我正在尝试更换锁屏,似乎这是一个必备功能。有没有什么方法可以在不需要 root 权限的情况下做到这一点?

Is there anyway to prevent users from sliding the status bar (expand) or collapsing back?

I'm trying out a lockscreen replacement and seems like it's a must-have feature. Is there any possible way to do it without requiring root privileges?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

救赎№ 2024-12-12 04:02:12

实际上,您可以防止状态栏展开,而无需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;
    }
}

You can actually prevent the status bar from expanding, without rooting phone. See this link. This draws a window the height of the status bar and consumes all touch events.

Call the following code just after 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;
    }
}
作死小能手 2024-12-12 04:02:12

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

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

有两种操作系统状态栏的权限, EXPAND_STATUS_BARSTATUS_BAR。前者可以被任何应用程序请求,但后者是为使用平台签名的应用程序(系统应用程序,而不是第三方)保留的。 可以展开/折叠系统状态栏(请参阅“如何通过intent打开或展开状态栏?”),但注意需要反射,因为StatusBarManager 类不是 SDK 的一部分。 Android 拨号器使用禁用方法来防止状态栏展开,没有上述 STATUS_BAR 权限的应用程序无法访问该方法。

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

Short answer: this is impossible!

Now should you be interested to know why this is impossible:

There are two permissions for manipulating the system status bar, EXPAND_STATUS_BAR and STATUS_BAR. The former can be requested by any application, but the later is reserved for applications signed with the platform signature (system applications, not third-party). It is possible to expand/ collapse the system status bar (see "How to open or expand status bar through intent?") but note that reflection is required because the StatusBarManager class is not part of the SDK. The disable method, which is used by the Android dialer to prevent the status bar from being expanded, cannot be accessed by an application without the aforementioned STATUS_BAR permission.

Sources: personal experience :-)

耳根太软 2024-12-12 04:02:12

首先,如果您的应用程序未使用经过手机 ROM 认证的签名,则无法修改状态栏,如果您尝试修改它,您将收到安全异常。

更新:在新 API 中,该方法是“collapsePanels”而不是“collapse”。

经过几个小时的工作后我发现的唯一方法是覆盖活动的“onWindowFocusChanged”方法,当它失去焦点时(可能用户触摸了通知栏),强制折叠 StatusBar,这里是代码(正在使用 Defy+ 2.3.5)。

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

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

并覆盖以下方法:

public void onWindowFocusChanged(boolean hasFocus)
{
        try
        {
           if(!hasFocus)
           {
                Object service  = getSystemService("statusbar");
                Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusbarManager.getMethod(Build.VERSION.SDK_INT > 16 ? "collapsePanels" : "collapse");
                collapse.setAccessible(true);
                collapse.invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}

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

First of all, it's impossible to modify the Status Bar if your app is not signed with the phone's rom certified, if you try to modify it you'll get an Security Exception.

Update: In new APIs the method is "collapsePanels" instead of "collapse".

The only way I've found after several hours of work is by overriding the "onWindowFocusChanged" method of the activity and when it loses the focus (maybe the user has touched the notifications bar), force to collapse the StatusBar, here is the code (working on a Defy+ 2.3.5).

You need to declare the following permission on the manifest:

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

And override the following method:

public void onWindowFocusChanged(boolean hasFocus)
{
        try
        {
           if(!hasFocus)
           {
                Object service  = getSystemService("statusbar");
                Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusbarManager.getMethod(Build.VERSION.SDK_INT > 16 ? "collapsePanels" : "collapse");
                collapse.setAccessible(true);
                collapse.invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}

Update: You will have to use your own custom Alert Dialog by overriding it their onWindowFocusChanged method too, because Alert Dialogs have their own focus.

过潦 2024-12-12 04:02:12

这实际上可以通过我偶然发现的一个小技巧来完成,但需要权限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);

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

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

This actually can be done via a little hack that I accidentally discovered, but requires the permission android.permission.SYSTEM_ALERT_WINDOW:

What you do is add a view the exact size of the status bar directly to the WindowManager with the certain parameters that covers the status bar and prevents it from receiving touch events:

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);

This will basically create a transparent view over the status bar that will receive all the touch events and block the events from reaching the status bar and therefore prevents it from being expanded.

NOTE: This code is untested, but the concept works.

潜移默化 2024-12-12 04:02:12

我尝试了 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);
    }
}

I tried the solutions mentioned by GrantLand and PoOk but both didn't work in my case. Though, Another solution Clear/Hide Recent Tasks List did the trick for me. I am writing a launcher app for which I had to disable a recent applications menu so user cannot open a locked app from it. Also, I had to prevent against notification bar expansion and this trick made me achieve both. Override OnWindowFocusChanged method in your activity and check if this is what u wanted.

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);
    }
}
燕归巢 2024-12-12 04:02:12

对于锁屏,为什么不在主要活动中使用以下内容:

@Override
public void onAttachedToWindow() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

如果用户没有设置安全锁屏,应用程序将允许用户向下拉状态栏并打开活动,但这并不重要,因为无论如何,用户显然不想要安全的屏幕。

如果用户确实设置了安全锁,则应用程序将显示状态栏,但不允许与其交互。这是因为手机实际上仍然处于锁定状态,只有您的活动才允许操作,直到用户解锁手机。无论如何关闭您的应用程序都会打开标准的安全锁屏。所有这些都是非常理想的,因为您不必花费所有时间来编码您无法保证与库存一样安全的安全功能。

如果您确实不希望用户能够与状态栏交互,也许您可​​以省略标志 FLAG_DISMISS_KEYGUARD 调用。然后,在您即将解锁手机之前,请设置标志,就像我在第一个块中所示的那样。我不知道最后一部分是否有效,但值得一试。

希望有帮助

For a lockscreen Why don't you just use the following in your main activity:

@Override
public void onAttachedToWindow() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

If the user doesn't have a secure lockscreen set the app will let the user pull the status bar down and open activities but that doesn't matter as the user obviously doesn't want a secure screen anyway.

If the user does have a secure locksreen set then the app will show the status bar but will not allow interactions with it. This is because the phone is still actually locked and only your activity is allowed to operate until the user unlocks the phone. Also closing your app in anyway will open the standard secure lockscreen. All this is highly desirable because you don't have to spend all that time coding secure features that you can't guarantee will be as secure as the stock ones.

If you really don't want the user to be able to interact with the status bar, maybe you can leave out the flag FLAG_DISMISS_KEYGUARD call. Then just before you are about to unlock the phone set the flag like I showed in the first block. I don't know if this last part works but it's worth a try.

Hope that helps

分開簡單 2024-12-12 04:02:12

抱歉,但它不起作用。使用 FLAG_LAYOUT_IN_SCREEN 会阻止您捕获任何触摸事件。

顺便说一句:
要将视图添加到窗口,请使用窗口管理器:

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 

Sorry but it does not work. using FLAG_LAYOUT_IN_SCREEN prevents you from catching any touch events.

And BTW:
to add a view to the window use the window manager:

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 
烟燃烟灭 2024-12-12 04:02:12

您可以做的是循环折叠状态栏,因此当用户尝试展开它时,它会自动折叠,这是代码,只需将其添加到您的 MainActivity.java 文件中:

    private Handler mHandler = new Handler();
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                @SuppressLint("WrongConstant") Object service = getSystemService("statusbar");
                Class<?> statusBarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusBarManager.getMethod(Build.VERSION.SDK_INT > 16 ? "collapsePanels" : "collapse");
                collapse.setAccessible(true);
                collapse.invoke(service);
            } catch (Exception ex) {
                // handle exception
            }
            mHandler.postDelayed(mRunnable, 100);
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        mHandler.postDelayed(mRunnable, 100);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mHandler.removeCallbacks(mRunnable);
    }

What you can do is collapse the status bar in a loop, so when user tries to expand it, it automatically will collapse, here is the code, just add it in your MainActivity.java file:

    private Handler mHandler = new Handler();
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                @SuppressLint("WrongConstant") Object service = getSystemService("statusbar");
                Class<?> statusBarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusBarManager.getMethod(Build.VERSION.SDK_INT > 16 ? "collapsePanels" : "collapse");
                collapse.setAccessible(true);
                collapse.invoke(service);
            } catch (Exception ex) {
                // handle exception
            }
            mHandler.postDelayed(mRunnable, 100);
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        mHandler.postDelayed(mRunnable, 100);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mHandler.removeCallbacks(mRunnable);
    }
め七分饶幸 2024-12-12 04:02:12
requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文