有没有办法阻止用户滑动状态栏(展开)或向后折叠?
我正在尝试更换锁屏,这似乎是一项必备功能。有没有什么方法可以在不需要root权限的情况下做到这一点?
有没有办法阻止用户滑动状态栏(展开)或向后折叠?
我正在尝试更换锁屏,这似乎是一项必备功能。有没有什么方法可以在不需要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;
}
}
简短的回答:这是不可能的!
现在您是否有兴趣知道为什么这是不可能的:
操作系统状态栏有两种权限,EXPAND_STATUS_BAR和STATUS_BAR。前者可以由任何应用程序请求,但后者保留给使用平台签名签名的应用程序(系统应用程序,而不是第三方)。可以展开/折叠系统状态栏(请参阅“如何通过意图打开或展开状态栏?”),但请注意,由于StatusBarManager类不是 SDK 的一部分,因此需要进行反射。没有上述 STATUS_BAR 权限的应用程序无法访问 Android 拨号器用来防止状态栏展开的 disable 方法。
资料来源:个人经验:-)
首先,如果您的应用没有通过手机的 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 方法来使用自己的自定义警报对话框,因为警报对话框有自己的焦点。
这实际上可以通过我偶然发现的一个小技巧来完成,但需要许可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);
这基本上将在状态栏上创建一个透明视图,该视图将接收所有触摸事件并阻止事件到达状态栏,从而防止它被扩展。
注意:此代码未经测试,但概念有效。
我尝试了GrantLand和PoOk提到的解决方案,但在我的情况下都不起作用。不过,另一种解决方案清除/隐藏最近的任务列表对我有用。我正在编写一个启动器应用程序,我必须为此禁用最近的应用程序菜单,以便用户无法从中打开锁定的应用程序。此外,我必须防止通知栏扩展,这个技巧让我实现了两者。在您的活动中覆盖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);
}
如果用户没有设置安全锁屏,应用程序会让用户拉下状态栏并打开活动,但这并不重要,因为用户显然不想要安全屏幕。
如果用户确实设置了安全锁,则应用程序将显示状态栏,但不允许与之交互。这是因为手机实际上仍处于锁定状态,并且在用户解锁手机之前,仅允许您的活动进行操作。无论如何关闭您的应用程序也会打开标准的安全锁屏。所有这一切都是非常可取的,因为您不必花费所有时间编写安全功能,而您不能保证这些功能与现有功能一样安全。
如果您真的不希望用户能够与状态栏进行交互,也许您可以省略 flagFLAG_DISMISS_KEYGUARD
调用。然后就在你要解锁手机之前设置标志,就像我在第一个块中显示的那样。我不知道这最后一部分是否有效,但值得一试。
希望有帮助
对不起,但它不起作用。usingFLAG_LAYOUT_IN_SCREEN
可以防止您捕获任何触摸事件。
顺便说一句:要向窗口添加视图,请使用窗口管理器:
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);