21

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

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

4

8 回答 8

20

您实际上可以防止状态栏扩展,而无需生根电话。请参阅此链接。这将绘制一个状态栏高度的窗口并消耗所有触摸事件。

在 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;
    }
}
于 2015-07-10T20:04:49.947 回答
18

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

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

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

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

于 2011-10-02T13:23:32.847 回答
15

首先,如果您的应用没有通过手机的 rom 认证签名,则无法修改状态栏,如果您尝试修改它,您将收到安全异常。

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

经过几个小时的工作,我发现的唯一方法是重写活动的“onWindowFocusChanged”方法,当它失去焦点时(可能用户已经触摸了通知栏),强制折叠状态栏,这里是代码(在 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 方法来使用自己的自定义警报对话框,因为警报对话框有自己的焦点。

于 2012-04-30T08:22:28.373 回答
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);

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

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

于 2011-10-03T04:20:27.017 回答
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);
    }
}
于 2014-02-19T07:23:06.407 回答
3

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

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

如果用户没有设置安全锁屏,应用程序会让用户拉下状态栏并打开活动,但这并不重要,因为用户显然不想要安全屏幕。

如果用户确实设置了安全锁,则应用程序将显示状态栏,但不允许与之交互。这是因为手机实际上仍处于锁定状态,并且在用户解锁手机之前,仅允许您的活动进行操作。无论如何关闭您的应用程序也会打开标准的安全锁屏。所有这一切都是非常可取的,因为您不必花费所有时间编写安全功能,而您不能保证这些功能与现有功能一样安全。

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

希望有帮助

于 2012-12-16T03:08:11.337 回答
1

对不起,但它不起作用。usingFLAG_LAYOUT_IN_SCREEN可以防止您捕获任何触摸事件。

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

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 
于 2011-12-24T16:03:57.847 回答
-4
requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
于 2011-09-17T21:01:09.147 回答