Android 禁止狀態欄下拉status bar


如果你有這樣的需求:用戶進入你的app以后,所有的操作都是你的app中設定的,用戶不可以擁有系統設置等行為的能力。然而,Android系統,可以通過從頂部往下拉,從而得到一個通知和快速系統設置的頁面: 
這里寫圖片描述 
因此,現在你想禁止它彈出,怎么辦呢? 
我不知道在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);     }
 
 
 
         
  • 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也在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;     }
 
 
 
         
  • 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

這里使用了屬性動畫將它移動到指定的高度上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM