systemui中动态禁用虚拟导航栏(一)

前篇介绍过activity中禁用虚拟按键导航栏,但会存在灰黑色背景框,下面介绍从systemui中如何动态禁用虚拟导航栏。

修改代码类NavigationBarFragment中禁用,具体设计代码流程:

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java makeStatusBarView->createNavigationBar

SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFragment.java

create()

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" + context.getDisplayId());
        lp.accessibilityTitle = context.getString(R.string.nav_bar);
        lp.windowAnimations = 0;
        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;

        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;

        final NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
                .create(NavigationBarFragment.class);
        navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {
                final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
                fragmentHost.getFragmentManager().beginTransaction()
                        .replace(R.id.navigation_bar_frame, fragment, TAG)
                        .commit();
                fragmentHost.addTagListener(TAG, listener);
            }

            @Override
            public void onViewDetachedFromWindow(View v) {
                FragmentHostManager.removeAndDestroy(v);
                navigationBarView.removeOnAttachStateChangeListener(this);
            }
        });
        context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
        return navigationBarView;
    }

上述代码navigation_bar_window.xml是NavigationBarFragment中NavigationBarView父布局,

NavigationBarFragment的onCreateView方法inflate动态加载navigation_bar.xml,最终获取到NavigationBarView该view,禁用也就是动态设置view.GONE。

关于在什么地方禁用,流程:

frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
                new SystemGesturesPointerEventListener.Callbacks() {
                    @Override
                    public void onSwipeFromTop() {
                        synchronized (mLock) {
                            if (mStatusBar != null) {
                                requestTransientBars(mStatusBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
                        }
                    }

                    @Override
                    public void onSwipeFromBottom() {
                        synchronized (mLock) {
                            if (mNavigationBar != null
                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                        }
                    }

                    @Override
                    public void onSwipeFromRight() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onSwipeFromLeft() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onFling(int duration) {
                        if (mService.mPowerManagerInternal != null) {
                            mService.mPowerManagerInternal.powerHint(
                                    PowerHint.INTERACTION, duration);
                        }
                    }

                    @Override
                    public void onVerticalFling(int duration) {
                        String currentPackage = getAppPackageName();
                        if (currentPackage == null) {
                            Slog.e(TAG, "Error: package name null");
                            return;
                        }
                        if (SCROLL_BOOST_SS_ENABLE) {
                            if (mPerfBoostFling == null) {
                                mPerfBoostFling = new BoostFramework();
                                mIsPerfBoostFlingAcquired = false;
                            }
                            if (mPerfBoostFling == null) {
                                Slog.e(TAG, "Error: boost object null");
                                return;
                            }
                            boolean isGame = isTopAppGame(currentPackage, mPerfBoostFling);
                            if (!isGame) {
                                mPerfBoostFling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
                                    currentPackage, duration + 160, BoostFramework.Scroll.VERTICAL);
                                mIsPerfBoostFlingAcquired = true;
                           }
                        }
                    }

                    @Override
                    public void onHorizontalFling(int duration) {
                        String currentPackage = getAppPackageName();
                        if (currentPackage == null) {
                            Slog.e(TAG, "Error: package name null");
                            return;
                        }
                        if (SCROLL_BOOST_SS_ENABLE) {
                            if (mPerfBoostFling == null) {
                                mPerfBoostFling = new BoostFramework();
                                mIsPerfBoostFlingAcquired = false;
                            }
                            if (mPerfBoostFling == null) {
                                Slog.e(TAG, "Error: boost object null");
                                return;
                            }
                            boolean isGame = isTopAppGame(currentPackage, mPerfBoostFling);
                            if (!isGame) {
                                mPerfBoostFling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
                                    currentPackage, duration + 160, BoostFramework.Scroll.HORIZONTAL);
                                mIsPerfBoostFlingAcquired = true;
                            }
                        }
                    }

                    @Override
                    public void onScroll(boolean started) {
                        String currentPackage = getAppPackageName();
                        if (currentPackage == null) {
                            Slog.e(TAG, "Error: package name null");
                            return;
                        }
                        boolean isGame;
                        if (mPerfBoostDrag == null) {
                            mPerfBoostDrag = new BoostFramework();
                        }
                        if (mPerfBoostDrag == null) {
                            Slog.e(TAG, "Error: boost object null");
                            return;
                        }
                        if (SCROLL_BOOST_SS_ENABLE) {
                            if (mPerfBoostPrefling == null) {
                                mPerfBoostPrefling = new BoostFramework();
                            }
                            if (mPerfBoostPrefling == null) {
                                Slog.e(TAG, "Error: boost object null");
                                return;
                            }
                            isGame = isTopAppGame(currentPackage, mPerfBoostPrefling);
                            if (!isGame) {
                                mPerfBoostPrefling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
                                        currentPackage, -1, BoostFramework.Scroll.PREFILING);
                            }
                        }
                        isGame = isTopAppGame(currentPackage, mPerfBoostDrag);
                        if (!isGame && started) {
                            mPerfBoostDrag.perfHint(BoostFramework.VENDOR_HINT_DRAG_BOOST,
                                            currentPackage, -1, 1);
                        } else {
                            mPerfBoostDrag.perfLockRelease();
                        }
                    }

                    @Override
                    public void onDebug() {
                        // no-op
                    }

                    private WindowOrientationListener getOrientationListener() {
                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
                        return rotation != null ? rotation.getOrientationListener() : null;
                    }

                    @Override
                    public void onDown() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchStart();
                        }
                        if(SCROLL_BOOST_SS_ENABLE && mPerfBoostFling!= null
                                            && mIsPerfBoostFlingAcquired) {
                            mPerfBoostFling.perfLockRelease();
                            mIsPerfBoostFlingAcquired = false;
                        }
                    }

                    @Override
                    public void onUpOrCancel() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchEnd();
                        }
                    }

                    @Override
                    public void onMouseHoverAtTop() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseHoverAtBottom() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseLeaveFromEdge() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                    }
                });

onSwipeFromBottom()方法就是底部上滑监听,requestTransientBars()

mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);

->frameworks/base/services/core/java/com/android/server/wm/InsetsPolicy.java,showTransient(@InternalInsetsType int[] types)

updateBarControlTarget(mFocusedWin);

->updateBarControlTarget()

mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);

->frameworks/base/services/core/java/com/android/server/wm/InsetsPolicy.BarWindow

updateVisibility()->setVisible()

private void updateVisibility(InsetsControlTarget controlTarget,
                @InternalInsetsType int type) {
            final WindowState controllingWin =
                    controlTarget instanceof WindowState ? (WindowState) controlTarget : null;
            setVisible(controllingWin == null
                    || controllingWin.getRequestedInsetsState().getSourceOrDefaultVisibility(type));
        }

private void setVisible(boolean visible) {
            final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
            if (mState != state) {
                mState = state;
                mPolicy.getStatusBarManagerInternal().setWindowState(
                        mDisplayContent.getDisplayId(), mId, state);
            }
        }

frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java

 @Override
        public void setWindowState(int displayId, int window, int state) {
            if (mBar != null) {
                try {
                    mBar.setWindowState(displayId, window, state);
                } catch (RemoteException ex) {}
            }
        }

//bar//
 // ================================================================================
    // Callbacks from the status bar service.
    // ================================================================================
    // TODO(b/118592525): refactor it as an IStatusBar API.
    @Override
    public RegisterStatusBarResult registerStatusBar(IStatusBar bar) {
        enforceStatusBarService();

        Slog.i(TAG, "registerStatusBar bar=" + bar);
        mBar = bar;
        mDeathRecipient.linkToDeath();
        notifyBarAttachChanged();
        final ArrayMap<String, StatusBarIcon> icons;
        synchronized (mIcons) {
            icons = new ArrayMap<>(mIcons);
        }
        synchronized (mLock) {
            // TODO(b/118592525): Currently, status bar only works on the default display.
            // Make it aware of multi-display if needed.
            final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY);
            final int[] transientBarTypes = new int[state.mTransientBarTypes.size()];
            for (int i = 0; i < transientBarTypes.length; i++) {
                transientBarTypes[i] = state.mTransientBarTypes.valueAt(i);
            }
            return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1),
                    state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
                    state.mImeBackDisposition, state.mShowImeSwitcher,
                    gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
                    state.mNavbarColorManagedByIme, state.mFullscreen, state.mImmersive,
                    transientBarTypes);
        }
    }

在frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

registerStatusBar()

RegisterStatusBarResult result = null;
        try {
            result = mBarService.registerStatusBar(mCommandQueue);
        } catch (RemoteException ex) {
            ex.rethrowFromSystemServer();
        }

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java

//handler 消息发送
@Override
    public void setWindowState(int displayId, int window, int state) {
        synchronized (mLock) {
            // don't coalesce these
            mHandler.obtainMessage(MSG_SET_WINDOW_STATE, displayId, window, state).sendToTarget();
        }
    }

// 遍历回调所有监听者 
case MSG_SET_WINDOW_STATE:
                    for (int i = 0; i < mCallbacks.size(); i++) {
                        mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2, (int) msg.obj);
                    }
                    break;

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java

@Override
    public void setWindowState(
            int displayId, @WindowType int window, @WindowVisibleState int state) {
        if (displayId == mDisplayId
                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                && mNavigationBarWindowState != state) {
            mNavigationBarWindowState = state;
            updateSystemUiStateFlags(-1);
            mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
            if (mOrientationHandle != null
                    && mStartingQuickSwitchRotation != -1) {
                orientSecondaryHomeHandle();
            }
            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));

            if (mNavigationBarView != null) {
                mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
            }
        }
    }

如何触发:

一、当每次手势滑动时,NavigationBarFragment类中的setWindowState()都被触发回调

二、当通过view.setSystemUiVisibility() 无论是hide或show都会触发

三、通过Settings.System  ContentObserver监听value改变

以上三种皆可以最终触发,走到最后setWindowState()方法内

@Override
    public void setWindowState(
            int displayId, @WindowType int window, @WindowVisibleState int state) {
        if (displayId == mDisplayId
                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                && mNavigationBarWindowState != state) {
            mNavigationBarWindowState = state;
            updateSystemUiStateFlags(-1);
            mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
            if (mOrientationHandle != null
                    && mStartingQuickSwitchRotation != -1) {
                orientSecondaryHomeHandle();
            }
            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
            if (mNavigationBarView != null  && isChecked) {
                mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
                if(条件?){
                    mNavigationBarView.setVisibility(View.GONE);
                }else{
                    mNavigationBarView.setVisibility(View.VISIBLE);
                }
                
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值