Android源码(6.0和8.1) 屏蔽状态栏下拉和屏蔽导航栏显示

第一种方法是直接禁止,第二种方法是动态禁止

(一)网上关于屏蔽状态栏的文章搜到不少,但都是针对某个应用,或者锁屏状态,才能屏蔽状态栏的下拉,而我的需求是不管任意状态都屏蔽状态栏下拉,百度到的也可能版本不一样,说的一些文件都找不到,搜到一篇文章,自己修改了一个方法,然后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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值