Hide status bar in android 4.4+ or kitkat with Fullscreen - android

I'm using following code for hiding status bar with full screen purpose:
void HideEverything(){
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// Remember that you should never show the action bar if the
// status bar is hidden, so hide that too if necessary.
ActionBar actionBar = getActionBar();
actionBar.hide();
}
}
It shows Screen in full-screen mode but when I touch status bar it shows status bar.
I tried other options to add the full screen and no title bar theme in application and activity level in manifest, but still results are the same... :(
I don't want to show status bar at any step.
How to achieve this in android?
Edit :
Android OS version is 4.4.2
(Above code is working on 4.3 but not on 4.4.2)
Update:
Problem has been solved...
Answer is written below separately...

No solution could work for the problem as Android version is 4.4.2.
As commented by #Academy of Programmer; this solution does not work on Android 6 and above.
But as per the suggestion by Sunny, problem has been solved by preventing the expansion of status bar.
Solution is:
Write an inline customViewGroup class in your main activity.
public 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;
}
}
Now in your onCreate method of mainActivity add following code before setContentView() :
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) (50 * getResources()
.getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.TRANSPARENT;
customViewGroup view = new customViewGroup(this);
manager.addView(view, localLayoutParams);
Above code will disable the expansion of status bar.
Now make full screen by following code, add it just below the above code and before the setContentView :
//fullscreen
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
Now in manifest add the permission:
<!-- prevent expanding status bar -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
and you are done.... :)
drawback : This code disables expansion of status bar for the device not just for an activity or an application, so use it if you really need it.
Thank you for all the solutions and suggestions... :)

We cannot prevent the status appearing in full screen mode in kitkat or above devices, so try a hack to block the status bar from expanding.
For an idea, put an overlay over status bar and consume all input events. It will prevent the status bar from expanding.

Using below code you can use full screen ;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Write below code above setcontentview.
Note : Don't give any theme to this activity.
Hope this helps.

use following code onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
}

Related

Hide status bar with layout stable and maintain position of action bar

Is it possible to programmatically hide the status bar without hiding the action bar?
The end goal is to hide the status bar and its content while keeping everything else on the screen in its place and without hiding the action bar as well, and then after 5 seconds, show the status bar again while also keeping all other content in place. Basically, to leave a blank view/space at the top of the screen the same size as the status bar.
I've tried various combinations of the following view flags:
private void maybeHideStatusBar() {
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
persistSystemUiVisibility(mActivityWindow, flags);
}
Where persistSystemUiVisibility(...) is as follows:
private static void persistSystemUiVisibility(final Window window, final int visibility) {
final View decorView = window.getDecorView();
decorView.setOnSystemUiVisibilityChangeListener(null);
decorView.setSystemUiVisibility(visibility);
decorView.setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int newVisibility) {
if (newVisibility != visibility) {
persistSystemUiVisibility(window, visibility);
}
}
});
}
However, the most important window flag View.SYSTEM_UI_FLAG_FULLSCREEN which actually hides the status bar and its content, also forces the action bar to be hidden as well. Is there any way to override this default action bar behavior?
All of this needs to happen after activity create and setContentView so requestWindowFeature(Window.FEATURE_ACTION_BAR) doesn't work.
Any help would be greatly appreciated, thank you! :)

Status bar background stays on screen when entering immersive mode?

I've been searching everywhere but I'm at a loss about that : trying to activate immersive mode on a project;
Nearly everything works fine, except the background of my status bar always stays there, spoiling the immersion...
I have included a screenshot of the screen before and after activating the immersive mode, and set the "colorPrimaryDark" to full green for max contrast :
screenshots showing the background of the status bar when nothing should be there
The code I used and reinserted in a blank project to isolate this problem comes straight from the google dev examples, in my MainActivity, I have :
private final String TAG = "DEBUG::" + this.getClass().getSimpleName();
private final int INITIAL_HIDE_DELAY = 1500;
private View decorView;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//setting needed decorView for fullscreen behavior
decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener(onSystemUiVisibilityChangeListener);
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.i(TAG, "onWindowFocusChanged::hasFocus = " + hasFocus);
if (hasFocus) {// When the window gains focus, hide the system UI.
delayedHide(INITIAL_HIDE_DELAY);
} else {// When the window loses focus, cancel any pending hide action.
mHideHandler.removeMessages(0);
}
}
private void hideSystemUI() {
Log.i(TAG, "hideSystemUI");
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
uiOptions |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE;
decorView.setSystemUiVisibility(uiOptions);
}
private final Handler mHideHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
hideSystemUI();
}
};
private void delayedHide(int delayMillis) {
Log.i(TAG, "delayedHide");
mHideHandler.removeMessages(0);
mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
}
private View.OnSystemUiVisibilityChangeListener onSystemUiVisibilityChangeListener =
new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// The system bars are visible
getSupportActionBar().show();
delayedHide(INITIAL_HIDE_DELAY);
} else {
// The system bars are NOT visible
getSupportActionBar().hide();
}
}
};
I wonder if my problem might come from layout or style files, but those are raw from project generation...
I hope someone out there can point me to where I failed!
Thanks in advance!
EDIT : I found that removing : android:fitsSystemWindows="true" from my activity's layout file allows a real fullscreen mode, but then, my ActionBar is partly hidden behind the StatusBar -when showing. Could it be that when I set my getSupportActionBar().show(); in onSystemUiVisibilityChangeListener, it gets drawn too soon?
EDIT 2 : How I understand this so far is that I only have 2 choices regarding the position/size of my content (action bar included) :
top of the screen, which will show the actionBar partially hidden by the statusbar,
or below the statusBar's bottom, which will leave me with a "hole" when the statusBar is hidden -_-
I am now looking for a solution to animate the ActionBar off-screen/on-screen by myself inside my onSystemUiVisibilityChangeListener method, but can't find a way to grab its View to do so, solutions posted there https://stackoverflow.com/a/21125631/6463888 seem out of date...
I met the same problem today. But I didn't solve this issue by setSystemUiVisibility. I solve it using following method:
hide:enter full screen
mActivity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
show:normal display
mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
So,
the way I solved this may seem a bit stretched, but I'm only a beginner, so feel free to comment!
I don't use getSupportActionBar().show(); or getSupportActionBar().hide(); anymore, but I managed to grab the View that contains the ActionBar which is an AppBarLayout, and I animated this View instead. So I call a small function animateActionBarInOrOut to animate it on or off screen inside onSystemUiVisibilityChange :
private void animateActionBarInOrOut(boolean appears){
Log.i(TAG, "animateActionBarInOrOut::actual position = " + toolbar.getY());
if(appears){
toolbar.animate().translationY(48).alpha(1); // move it out of the screen
}else{
toolbar.animate().translationY(-48).alpha(0); // move it out of the screen
}
}
Although this is not exactly an answer to the initial question, it works as a solution to the problem, one just has to move the content accordingly...
Hi your problem is caused by StatusBar nature, it has a separate layout from your main content and you need to set his color manually. For example when you call onSystemUiVisibilityChange() you can take the color of your background and, after set the color of StatusBar with that color. This is a workaround to avoid 2 different background colors.

hide and show statusbar without any effect to layout in android

I want to write a book-reader application that normally runs in full-screen, but when user touched screen, status bar become visible OVER my main layout without re-creating the whole view.
I already read these but no help at all:
Hide notification bar without using fullscreen
Hide Notification bar
Android Show Activity Title/status bar at the top after it is hidden
any idea how can I do it?
thanks
finally, I did it!!
these 2 methods will show and hide status bar without destroying the layout.
you need to set
private View mMainView; // The main view of the activity
private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
then
/** Hides StatusBar and ActionBar */
private void hideSystemUi() {
ActionBar ab = getActionBar();
ab.hide();
// Set flags for hiding status bar
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
// Hide the status bar.
mMainView.setSystemUiVisibility(uiOptions);}
and
/** Shows StatusBar and ActionBar */
private void showSystemUi() {
ActionBar ab = getActionBar();
ab.show();
// Reset flags
mMainView.setSystemUiVisibility(this.mSystemUiVisibility);
}
and put this in your onCreate() method:
mMainView = findViewById(R.id.mainLayout);
mMainView.setSystemUiVisibility(mSystemUiVisibility);

PopupWindow + full screen => show notification-bar?

Background
I'm making an activity that has 2 fragments.
the second fragment shows a full screen image, which also hides the status bar (AKA notification bar) using:
final View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN)
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
The problem
I'm trying to add a sharing dialog of the currently shown image, but no matter which method I try to do it, it always shows the status bar, making things "jumpy".
What I've tried
The normal way to open the sharing dialog didn't work (I mean, it worked, but it showed the status bar) :
startActivity(Intent.createChooser(shareIntent,"some text");
So I had to create my own popup.
First I wanted to show some sort of progressDialog, but it also caused the status bar to show, so I removed it.
Then I wanted to show a list of the items, so I used ListPopupWindow (anchored to the view the user is clicking) , but it also showed the status bar. Another thing I tried is to use the normal PopupWindow and set a listView inside of it, but it also didn't help.
Another thing that I tried is to change the window of the popupWindow to have the same settings as the fragment's activity, but it also didn't help.
I even tried to set a smaller height for the popup, but it didn't help.
The question
How can I use a PopupWindow (or the normal sharing dialog) so that the status bar will remain in the same state as it did before showing it?
OK, I think I've found the perfect combination. I used the normal sharing intent, and set the flags of the window as needed.
for hiding/showing the status bar correctly :
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void setStatuBarVisibility(final boolean visible) {
if (visible) {
// if (Build.VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN)
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
final View decorView = getActivity().getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
// a no animation version of: getActivity().getActionBar().show();
ViewUtil.getActionBarView(getActivity()).setVisibility(View.VISIBLE);
} else {
// hide status bar (if possible) and the action bar, and dim navigation buttons:
final View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN)
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// if (Build.VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN)
getActivity().getWindow().addFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
// a no animation version of: getActivity().getActionBar().hide();
ViewUtil.getActionBarView(getActivity()).setVisibility(View.GONE);
ViewUtil.hideSoftKeyboardFromFocusedView(getActivity());
}
}
public static View getActionBarView(final FragmentActivity activity) {
final Window window = activity.getWindow();
final View v = window.getDecorView();
final int resId = activity.getResources().getIdentifier("action_bar_container", "id", "android");
return v.findViewById(resId);
}
public static void hideSoftKeyboardFromFocusedView(final Context context, final View view) {
final InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
it also avoids the jumpy behavior when going to/from the fragment, and when showing the sharing dialog.

Preventing status bar expansion

Is there anyway to prevent users from sliding the status bar (expand) or collapsing back?
I'm trying out a lockscreen replacement and seems like it's a must-have feature. Is there any possible way to do it without requiring root privileges?
You can actually prevent the status bar from expanding, without rooting phone. See this link. This draws a window the height of the status bar and consumes all touch events.
Call the following code just after 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;
}
}
Short answer: this is impossible!
Now should you be interested to know why this is impossible:
There are two permissions for manipulating the system status bar, EXPAND_STATUS_BAR and STATUS_BAR. The former can be requested by any application, but the later is reserved for applications signed with the platform signature (system applications, not third-party). It is possible to expand/ collapse the system status bar (see "How to open or expand status bar through intent?") but note that reflection is required because the StatusBarManager class is not part of the SDK. The disable method, which is used by the Android dialer to prevent the status bar from being expanded, cannot be accessed by an application without the aforementioned STATUS_BAR permission.
Sources: personal experience :-)
First of all, it's impossible to modify the Status Bar if your app is not signed with the phone's rom certified, if you try to modify it you'll get an Security Exception.
Update: In new APIs the method is "collapsePanels" instead of "collapse".
The only way I've found after several hours of work is by overriding the "onWindowFocusChanged" method of the activity and when it loses the focus (maybe the user has touched the notifications bar), force to collapse the StatusBar, here is the code (working on a Defy+ 2.3.5).
You need to declare the following permission on the manifest:
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
And override the following method:
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)
{
}
}
Update: You will have to use your own custom Alert Dialog by overriding it their onWindowFocusChanged method too, because Alert Dialogs have their own focus.
This actually can be done via a little hack that I accidentally discovered, but requires the permission android.permission.SYSTEM_ALERT_WINDOW:
What you do is add a view the exact size of the status bar directly to the WindowManager with the certain parameters that covers the status bar and prevents it from receiving touch events:
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);
This will basically create a transparent view over the status bar that will receive all the touch events and block the events from reaching the status bar and therefore prevents it from being expanded.
NOTE: This code is untested, but the concept works.
I tried the solutions mentioned by GrantLand and PoOk but both didn't work in my case. Though, Another solution Clear/Hide Recent Tasks List did the trick for me. I am writing a launcher app for which I had to disable a recent applications menu so user cannot open a locked app from it. Also, I had to prevent against notification bar expansion and this trick made me achieve both. Override OnWindowFocusChanged method in your activity and check if this is what u wanted.
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);
}
}
For a lockscreen Why don't you just use the following in your main activity:
#Override
public void onAttachedToWindow() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
If the user doesn't have a secure lockscreen set the app will let the user pull the status bar down and open activities but that doesn't matter as the user obviously doesn't want a secure screen anyway.
If the user does have a secure locksreen set then the app will show the status bar but will not allow interactions with it. This is because the phone is still actually locked and only your activity is allowed to operate until the user unlocks the phone. Also closing your app in anyway will open the standard secure lockscreen. All this is highly desirable because you don't have to spend all that time coding secure features that you can't guarantee will be as secure as the stock ones.
If you really don't want the user to be able to interact with the status bar, maybe you can leave out the flag FLAG_DISMISS_KEYGUARD call. Then just before you are about to unlock the phone set the flag like I showed in the first block. I don't know if this last part works but it's worth a try.
Hope that helps
Sorry but it does not work. using FLAG_LAYOUT_IN_SCREEN prevents you from catching any touch events.
And BTW:
to add a view to the window use the window manager:
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);

Categories

Resources