Android 禁止状态栏下拉

如果你有这样的需求:用户进入你的app以后,所有的操作都是你的app中设定的,用户不可以拥有系统设置等行为的能力。然而,android系统,可以通过从顶部往下拉,从而得到一个通知和快速系统设置的页面:
Android 禁止状态栏下拉_第1张图片
因此,现在你想禁止它弹出,怎么办呢?
我不知道在app中怎么做,但是如果你们的处境像我一样:Android系统是一个针对特殊平台定制的,它一旦启动就进入特定的功能页面,并且不允许用户有进入系统设置的能力,那么您可以像下面这样,直接在系统代码中进行修改。

分析如何解决问题

使用Android device monitor工具,我们可以看到Android 状态栏的布局,我们会发现,平时我们看到的状态栏(如下图所示)是由PhoneStatusBarView负责绘制个管理的:
这里写图片描述
结合我们的操作,当我们点击状态栏或者下拉的时候,都会出现通知界面。而点击和下拉都是触摸事件,因此,理所当然的,我们会想到在PhoneStatusBarView的onTouchEvent中处理相应的逻辑。onTouchEvent定义在frameworks\base\packages\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);
    }

它似乎什么都没有做…然而不要忽视了,它调用了super.onTouchEvent(event)方法。PhoneStatusBarView继承了PanelBar类,这个类继承自PanelBar类。因此,super.onTouchEvent就是调用PanelBar中的onTouchEvent方法,PanelBar也在frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\目录下:

   @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Allow subclasses to implement enable/disable semantics
        if (!panelsEnabled()) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
                        (int) event.getX(), (int) event.getY()));
            }
            return false;
        }

        // figure out which panel needs to be talked to here
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            final PanelView panel = selectPanelForTouch(event);
            if (panel == null) {
                // panel is not there, so we'll eat the gesture
                Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
                        (int) event.getX(), (int) event.getY()));
                mTouchingPanel = null;
                return true;
            }
            boolean enabled = panel.isEnabled();
            if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
                    (enabled ? "" : " (disabled)"));
            if (!enabled) {
                // panel is disabled, so we'll eat the gesture
                Log.v(TAG, String.format(
                        "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
                        panel, (int) event.getX(), (int) event.getY()));
                mTouchingPanel = null;
                return true;
            }
            startOpeningPanel(panel);
        }
        final boolean result = mTouchingPanel != null
                ? mTouchingPanel.onTouchEvent(event)
                : true;
        return result;
    }

从函数的名字猜测,startOpeningPanel方法似乎就是弹出下拉菜单的入口,把它注释掉,重新编译SystemUI模块,然后替换/system/priv-app/SystemUI/SystemUI.apk,重启系统,就发现无论你是点击还是下拉屏幕顶部,都不会出现下拉也面了。
我们不妨简单分析下这里:
startOpeningPanel接收一个panel作为参数,而这个panel则是selectPanelForTouch(event);方法返回的。
PhoneStatusBarView中覆写了该方法:


    @Override
    public PanelView selectPanelForTouch(MotionEvent touch) {
        // No double swiping. If either panel is open, nothing else can be pulled down.
        return mNotificationPanel.getExpandedHeight() > 0
                ? null
                : mNotificationPanel;
    }

可以看到,这里返回的是mNotificationPanel。是的它就是下面的样子:
Android 禁止状态栏下拉_第2张图片
既然我们在这里得到了这个页面,startOpeningPanel应该就是将这个页面呈现出来吧。
startOpeningPanel如下:

    // called from PanelView when self-expanding, too
    public void startOpeningPanel(PanelView panel) {
        if (DEBUG) LOG("startOpeningPanel: " + panel);
        mTouchingPanel = panel;
        mPanelHolder.setSelectedPanel(mTouchingPanel);
        for (PanelView pv : mPanels) {
            if (pv != panel) {
                pv.collapse(false /* delayed */);
            }
        }
    }

对所有的PanelView ,调用它的collapse方法,改方法如下:

    public void collapse(boolean delayed) {
        if (DEBUG) logf("collapse: " + this);
        if (mPeekPending || mPeekAnimator != null) {
            mCollapseAfterPeek = true;
            if (mPeekPending) {

                // We know that the whole gesture is just a peek triggered by a simple click, so
                // better start it now.
                removeCallbacks(mPeekRunnable);
                mPeekRunnable.run();
            }
        } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
            cancelHeightAnimator();
            mClosing = true;
            notifyExpandingStarted();
            if (delayed) {
                postDelayed(mFlingCollapseRunnable, 120);
            } else {
                fling(0, false /* expand */);
            }
        }
    }

如果我们正在下拉,同时下拉的动画不为空,那么会调用mPeekRunnable.run();

    private Runnable mPeekRunnable = new Runnable() {
        @Override
        public void run() {
            mPeekPending = false;
            runPeekAnimation();
        }
    };

调用runPeekAnimation:

   private void runPeekAnimation() {
        mPeekHeight = getPeekHeight();
        if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
        if (mHeightAnimator != null) {
            return;
        }
        mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
                .setDuration(250);
        mPeekAnimator.setInterpolator(mLinearOutSlowInInterpolator);
        mPeekAnimator.addListener(new AnimatorListenerAdapter() {
            private boolean mCancelled;

            @Override
            public void onAnimationCancel(Animator animation) {
                mCancelled = true;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mPeekAnimator = null;
                if (mCollapseAfterPeek && !mCancelled) {
                    postOnAnimation(new Runnable() {
                        @Override
                        public void run() {
                            collapse(false /* delayed */);
                        }
                    });
                }
                mCollapseAfterPeek = false;
            }
        });
        notifyExpandingStarted();
        mPeekAnimator.start();
        mJustPeeked = true;
    }

这里使用了属性动画将它移动到指定的高度上。

你可能感兴趣的:(Android 禁止状态栏下拉)