jQuery鼠标指针特效

Android 11 导航栏添加一个虚拟按钮--问题合集

导航栏添加一个虚拟按钮

按钮功能:显示隐藏导航栏

1.frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
protected String getDefaultLayout() {
    final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)
            ? R.string.config_navBarLayoutHandle
            : mOverviewProxyService.shouldShowSwipeUpUI()
                    ? R.string.config_navBarLayoutQuickstep
                    : R.string.config_navBarLayout;
    return getContext().getString(defaultResource);
}

//R.string.config_navBarLayout,构成底部按钮的文件

2.frameworks/base/packages/SystemUI/res/values/config.xml,nav_hide,就是新增按钮的名称
<string name="config_navBarLayout" translatable="false">left[.5W];volume_sub,back,home,recent,volume_add,nav_hide,screenshot;right[.5W]</string>

//sw是smallwidth的意思,当屏幕的最小边像素大于900 就会使用values-sw900dp,根据 config_navBarLayout_right 的值 来计算每个图标的宽度 如果为 W或WC 则表示为weight 如果为AC 则表示是像素值

3.给新添加的button 创建layout布局, 默认放在layout文件夹下
<com.android.systemui.statusbar.policy.KeyButtonView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_hide"
    android:layout_width="@dimen/navigation_key_width"
    android:layout_height="match_parent"
    android:layout_weight="0"
    systemui:keyCode="101" 
    android:scaleType="center"
    android:contentDescription="hide"
    android:paddingStart="@dimen/navigation_key_padding"
    android:paddingEnd="@dimen/navigation_key_padding"
    />
    
4.将按钮布局,添加进入导航栏布局中.
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java

private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
	...
	} else if (VOLUME_SUB.equals(button)) {
            v = inflater.inflate(R.layout.volume_sub, parent, false);
        } else if (NAV_HIDE.equals(button)) {
            v = inflater.inflate(R.layout.nav_hide, parent, false);//add 
        }
	...
}

5.为按钮添加图片和点击事件
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java

//仿照系统原有的按钮比如home或Screenshot(截屏)做就行了
@@ -125,6 +125,7 @@ public class NavigationBarView extends FrameLayout implements
     private KeyButtonDrawable mVolumeAddIcon;
     private KeyButtonDrawable mVolumeSubIcon;
     private KeyButtonDrawable mScreenshotIcon;
+    private KeyButtonDrawable mNavHideIcon;//add hide nav 

     private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private final DeadZone mDeadZone;
@@ -335,6 +336,7 @@ public class NavigationBarView extends FrameLayout implements
         mButtonDispatchers.put(R.id.screenshot, new ButtonDispatcher(R.id.screenshot));
         mButtonDispatchers.put(R.id.volume_add, new ButtonDispatcher(R.id.volume_add));
         mButtonDispatchers.put(R.id.volume_sub, new ButtonDispatcher(R.id.volume_sub));
+        mButtonDispatchers.put(R.id.nav_hide, new ButtonDispatcher(R.id.nav_hide));//add hide nav 
         mDeadZone = new DeadZone(this);

         mNavColorSampleMargin = getResources()
@@ -483,6 +485,12 @@ public class NavigationBarView extends FrameLayout implements
         return mButtonDispatchers.get(R.id.screenshot);
     }

+    //add hide nav 
+    public ButtonDispatcher getNavHideButton(){
+        return mButtonDispatchers.get(R.id.nav_hide);
+    }
+    //add hide nav 
+
     public ButtonDispatcher getVolumeAddButton() {
         return mButtonDispatchers.get(R.id.volume_add);
     }
@@ -539,6 +547,7 @@ public class NavigationBarView extends FrameLayout implements
         mVolumeAddIcon = getDrawable(R.drawable.ic_sysbar_volume_add_button);
         mVolumeSubIcon = getDrawable(R.drawable.ic_sysbar_volume_sub_button);
         mScreenshotIcon = getDrawable(R.drawable.ic_sysbar_capture_button);
+        mNavHideIcon = getDrawable(R.drawable.ic_sysbar_hide);//add hide nav 
     }

     public KeyButtonDrawable getBackDrawable() {
@@ -695,7 +704,7 @@ public class NavigationBarView extends FrameLayout implements
         getVolumeAddButton().setImageDrawable(mVolumeAddIcon);
         getVolumeSubButton().setImageDrawable(mVolumeSubIcon);
         getScreenshotButton().setImageDrawable(mScreenshotIcon);
-
+        getNavHideButton().setImageDrawable(mNavHideIcon);//add hide nav 
         updateRecentsIcon();

         // Update IME button visibility, a11y and rotate button always overrides the appearance
@@ -745,6 +754,7 @@ public class NavigationBarView extends FrameLayout implements
         getHomeButton().setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent  ? View.INVISIBLE : View.VISIBLE);
         getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
+        getNavHideButton().setVisibility(View.VISIBLE);//add hide nav 
         notifyActiveTouchRegions();
     }


6.最重要一步,点击事件响应,之前布局的keyCode,当前的keyCode = 101,而我们的屏幕分辨率大小是480x480,所以点击导航栏这个按钮,201可能代表屏幕上某个坐标点,Launcher3布局其他地方会响应点击事件, 建议把keyCode改成999,反正要大于分辨率尺寸!
如果不想采取上面那个方案,建议是用6.1方案
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
case MotionEvent.ACTION_UP:
                final boolean doIt = isPressed() && !mLongClicked;
                setPressed(false);
                final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
                if (showSwipeUI) {
                    if (doIt) {
                        // Apply haptic feedback on touch up since there is none on touch down
                        performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                        playSoundEffect(SoundEffectConstants.CLICK);
                    }
                } else if (doHapticFeedback && !mLongClicked) {
                    // Always send a release ourselves because it doesn't seem to be sent elsewhere
                    // and it feels weird to sometimes get a release haptic and other times not.
                    performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
                }
                if (mCode != KEYCODE_UNKNOWN) {
                    if(mCode == 101){
                        //do it
                    }else if(mCode == 102){
                       ....
                    }
                    if (doIt) {
                        sendEvent(KeyEvent.ACTION_UP, 0);
                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                    } else {
                        sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                    }
                } else {
                    // no key code, just a regular ImageView
                    if (doIt && mOnClickListener != null) {
                        mOnClickListener.onClick(this);
                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                    }
                }
                removeCallbacks(mCheckLongPress);
                break;
        }
   
6.1 新增按钮监听事件响应
首先布局里面的systemui:keyCode="0" ,keycode变为0,
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -177,7 +177,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
     private @TransitionMode int mNavigationBarMode;
     private AccessibilityManager mAccessibilityManager;
     private ContentResolver mContentResolver;
-    private ContentObserver mScreenshotShowObserver;
+    private ContentObserver mScreenshotShowObserver,mHideNavButtonShowObserver;
     private boolean mAssistantAvailable;

     private int mDisabledFlags1;
@@ -233,6 +233,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
     private UiEventLogger mUiEventLogger;
     private boolean mShowOrientedHandleForImmersiveMode;
     private long mLastClickScreenshotTime = 0;
+    private long mLastClickNavHideTime = 0;

     @com.android.internal.annotations.VisibleForTesting
     public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
@@ -454,6 +455,21 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                 Settings.System.getUriFor(Settings.System.SCREENSHOT_BUTTON_SHOW), true,
                 mScreenshotShowObserver, UserHandle.USER_ALL);

+        //addstart
+        mHideNavButtonShowObserver = new ContentObserver(getContext().getMainThreadHandler()) {
+            @Override
+            public void onChange(boolean selfChange) {
+                boolean isShowNavHideButton = Settings.System.getInt(getContext().getContentResolver(), "hide_button_statu", 1) == 1;
+                android.util.Log.d("tww","hide_button_statu:"+isShowNavHideButton);
+                ButtonDispatcher navHideButton = mNavigationBarView.getNavHideButton();
+                navHideButton.setVisibility(isShowNavHideButton ? View.VISIBLE : View.GONE);
+            }
+        };
+        mContentResolver.registerContentObserver(
+                Settings.System.getUriFor("hide_button_statu"), true,
+                mHideNavButtonShowObserver, UserHandle.USER_ALL);
+        //addend
+
         if (savedInstanceState != null) {
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
             mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
@@ -488,6 +504,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
         if(null != mScreenshotShowObserver){
             mContentResolver.unregisterContentObserver(mScreenshotShowObserver);
         }
+        //add text 
+        if(null != mHideNavButtonShowObserver){
+            mContentResolver.unregisterContentObserver(mHideNavButtonShowObserver);
+        }
+        //add text 
     }

     @Override
@@ -1038,6 +1059,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
             screenshotButton.setVisibility(View.GONE);
         }

+        //addstart
+        boolean isShowNavHideButton = Settings.System.getInt(getContext().getContentResolver(), "hide_button_statu", 1) == 1;
+        ButtonDispatcher navHideButton = mNavigationBarView.getNavHideButton();
+        navHideButton.setOnClickListener(this:: navHideClick);
+        if(isShowNavHideButton){
+            navHideButton.setVisibility(View.VISIBLE);
+        }else{
+            navHideButton.setVisibility(View.GONE);
+        }
+        //addend
         ButtonDispatcher volumeAddButton=mNavigationBarView.getVolumeAddButton();
         ButtonDispatcher volumeSubButton=mNavigationBarView.getVolumeSubButton();
         boolean isShowVolumeButton="true".equals(SystemProperties.get("ro.rk.systembar.voiceicon","true"));
@@ -1256,6 +1287,19 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
         mLastClickScreenshotTime = nowTime;
     }

+    //addstart
+    private void navHideClick(View v) {
+        android.util.Log.d("tww","navHideClick");
+        long nowTime = SystemClock.elapsedRealtime();
+        if (nowTime - mLastClickNavHideTime < 2000) {
+            return;
+        }
+        Intent intent = new Intent("ACTION_HIDE_NAVIGATION");
+        getContext().sendBroadcast(intent);
+        mLastClickNavHideTime = nowTime;
+    }
+    //add end
+
     private void onAccessibilityClick(View v) {
         final Display display = v.getDisplay();
         mAccessibilityManager.notifyAccessibilityButtonClicked(

     
7.系统的手势监听,隐藏之后上滑发送显示广播xxx
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);
                              //do it 下滑 add
                          }
                      }
  
                      @Override
                      public void onSwipeFromBottom() {
                          synchronized (mLock) {
                              if (mNavigationBar != null
                                      && mNavigationBarPosition == NAV_BAR_BOTTOM) {
                                  requestTransientBars(mNavigationBar);
                              }
                              checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                              //do it  上滑 add
                          }
                      }
  
                      @Override
                      public void onSwipeFromRight() {
                          final Region excludedRegion = Region.obtain();
                          synchronized (mLock) {
                              mDisplayContent.calculateSystemGestureExclusion(
                                      excludedRegion, null /* outUnrestricted */);
                              final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                      || mNavigationBarPosition == NAV_BAR_RIGHT;
                              if (mNavigationBar != null && sideAllowed
                                      && !mSystemGestures.currentGestureStartedInRegion(
                                              excludedRegion)) {
                                  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 sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                      || mNavigationBarPosition == NAV_BAR_LEFT;
                              if (mNavigationBar != null && sideAllowed
                                      && !mSystemGestures.currentGestureStartedInRegion(
                                              excludedRegion)) {
                                  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 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();
                          }
                      }
  
                      @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);
                      }
                  });
                  
8.创造导航栏和移除导航栏方法
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -164,7 +164,7 @@ public class NavigationBarController implements Callbacks {
         });
     }
     
      public void createNavigationBars(final boolean includeDefaultDisplay,
            RegisterStatusBarResult result) {...
     
     //隐藏导航栏方法变为public 方便调用
-    private void removeNavigationBar(int displayId) {
+    public void removeNavigationBar(int displayId) {
         NavigationBarFragment navBar = mNavigationBars.get(displayId);
         if (navBar != null) {
             View navigationWindow = navBar.getView().getRootView();
             ....

    //或者自己建立一个类似removeNavigationBar add
    public void reomveNavigationBar_2()  {
        Display[] displays = mDisplayManager.getDisplays();
        for (Display display : displays) {
            removeNavigationBar(display.getDisplayId());
        }
    }
    
    
9.具体使用
 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
 
private void HideStatusBar() {
        if (all_hide_bar == 1) return;

        if (mPhoneStatusBarWindow.getVisibility() == View.VISIBLE) {
            mPhoneStatusBarWindow.setVisibility(View.GONE);
        }
    }

private void ShowStatusBar() {
        if (all_hide_bar == 1) return;

        if (mPhoneStatusBarWindow.getVisibility() == View.GONE) {
            mPhoneStatusBarWindow.setVisibility(View.VISIBLE);
        }
}

private boolean flag = true;
private void HideNavigationBar() {
        if (flag) {
            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
            if (mNavigationBarView != null) {
                mNavigationBarController.removeNavigationBar_2();
            }
            flag = false;
        }
    }

private void ShowNavigationBar() {
        //flag 设备重启默认是true,在初始化的时候,已经添加了导航栏,它的作用是防止systemUI初始化时,二次添加导致异常
        if (!flag) {
            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
            if (mNavigationBarView == null) {
                mNavigationBarController.createNavigationBars(true, null);
            }
            flag = true;
        }
} 

Android 12 自定义底部导航栏 - xiaowang_lj - 博客园 (cnblogs.com)

Android12 隐藏状态栏导航栏 - simple雨 - 博客园 (cnblogs.com)

Android 11 关于系统应用发送广播 Sending non-protected broadcast 警告

1.带android:sharedUserId=“android.uid.system” 发送广播时,会出现 Sending non-protected broadcast
2.如果是非系统应用,想要发送一样的广播,也会报错 SecurityException: Permission Denial: not allowed to send broadcast XXX

如何修改:

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

@Override
public boolean isProtectedBroadcast(String actionName) {
    // allow instant applications
    synchronized (mProtectedBroadcasts) {
        if (mProtectedBroadcasts.contains(actionName)) {
            return true;
        } else if (actionName != null) {
            // TODO: remove these terrible hacks
            if (actionName.startsWith("android.net.netmon.lingerExpired")
                    || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
                    || actionName.startsWith("com.android.internal.telephony.data-reconnect")
                    || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
                    //在上面的函数上添加你需要过滤的广播名字
                return true;
            }
        }
    }
    return false;
}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
        String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
    if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
        // Don't yell about broadcasts sent via shell
        return;
    }

    final String action = intent.getAction();
    
    if (isProtectedBroadcast
            || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
            || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
            || Intent.ACTION_MEDIA_BUTTON.equals(action)
            || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
            || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
            || Intent.ACTION_MASTER_CLEAR.equals(action)
            || Intent.ACTION_FACTORY_RESET.equals(action)
            || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
            || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
            || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
            || TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
            || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
            || AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
            || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
        // Broadcast is either protected, or it's a public action that
        // we've relaxed, so it's fine for system internals to send.
        android.util.Log.d("tag","relax");
        return;
    }
    //add
    if(xxx){
    	// we've relaxed, so it's fine for system internals to send.
    	return;
    }
    //end
    
   	...
   	// The vast majority of broadcasts sent from system internals
        // should be protected to avoid security holes, so yell loudly
        // to ensure we examine these cases.
        if (callerApp != null) {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system " + callerApp.toShortString() + " pkg " + callerPackage,
                    new Throwable());
        } else {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system uid " + UserHandle.formatUid(callingUid)
                            + " pkg " + callerPackage,
                    new Throwable());
        }
    }
posted @ 2024-04-13 19:11  僵小七  阅读(164)  评论(0编辑  收藏  举报