第一种方法是直接禁止,第二种方法是动态禁止
(一)网上关于屏蔽状态栏的文章搜到不少,但都是针对某个应用,或者锁屏状态,才能屏蔽状态栏的下拉,而我的需求是不管任意状态都屏蔽状态栏下拉,百度到的也可能版本不一样,说的一些文件都找不到,搜到一篇文章,自己修改了一个方法,然后OK了,具体如下:
文件位置:frameworks\base\core\java\android\app\StatusBarManager.java
修改此方法中的参数,不用传穿进去的参数
public void disable(int what) {
try {
mService.disable(DISABLE_EXPAND, mToken, mContext.getPackageName());
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
参考文章:http://www.xuebuyuan.com/1608099.html
1.做锁屏软件,锁屏软件具体界面的实现不说,在屏蔽通知栏下拉的时候就出现问题了。网上找了一些资料,可以通过statusbarmanager这个类来实现,由于这个类是系统隐藏的,所以我们很容易就想到使用反射,这个类的源码如下:
package android.app;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.ServiceManager;
public class StatusBarManager {
public static final int DISABLE_EXPAND = 0x00000001;
public static final int DISABLE_NOTIFICATION_ICONS = 0x00000002;
public static final int DISABLE_NOTIFICATION_ALERTS = 0x00000004;
public static final int DISABLE_NOTIFICATION_TICKER = 0x00000008;
public static final int DISABLE_NONE = 0x00000000;
private Context mContext;
private IStatusBar mService;
private IBinder mToken = new Binder();
StatusBarManager(Context context) {
mContext = context;
mService = IStatusBar.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
public void disable(int what) {
try {
mService.disable(what, mToken, mContext.getPackageName());
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public void expand() {
try {
mService.activate();
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public void collapse() {
try {
mService.deactivate();
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public void toggle() {
try {
mService.toggle();
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public IBinder addIcon(String slot, int iconId, int iconLevel) {
try {
return mService.addIcon(slot, mContext.getPackageName(), iconId, iconLevel);
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
try {
mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
public void removeIcon(IBinder key) {
try {
mService.removeIcon(key);
} catch (RemoteException ex) {
// system process is dead anyway.
throw new RuntimeException(ex);
}
}
}
</span>
2.如果是系统级应用,也就是手机厂家植入的应用,可以使用disable(int)的方法来进行屏蔽,参数如上源码五个参数之一即可。但是如果是在应用层上的,disable方法因为权限问题无法使用(如果一定要使用必须具有系统签名)。这个时候可以使用collapse()方法,现在的小米锁屏和360锁屏都是使用该方法,具体代码如下:
<span style="margin: 0px; padding: 0px; border: 0px; font-size: 12px; background: transparent;">@Override
public void onWindowFocusChanged(boolean hasFocus) {
disableStatusBar();
super.onWindowFocusChanged(hasFocus);
}
public void disableStatusBar(){
try {
Object service = getSystemService("statusbar");
Class<?> claz = Class.forName("android.app.StatusBarManager");
Method expand = claz.getMethod("collapse");
expand.invoke(service);
} catch (Exception e) {
e.printStackTrace();
}
}</span>
3.重写activity的onWindowfocuschanged方法,执行如上操作即可。以上方法使用了反射,如果不想使用使用反射获得隐藏的StatusBarManager,我这里提供一个jar包,将jar包导入到项目中,即可直接使用StatusBarManager ,还可以直接使用ServiceManager这个隐藏类,它有什么用?相信做过自动挂断电话的童鞋应该了解。
jar下载地址包:http://download.csdn.net/detail/welen123456789/5068165
(二)屏蔽状态栏下拉
6.0解决办法
源码位置 SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBarView.java
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean barConsumedEvent = mBar.interceptTouchEvent(event);
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
event.getActionMasked(), (int) event.getX(), (int) event.getY(),
barConsumedEvent ? 1 : 0);
}
}
// return barConsumedEvent || super.onTouchEvent(event);
return false;
}
直接返回false,action_move不会执行,代码看似简单,实则super.onTouchEvent(event)调用的是PanelBar.java中的onTouchEvent()
8.1解决办法(同上)
6.0和8.1的状态栏代码是有差异的,但是通过上面的方法都能达到需求效果
6.0的PhoneStatusBarView调用onTouchEvent(),最终调用PanelBar的onTouchEvent()
8.1的PhoneStatusBarView调用onTouchEvent(),接着调用PanelBar的onTouchEvent(),最终调用PanelView的onTouchEvent()
从根本上阻止事件的传递来达到屏蔽下拉的效果
补充
如果需要动态的控制是否允许下拉状态栏,可以通过广播通知,接受传递的参数,持久化保存(可通过SharedPreference或者Settings.Global.xxxx)当前状态栏的状态,一般建议采用Settings.Global保存。
具体步骤
1.在frameworks\base\core\java\android\provider\Settings.java中Globel内部类下添加变量名称,比如OPEN_PANEL_ENABLED
2.通过make update-api指令重新编译,因为在Settings中修改后需要编译才能对应到这两文件frameworks/base/api/system-current.txt、frameworks/base/api/current.txt
3.在广播接收的地方通过Settings.Global.putInt(context.getContentResolver(), Settings.Global.OPEN_PANEL_ENABLED, 1) 保存值
(ps 可通过adb命令 adb shell settings put global open_panel_enabled 1 模拟写入 adb shell settings get global open_panel_enabled 模拟查看)
4.将刚刚的return false改成
boolean flag=Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.OPEN_PANEL_ENABLED,1)==1;
return flag ? barConsumedEvent || super.onTouchEvent(event) : flag;
屏蔽导航栏显示
6.0解决办法
源码位置SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBar.java
@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
updateDisplaySize();
mScrimSrcModeEnabled = mContext.getResources().getBoolean(
R.bool.config_status_bar_scrim_behind_use_src);
super.start(); // calls createAndAddWindows()
mMediaSessionManager
= (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
// TODO: use MediaSessionManager.SessionListener to hook us up to future updates
// in session state
addNavigationBar();
.....
}
直接注释addNavigationBar()就能达到需求效果
8.1解决办法
源码位置SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java
protected void makeStatusBarView() {
final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
....
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
createNavigationBar();
}
} catch (RemoteException ex) {
// no window manager? good luck with that
}
....
}
直接注释createNavigationBar()或者将showNav=false就能达到需求效果
代码流程分析
6.0和8.1的导航栏都是通过WindowManager的addView来添加的,通过WindowManager的removeViewImmediate来移除
1、6.0的addNavigationBar实现,通过addView将mNavigationBarView添加,prepareNavigationBarView方法设置了点击、触摸、长按事件,无需关心
private void addNavigationBar() {
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
if (mNavigationBarView == null) return;
prepareNavigationBarView();
mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
mNavigationShown=true;
}
查找到在makeStatusBarView()中,mNavigationBarView初始化,加载navigation_bar布局文件
protected PhoneStatusBarView makeStatusBarView() {
final Context context = mContext;
Resources res = context.getResources();
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
...
mNavigationBarView = (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
mNavigationBarView.setDisabledFlags(mDisabled1);
mNavigationBarView.setBar(this);
mNavigationBarView.setOnVerticalChangedListener(
new NavigationBarView.OnVerticalChangedListener() {
@Override
public void onVerticalChanged(boolean isVertical) {
if (mAssistManager != null) {
mAssistManager.onConfigurationChanged();
}
mNotificationPanel.setQsScrimEnabled(!isVertical);
}
});
mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
checkUserAutohide(v, event);
return false;
}});
}
2、8.1的createNavigationBar实现,发现是通过NavigationBarFragment来实例化mNavigationBarView
protected void createNavigationBar() {
mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
mNavigationBar = (NavigationBarFragment) fragment;
if (mLightBarController != null) {
mNavigationBar.setLightBarController(mLightBarController);
}
mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
});
}
NavigationBarFragment的crate方法通过addView将mNavigationBarView添加,加载navigation_bar_window布局
public static View create(Context context, FragmentListener listener) {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.setTitle("NavigationBar");
lp.windowAnimations = 0;
View navigationBarView = LayoutInflater.from(context).inflate(
R.layout.navigation_bar_window, null);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
if (navigationBarView == null) return null;
context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
NavigationBarFragment fragment = new NavigationBarFragment();
fragmentHost.getFragmentManager().beginTransaction()
.replace(R.id.navigation_bar_frame, fragment, TAG)
.commit();
fragmentHost.addTagListener(TAG, listener);
return navigationBarView;
}
补充
依旧是通过广播来动态控制导航栏的显示和隐藏
6.0已在开头文章中写过,这里就只补充8.1的显示和隐藏
源码位置SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java
private static final String SHOW_NAVIGATION = "cc.intent.systemui.shownavigation";
private static final String HIDE_NAVIGATION = "cc.intent.systemui.hidenavigation";
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (HIDE_NAVIGATION.equals(action)) {
if (mNavigationBarView == null) return;
mWindowManager.removeViewImmediate(mNavigationBarView);
mNavigationBarView = null;
}else if (SHOW_NAVIGATION.equals(action)) {
if (mNavigationBarView != null) return;
createNavigationBar();
}
}
};
原文地址:https://blog.csdn.net/u012932409/article/details/89156391