30

I am implementing a kiosk mode application and i have successfully made the application full-screen without status bar appearance post 4.3 but unable to hide status bar in 4.3 and 4.4 as status-bar appears when we swipe down at the top of the screen.

I have tried to make it full screen by

  • speciflying the full screen theme in manifest
  • setting window Flags ie setFlags
  • setSystemUiVisibility

Possible duplicate but no concrete solution found

Permanently hide Android Status Bar

Finally the thing i want is, how to hide status bar permanently in an activity?? in android 4.3,4.4,5,6versions

Community
  • 1
  • 1
Abhimaan
  • 1,893
  • 2
  • 19
  • 26

3 Answers3

86

We could not prevent the status appearing in full screen mode in kitkat devices, so made a hack which still suits the requirement ie block the status bar from expanding.

For that to work, the app was not made full screen. We put a overlay over status bar and consumed all input events. It prevented the status from expanding.

note:

  • customViewGroup is custom class which extends any layout(frame,relative layout etc) and consumes touch event.
  • to consume touch event override the onInterceptTouchEvent method of the view group and return true

Updated

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

customViewGroup implementation

Code :

WindowManager manager = ((WindowManager) getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));

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;
    localLayoutParams.height = (int) (50 * getResources()
            .getDisplayMetrics().scaledDensity);
    localLayoutParams.format = PixelFormat.TRANSPARENT;

    customViewGroup view = new customViewGroup(this);

    manager.addView(view, localLayoutParams);
Abhimaan
  • 1,893
  • 2
  • 19
  • 26
  • 1
    Absolutely the only thing that worked for me after 2 weeks trying. Completely blocks status bar expansion – MikeyB Aug 21 '14 at 13:23
  • 1
    Note: Needs to run – MikeyB Aug 21 '14 at 13:36
  • I am a Noob, can you give some more detail about the customViewGroup? – user1416682 Sep 20 '14 at 08:54
  • 2
    @user1416682 Here's a VERY basic customViewGroup that will get you started. [link](https://gist.github.com/sarme/7e4dc90e2478ade310e6) – sarme Sep 26 '14 at 15:17
  • Unfortunately this disables the status bar permanently (even when you quit the app!). Is there a way to do it only within the application? – longwalker Oct 16 '14 at 09:58
  • 1
    you can remove the view when you quit your application. so that should not be a problem – Abhimaan Oct 16 '14 at 12:53
  • 2
    @AbhimaanMadhav, I did not think of that :) Calling manager.removeView(view) was enough for me. BTW, can you apply this to disable the soft buttons as well? It is not working for me at the moment. – longwalker Oct 16 '14 at 13:19
  • what about softkeyboard ? {Back , home , recentapp button,..etc} – Menna-Allah Sami Feb 18 '15 at 13:12
  • @longwalker you cannot apply it for soft keyboards. But you can disable all the keys in the key boards. Please post a question in stack overflow and i would try to answer it with my limited knowledge. – Abhimaan Feb 20 '15 at 07:18
  • @Menna-AllahSami Post your question in stackoverflow and comment it as a link may be i can address your issue – Abhimaan Feb 20 '15 at 07:19
  • 1
    What if an app uses fullscreen mode with actionbar menu? This method will just overlap these controls making them not usable. – kechap Mar 05 '15 at 06:55
  • I have mentioned not to use full screen mode – Abhimaan Mar 05 '15 at 07:02
  • This solution worked for me and I am using full screen mode (no action bar, though). Running Lollipop on Nexus 7. – Kristy Welsh Jun 26 '15 at 15:07
  • where does the code section go? does it go into the customViewGroup's onInterceptTouchEvent? – Lothre1 Jul 13 '15 at 17:32
  • yes its intercepted by custom view group and the touch is blocked ie(the touch is consumed) – Abhimaan Jul 14 '15 at 06:45
  • 1
    @AbhimaanMadhav Any idea how can i disable the soft keys(Back, Home, Recent Apps) as well? – Dave Feb 10 '16 at 10:25
  • @Dave http://stackoverflow.com/questions/34224398/how-we-can-disable-navigation-soft-buttons-home-recent/35337882#35337882 – Abhimaan Feb 11 '16 at 11:19
  • `(int) (50 * getResources()` what is decision criteria for using 50? – dsharew Jun 01 '16 at 08:13
  • usually the status bar height is around 24dp selected 50dp so that it works on all devices and density. you can choose suitable height @DegenSharew – Abhimaan Jun 02 '16 at 14:17
  • Best solution so far – Ishan Fernando Dec 23 '16 at 10:51
  • 1
    Working like a charm in KitKat but not in Marshmallow where I get a permission issue: Unable to add window android.view.ViewRootImpl$W@d27eba5 -- permission denied for this window type – Michael Knight Oct 30 '17 at 07:17
  • Very good solution, but how is this view removed? Because I try to use manager.removeView (view) and manager.removeViewImmediate (view) and the status bar is still blocked or with the transparent layer on top Thanks – Sergio Antonio Snchez Camarero Oct 31 '17 at 15:44
  • @MichaelKnight if you want to achieve the same in 6.0+ devices you should check Settings.canDrawOverlays() before drawing. If the permission is not granted please as the user to grant it. please refer the below link for details https://developer.android.com/reference/android/Manifest.permission.html – Abhimaan Nov 02 '17 at 04:44
  • This one helped me.. after all the trail and error methods – other Tall guy Mar 27 '18 at 04:40
  • 2
    Does not work on Android 8.0 or Oreo devices any more. – Run Aug 08 '18 at 00:30
  • @QLocker can you elaborate on what does not work on oreo and above devices – Abhimaan Aug 08 '18 at 03:16
  • 3
    @Abhimaan On oreo+ devices, any user added window or view can not show above the status bar, the status bar can always be pulled down. – Run Aug 08 '18 at 03:46
  • 1
    @QLocker did you find any solution for Oreo+? – FDaumas Apr 17 '20 at 03:41
  • What if I have a EditText on top of the screen and that editText still need to receive touchEvent. – shadow_wxh Jul 14 '20 at 23:43
  • Ok this prevent the status bar from expanding but If I touch the top of the screen the status bar stll apear for about 5 sec or so,still need better way to solve this. – shadow_wxh Jul 15 '20 at 00:06
  • @shadow_wxh may be this https://developer.android.com/work/dpc/dedicated-devices/lock-task-mode might help. Since now most of devices are 5.0 and above. The answer might be out date on newer devices – Abhimaan Jul 15 '20 at 05:55
19

In Android M you have to get an extra permission for making overlays. android.permission.SYSTEM_ALERT_WINDOW is not enough! So I used the code from the answer of Abhimaan within disableStatusBar() and had to make an intent to open the right settings dialog. I also added removing view in onDestroy() in order to enable status bar when the app exits. I also reduced the overlay height to 40 as it seems to be enough. Code works with 5.1 and 6.0 here.

public static final int OVERLAY_PERMISSION_REQ_CODE = 4545;
protected CustomViewGroup blockingView = null;

@Override
protected void onDestroy() {

    super.onDestroy();

    if (blockingView!=null) {
        WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
        manager.removeView(blockingView);
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "Please give my app this permission!", Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
            } else {
                disableStatusBar();
            }
        }
        else {
            disableStatusBar();
        }
}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
        if (!Settings.canDrawOverlays(this)) {
            Toast.makeText(this, "User can access system settings without this permission!", Toast.LENGTH_SHORT).show();
        }
        else
        { disableStatusBar();
        }
    }
}

protected void disableStatusBar() {

    WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));

    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 receive touch events
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

            // Draws over status bar
            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
    localLayoutParams.height = (int) (40 * getResources().getDisplayMetrics().scaledDensity);
    localLayoutParams.format = PixelFormat.TRANSPARENT;

    blockingView = new CustomViewGroup(this);
    manager.addView(blockingView, localLayoutParams);
}
Alexey Ozerov
  • 1,398
  • 13
  • 23
  • (int) (40 * getResources() what is decision criteria for using 40? – dsharew Jun 01 '16 at 08:13
  • usually the status bar would be around 40 dp i believe – Abhimaan Dec 20 '16 at 06:20
  • 1
    Unfortunately none of the solutions have worked for me including this. In my Kiosk app, I can still pull down the status bar. My app is in pinned mode, which means the status bar is blank, but regardless, I can swipe it from top. I don't get it what type of pinning is this, why Android doesn't hide it permanently in pinning mode, when it is blank anyways. – zeeshan Feb 27 '17 at 17:33
  • This is the only solution that worked for me. Using this approach I was also able to block off the soft keys at the bottom. Thanks!!! – netsuite_insights May 24 '17 at 15:34
  • is it working with rooted devices?i have tried it on 5.1 Lollilop root device with no results... – tsiro Aug 26 '17 at 12:53
  • Yes, it should. Rooting usually doesn't break Android logics like this. – Alexey Ozerov Aug 27 '17 at 18:59
  • How remove this view?¿ Because with `manager.removeView(view)` and `manager.removeViewImmediate(view)` not work – Sergio Antonio Snchez Camarero Oct 31 '17 at 15:42
  • This should work like in the sample above with `manager.removeView(blockingView);` – Alexey Ozerov Oct 31 '17 at 17:58
  • The status bar height on the most devices is 24 or 25 dp. This would be sufficient in the code above. – Alexey Ozerov Nov 22 '17 at 10:06
  • Just note this way to request permission requires Android 6 (M), but special permission requirement is already in Android 4.4.4 - solution above will not work there. – Honza May 06 '18 at 21:41
  • 3
    it does not work in oreo please make for oreo support also – umesh shakya Sep 11 '18 at 09:35
  • 1
    @Honza: For Android 4.4 and 5 it's enough to put the permission in the Manifest file `` – Alexey Ozerov Sep 12 '18 at 10:05
  • @zeeshan did you find the solution because I am also using the same app but not able to restrict notification bar? – Ashish Jain Dec 18 '18 at 11:40
  • @AshishJain yes, I had found and implemented a solution for this. I just posted my code in a separate answer since it is lengthy and in comments it is not possible to post it. Its been a while and it was on Android M, so I cannot guarantee that it would work on later Android versions. – zeeshan Dec 18 '18 at 16:41
  • @zeeshan so is there any way to share that code either using pastie or other things? actually, I am trying to run code in oreo and need to check for below version. can we discuss a few things using chat room (personally) related to Kiosk app I need your help? – Ashish Jain Dec 19 '18 at 05:43
0

For a project I worked on I had found a solution for this but it took a long time. Various threads on Stackoverflow and elsewhere helped me to come up with it. It was a work around on Android M but it worked perfectly. As someone asked for it so I thought I should post it here if it can benefit anyone.

Now that its been a while, I don't remember all the details, but the CustomViewGroup is the class which overrides the main ViewGroup, and detects that a user has swiped from top to show the status bar. But we didn't want to show it, so the user's intercept was detected and any further action was ignored, i.e. Android OS won't get a signal to open the hidden status bar.

And then the methods to show and hide the status bar are also included which you can copy/paste as is in your code where you want to show/hide the status bar.

/**
 * This class creates the overlay on the status bar which stops it from expanding.
 */
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", "********** Status bar swipe intercepted");
        return true;
    }
}

public static void allowStatusBarExpansion(Context context) {
    CustomViewGroup view = new CustomViewGroup(context);
    WindowManager manager = ((WindowManager) context.getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));
    manager.removeView(view);
}

// Stop expansion of the status bar on swipe down.
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 receive touch events
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

            // Draws over status bar
            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
    //http://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);
}
zeeshan
  • 4,913
  • 1
  • 49
  • 58
  • I'm getting this error `android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@acbb68b -- permission denied for window type 2010`How can i fix it – Cursed Sep 20 '19 at 13:43
  • Use TYPE_APPLICATION_OVERLAY instead of TYPE_SYSTEM_ERROR for api >26 – Krasavello13 Oct 09 '19 at 08:43
  • `Android OS won't get a signal to open the hidden status bar`, how exactly? – Mahm00d Mar 16 '21 at 18:03