zoukankan      html  css  js  c++  java
  • Android 禁止状态栏下拉status bar

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

    分析如何解决问题

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

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

       @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;     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    从函数的名字猜测,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;     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以看到,这里返回的是mNotificationPanel。是的它就是下面的样子: 
    这里写图片描述 
    既然我们在这里得到了这个页面,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 */);             }         }     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对所有的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 */);             }         }     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

        private Runnable mPeekRunnable = new Runnable() {         @Override         public void run() {             mPeekPending = false;             runPeekAnimation();         }     };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用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;     } 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

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

  • 相关阅读:
    PAT 1006 Sign In and Sign Out
    PAT 1004. Counting Leaves
    JavaEE开发环境安装
    NoSql数据库探讨
    maven的配置
    VMWARE 下使用 32位 Ubuntu Linux ,不能给它分配超过3.5G 内存?
    XCODE 4.3 WITH NO GCC?
    在苹果虚拟机上跑 ROR —— Ruby on Rails On Vmware OSX 10.7.3
    推荐一首让人疯狂的好歌《Pumped Up Kicks》。好吧,顺便测下博客园可以写点无关技术的帖子吗?
    RUBY元编程学习之”编写你的第一种领域专属语言“
  • 原文地址:https://www.cnblogs.com/muhuacat/p/7448656.html
Copyright © 2011-2022 走看看