androidandroid-notification-bar

Disable the notification panel from being pulled down


I am working on a lockscreen app and I need to disable the ability to pull down the notification/status bar at the top of the screen. There is an app called Holo Locker and what this app does is when the user pulls down from the top of the screen, it just sets the bar back up to the top of the screen and making it impossible to pull the drawer down.

I have no idea where to start. Any help would be great! Thanks!


Solution

  • This is possible using reflection. There are plenty of problems though.

    There's no way to check if the notification panel is open, or opening. So, we'll have to rely on Activity#onWindowFocusChanged(boolean). And this is where the problems begin.

    What the method does:

    public void onWindowFocusChanged (boolean hasFocus)

    Called when the current Window of the activity gains or loses focus. This is the best indicator of whether this activity is visible to the user.

    So, we'll have to figure out a way to distinguish between focus-loss due to showing of notification panel, and focus-loss because of other events.

    Some events that will trigger onWindowFocusChanged(boolean):

    Your activity may not have to deal with all of these issues. The following example handles a subset of them:

    Firstly, you need the EXPAND_STATUS_BAR permission:

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

    Next, declare these class-scope variable in your activity:

    // To keep track of activity's window focus
    boolean currentFocus;
    
    // To keep track of activity's foreground/background status
    boolean isPaused;
    
    Handler collapseNotificationHandler;
    

    Override onWindowFocusChanged(boolean):

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
    
        currentFocus = hasFocus;
    
        if (!hasFocus) {
    
            // Method that handles loss of window focus
            collapseNow();
        }
    }
    

    Define collapseNow():

    public void collapseNow() {
    
        // Initialize 'collapseNotificationHandler'
        if (collapseNotificationHandler == null) {
            collapseNotificationHandler = new Handler();
        }
    
        // If window focus has been lost && activity is not in a paused state
        // Its a valid check because showing of notification panel
        // steals the focus from current activity's window, but does not 
        // 'pause' the activity
        if (!currentFocus && !isPaused) {
    
            // Post a Runnable with some delay - currently set to 300 ms
            collapseNotificationHandler.postDelayed(new Runnable() {
    
                @Override
                public void run() {
    
                    // Use reflection to trigger a method from 'StatusBarManager'                
    
                    Object statusBarService = getSystemService("statusbar");
                    Class<?> statusBarManager = null;
    
                    try {
                        statusBarManager = Class.forName("android.app.StatusBarManager");
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
    
                    Method collapseStatusBar = null;
    
                    try {
    
                        // Prior to API 17, the method to call is 'collapse()'
                        // API 17 onwards, the method to call is `collapsePanels()`
    
                        if (Build.VERSION.SDK_INT > 16) {
                            collapseStatusBar = statusBarManager .getMethod("collapsePanels");
                        } else {
                            collapseStatusBar = statusBarManager .getMethod("collapse");
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }
    
                    collapseStatusBar.setAccessible(true);
    
                    try {
                        collapseStatusBar.invoke(statusBarService);
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
    
                    // Check if the window focus has been returned
                    // If it hasn't been returned, post this Runnable again
                    // Currently, the delay is 100 ms. You can change this
                    // value to suit your needs.
                    if (!currentFocus && !isPaused) {
                        collapseNotificationHandler.postDelayed(this, 100L);
                    }
    
                }
            }, 300L);
        }   
    }
    

    Handle activity's onPause() and onResume():

    @Override
    protected void onPause() {
        super.onPause();
    
        // Activity's been paused      
        isPaused = true;
    }
    
    @Override
    protected void onResume() {
        super.onResume();
    
        // Activity's been resumed
        isPaused = false;
    }
    

    Hope this is close to what you are looking for.

    Note: The flicker that happens when you slide the notification bar and hold on to it is unfortunately unavoidable. Its appearance can however be controlled/improved using 'better' values for handler-delays. This is issue is also present in the Holo Locker app.