防止状态栏扩展

时间:2011-09-17 20:57:18

标签: android statusbar lockscreen

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

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

8 个答案:

答案 0 :(得分:17)

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

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

操纵系统状态栏EXPAND_STATUS_BARSTATUS_BAR有两种权限。前者可以由任何应用程序请求,但后者保留给使用平台签名(系统应用程序,而不是第三方)签名的应用程序。 可以扩展/折叠系统状态栏(请参阅"How to open or expand status bar through intent?"),但请注意,因为StatusBarManager类不是SDK的一部分,所以需要进行反射。如果没有上述STATUS_BAR权限,应用程序将无法访问Android拨号程序用于阻止状态栏扩展的禁用方法。

来源:个人经历: - )

答案 1 :(得分:16)

实际上,您可以阻止状态栏展开,而无需拨打电话。见this link。这会将窗口绘制为状态栏的高度并消耗所有触摸事件。

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

答案 2 :(得分:13)

首先,如果您的应用未通过手机的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("collapse");
                collapse .setAccessible(true);
                collapse .invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}

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

答案 3 :(得分: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);

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

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

答案 4 :(得分:8)

我尝试了 GrantLand PoOk 提到的解决方案,但两者都不适用于我的情况。虽然,另一个解决方案Clear/Hide Recent Tasks List为我做了诀窍。我正在编写一个启动器应用程序,我必须禁用它最近的应用程序菜单,以便用户无法从中打开锁定的应用程序。此外,我不得不防止通知栏扩展,这个技巧让我实现了两者。在您的活动中覆盖 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);
    }
}

答案 5 :(得分:3)

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

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

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

如果用户确实设置了安全锁屏,则应用程序将显示状态栏,但不允许与其进行交互。这是因为手机实际上仍处于锁定状态,只有您的活动才能在用户解锁手机之前运行。无论如何还要关闭你的应用程序将打开标准的安全锁屏。所有这些都是非常需要的,因为您不必花费所有时间编写安全功能,而您无法保证这些功能与库存功能一样安全。

如果您真的不希望用户能够与状态栏进行交互,那么您可以忽略标记FLAG_DISMISS_KEYGUARD。就在你即将解锁手机之前,设置了我在第一个区块中显示的标志。我不知道这最后一部分是否有效,但值得一试。

希望有所帮助

答案 6 :(得分:1)

抱歉,但不起作用。使用FLAG_LAYOUT_IN_SCREEN可以阻止您捕捉任何触摸事件。

而BTW: 要向窗口添加视图,请使用窗口管理器:

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

答案 7 :(得分:-3)

requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);