The following implementation is only working below Android 8. You can refer to the details here.
public static void preventStatusBarExpansion(Context context) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
WindowManager manager = ((WindowManager) context.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE));
WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
localLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
}
localLayoutParams.gravity = Gravity.TOP;
localLayoutParams.flags =
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
int resId = context.getResources()
.getIdentifier("status_bar_height", "dimen", "android");
int result = 0;
if (resId > 0) {
result = context.getResources().getDimensionPixelSize(resId);
}
localLayoutParams.height = result;
localLayoutParams.format = PixelFormat.RGB_888;
CustomViewGroup view = new CustomViewGroup(context);
manager.addView(view, localLayoutParams);
}
/**
* 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", "Pull down status bar action");
return true;
}
}
And for Android 8 or above, you may refer to the link above for the corresponding implementation. And that should be the one you have mentioned: onWindowFocusChanged()
. You can implement onWindowFocusChanged()
in a BaseActivity
(For the basic of BaseActivity structure, you may refer to here), and all your other Activity
should extend the BaseActivity
.
BaseActivity.java
public abstract class BaseActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
}
protected abstract int getLayoutResourceId();
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.d("BaseActivity", "window focus changed");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
collapseNow();
}
}
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();
}
}
}
MainActivity.java
public class MainActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutResourceId(){
return R.layout.activity_main;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu, menu);
return true;
}
}
options_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/item_a"
android:title="A" />
<item android:id="@+id/item_b"
android:title="B" />
<item android:id="@+id/item_c"
android:title="C" />
<item android:id="@+id/item_d"
android:title="D" />
</menu>
The status bar should be closed automatically even though the option menu is opened:
