Prevent status bar for appearing android (modified)
Asked Answered
P

3

31

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

Pretermit answered 13/8, 2014 at 10:51 Comment(0)
P
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);
Pretermit answered 20/8, 2014 at 5:4 Comment(31)
Absolutely the only thing that worked for me after 2 weeks trying. Completely blocks status bar expansionMontfort
Note: Needs <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> to runMontfort
I am a Noob, can you give some more detail about the customViewGroup?Normalize
@Normalize Here's a VERY basic customViewGroup that will get you started. linkBedplate
Unfortunately this disables the status bar permanently (even when you quit the app!). Is there a way to do it only within the application?Xylem
you can remove the view when you quit your application. so that should not be a problemPretermit
@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.Xylem
what about softkeyboard ? {Back , home , recentapp button,..etc}Efrainefram
@Xylem 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.Pretermit
@Menna-AllahSami Post your question in stackoverflow and comment it as a link may be i can address your issuePretermit
What if an app uses fullscreen mode with actionbar menu? This method will just overlap these controls making them not usable.Anything
I have mentioned not to use full screen modePretermit
This solution worked for me and I am using full screen mode (no action bar, though). Running Lollipop on Nexus 7.Frerichs
where does the code section go? does it go into the customViewGroup's onInterceptTouchEvent?Hersh
yes its intercepted by custom view group and the touch is blocked ie(the touch is consumed)Pretermit
@AbhimaanMadhav Any idea how can i disable the soft keys(Back, Home, Recent Apps) as well?Indispose
@Indispose #34224898Pretermit
(int) (50 * getResources() what is decision criteria for using 50?Bambara
usually the status bar height is around 24dp selected 50dp so that it works on all devices and density. you can choose suitable height @DegenSharewPretermit
Best solution so farLyrism
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 typePhalanx
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 ThanksPompadour
@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 developer.android.com/reference/android/…Pretermit
This one helped me.. after all the trail and error methodsDorsum
Does not work on Android 8.0 or Oreo devices any more.Muscadel
@QLocker can you elaborate on what does not work on oreo and above devicesPretermit
@Pretermit On oreo+ devices, any user added window or view can not show above the status bar, the status bar can always be pulled down.Muscadel
@QLocker did you find any solution for Oreo+?Mano
What if I have a EditText on top of the screen and that editText still need to receive touchEvent.Whichever
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.Whichever
@Whichever may be this 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 devicesPretermit
P
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);
}
Pfennig answered 13/2, 2016 at 16:7 Comment(15)
(int) (40 * getResources() what is decision criteria for using 40?Bambara
usually the status bar would be around 40 dp i believePretermit
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.Brattice
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!!!Jetsam
is it working with rooted devices?i have tried it on 5.1 Lollilop root device with no results...Dorkas
Yes, it should. Rooting usually doesn't break Android logics like this.Pfennig
How remove this view?¿ Because with manager.removeView(view) and manager.removeViewImmediate(view) not workPompadour
This should work like in the sample above with manager.removeView(blockingView);Pfennig
The status bar height on the most devices is 24 or 25 dp. This would be sufficient in the code above.Pfennig
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.Callaway
it does not work in oreo please make for oreo support alsoBeneficence
@Honza: For Android 4.4 and 5 it's enough to put the permission in the Manifest file <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />Pfennig
@Brattice did you find the solution because I am also using the same app but not able to restrict notification bar?Cuisse
@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.Brattice
@Brattice 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?Cuisse
B
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;
    //https://mcmap.net/q/36502/-how-to-get-screen-dimensions-as-pixels-in-android
    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);
}
Brattice answered 18/12, 2018 at 16:37 Comment(3)
I'm getting this error android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@acbb68b -- permission denied for window type 2010How can i fix itMickimickie
Use TYPE_APPLICATION_OVERLAY instead of TYPE_SYSTEM_ERROR for api >26Saintsimonianism
Android OS won't get a signal to open the hidden status bar, how exactly?Home

© 2022 - 2024 — McMap. All rights reserved.