美文网首页
Android源码(6.0和8.1) 屏蔽状态栏下拉和屏蔽导航栏

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

作者: cczhengv | 来源:发表于2019-04-09 17:47 被阅读0次

    之前写过一遍6.0的导航栏屏蔽分析过程,可参考Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP)/动态显示和隐藏NavigationBar

    屏蔽状态栏下拉

    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();
            }
        }
    };

    相关文章

      网友评论

          本文标题:Android源码(6.0和8.1) 屏蔽状态栏下拉和屏蔽导航栏

          本文链接:https://www.haomeiwen.com/subject/qmpiiqtx.html