Disable the notification panel from being pulled down
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)
:
Window focus is lost when an activity is sent to background (user switching apps, or pressing the
home
button)Since Dialogs and PopupWindows open in their own separate windows, the activity's window focus will be lost when these are displayed.
Another instance in which the activity's window will lose focus is when a spinner is clicked upon, displaying a PopupWindow.
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.
Android Hide & Disable Notification (Status) Bar in oreo
I am using below code in MainActivity
.
//Global Declaration
Handler collapseNotificationHandler;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.d(tag, "window focus changed");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
collapseNow();
}
}
Collapse Method
public void collapseNow() {
try {
// Initialize 'collapseNotificationHandler'
if (collapseNotificationHandler == null) {
collapseNotificationHandler = new Handler();
}
// 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();
}
// Currently, the delay is 10 ms. You can change this
// value to suit your needs.
collapseNotificationHandler.postDelayed(this, 10L);
}
}, 10L);
} catch (Exception e) {
e.printStackTrace();
}
}
Android Hide & Disable Notification (Status) Bar
Instead of following links to other answers, here's what I did.
This solution does not disallow a user to "view" the status bar in it's 'preview' state if pulled down (even in a full screen app), but it DOES disallow a user from pulling the status bar down to it's full state to see settings, notifications, etc.
You must first add the permissions in your AndroidManifest.xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Then add another class (Java file) called customViewGroup.java
and place this code in it:
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
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;
}
}
After you have both of those set up, you can then add this into your main onCreate()
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);
This solution disables the ability to pull the status bar down always, until your app is closed. You'll have to remove this action on pause if you don't want to close your app every time.
Credit goes to @Abhimaan Madhav from This Answer
Related Topics
How to to Check If a User Has Rated Your App on the Google Play
Error: Configuration with Name 'Default' Not Found in Android Studio
Android Studio Getslotfrombufferlocked: Unknown Buffer Error
"Gps" Location Provider Requires Access_Fine_Location Permission for Android 6.0
How to Add Android Support V7 Libraries in Eclipse
Mapview Rendering with Tiles Missing with an "X" in the Center
Intent Does Not Set the Camera Parameters
Restrict Edittext to Single Line
Android: Scrollview VS Nestedscrollview
How to Check the Multiple Permission at Single Request in Android M
How Get Permission for Camera in Android.(Specifically Marshmallow)
Android How to Runonuithread in Other Class
What Is a Maximum Size of SQLite Database on Android
Gmail 5.0 App Fails with "Permission Denied for the Attachment" When It Receives Action_Send Intent
Error:Connectionresult{Statuscode=Internal_Error, Resolution=Null}
How to Kill Sub Activities and Bring Activity to Top of Stack
Unable to Execute Adb in Ubuntu. Downloaded File Is Meant for X86-64 While I Have I686