防止状态栏扩展

无论如何阻止用户滑动状态栏(展开)或折叠?

我尝试了一个锁屏更换,似乎是一个必须具备的function。 有没有可能的方式来做到这一点,而不需要root权限?

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

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

有两个操作系统状态栏的权限EXPAND_STATUS_BAR和STATUS_BAR 。 前者可以由任何应用程序请求,但后者是为使用平台签名(系统应用程序,而不是第三方)签名的应用程序保留的。 可以展开/折叠系统状态栏(请参阅“如何通过意向打开或展开状态栏?” ),但请注意reflection是必需的,因为StatusBarManager类不是SDK的一部分。 如果没有上述STATUS_BAR权限,应用程序将无法访问Android拨号程序用来阻止状态栏展开的disable方法。

来源:个人经历:-)

首先,如果您的应用程序没有通过电话的ROMauthentication,那么修改状态栏是不可能的。如果您尝试修改它,您会得到一个安全例外。

更新 :在新的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("collapse"); collapse .setAccessible(true); collapse .invoke(service); } } catch(Exception ex) { } } 

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

这实际上可以通过我不小心发现的一点点黑客来完成,但是需要权限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); 

这将基本上创build一个透明的状态栏视图,将接收所有的触摸事件,并阻止事件到达状态栏,从而防止扩大。

注意:这个代码是未经testing的,但是这个概念起作用。

实际上,您可以防止状态栏扩展,而不需要根植电话。 看到这个链接 。 这绘制了一个窗口的状态栏的高度,并消耗所有的触摸事件。

在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; } } 

我尝试了GrantLandPoOk提到的解决scheme,但两者都不适用于我的情况。 虽然, 清除/隐藏近期任务列表的另一个解决scheme为我做了诡计。 我正在写一个启动应用程序,我不得不禁用最近的应用程序菜单,所以用户无法打开一个locking的应用程序。 此外,我不得不防止通知栏扩展,这个伎俩使我实现了两个。 在你的活动中覆盖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); } } 

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

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

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

如果用户确实设置了安全锁屏,那么应用程序将显示状态栏,但不允许与其进行交互。 这是因为手机仍处于locking状态,只有您的活动被允许运行,直到用户解锁手机。 另外closures你的应用程序将打开标准的安全锁屏。 所有这一切都是非常可取的,因为您不必花费所有时间编写安全function,而不能保证与安全function一样安全。

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

希望有所帮助

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

顺便说一句:要添加一个视图窗口使用窗口pipe理器:

 WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE); winMgr.addView(disableStatusBar, handleParams); 
 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);