首页 > 其他分享 >Android 11 导航栏添加一个虚拟按钮--问题合集

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

时间:2024-04-13 19:23:56浏览次数:15  
标签:11 -- void ACTION add action Android null public

导航栏添加一个虚拟按钮

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

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

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;
        }
        
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 onm ouseHoverAtTop() {
                          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 onm ouseHoverAtBottom() {
                          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 onm ouseLeaveFromEdge() {
                          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());
        }
    }

标签:11,--,void,ACTION,add,action,Android,null,public
From: https://www.cnblogs.com/kato-T/p/18133234

相关文章

  • @Resource和@Autowired注解
    @Resource和@Autowired注解都是用来实现依赖注入的。只是@AutoWried按bytype自动注入,而@Resource默认按byName自动注入。@Resource有两个重要属性,分别是name和typespring将name属性解析为bean的名字,而type属性则被解析为bean的类型。所以如果使用name属性,则使用byName的自动注......
  • Jeecg安装记录(docker)
    Linux安装1.1Linux安装略1.2SSH连接Linux使用xshell略使用SSHpowershell连接Linux虚拟机_powershell连接虚拟机命令-CSDN博客本地环境安装java8MavenIDEA虚拟机环境安装3.1docker安装Ubuntu·Docker--从入门到实践卸载旧版本旧版本的Dock......
  • VM虚拟机显示“客户机操作系统已禁用cpu”及“该虚拟机要求使用 AVX2,但 AVX 不存在”
    版本:VM:15.5.7build-17171714虚拟机:rhel-8.8-x86_64-dvd地址:D:\Users\q2383\Documents\VirtualMachines\RedHatEnterpriseLinux864位\RedHatEnterpriseLinux864位.vmx问题:客户机操作系统已禁用cpu1.添加内容点击查看代码.encoding="GBK"config.version=......
  • C# NModbus 4 demo
    1.添加modbus程序包 2.创建 ModbusSerialMaster 实例对象 privatestaticModbusSerialMasterCreateModbusRtu(){SerialPortport=newSerialPort();port.PortName="COM11";port.BaudRate=9600;......
  • Go文档:Release History(发布历史)
    本文更新于2024-03-22。官方文档:https://go.dev/doc/devel/release目录泛型go1.22.0(2024-02-06)go1.21.0(2023-08-08)go1.20(2023-02-01)go1.19(2022-08-02)go1.18(2022-03-15)模块go1.17(2021-08-16)go1.16(2021-02-16)go1.15(2020-08-11)go1.14(2020-02-25)go1.13(......
  • 实验1—盗版音乐APP
    一、墨刀、Axure、Mockplus等原型设计工具的各自的适用领域及优缺点1、墨刀适用领域:墨刀主要专注于移动应用的原型设计,非常适合为iOS和Android平台创建高保真度的原型。优点:墨刀的操作效率高,易于上手,同时提供丰富的动效设计功能。它还支持通过二维码分享原型,使得团队协作更加......
  • Docker+Net8运行https
    环境:win11,docker4.28.0,Net8。使用windows版docker 跑老外的run-aspnetcore-microservices 这个分布式项目时,最开始直接运行会遇到这个问题。中间也试了几种方法,有ok也有不行的,有些较为麻烦。Net8开始Docker 端口 默认端口8080了下面是我的1生成pfx文件d......
  • [深度学习]多层感知机(MLP)
    多层感知机(MLP)1.单层感知机1.1感知机线性回归输出的是一个实数,感知机输出的是一个离散的类。1.2训练感知机①如果分类正确的话y<w,x>为正数,负号后变为一个正数,和\(0\)取\(max\)之后得\(0\),则梯度不进行更新②如果分类错了,y<w,x>为负数,的判断条件成立,就进行梯度更新。......
  • Veriadic templates
    Veriadictemplates数量不定的模板参数声明方式:#pragmaonce#ifndef__VARIADICT__#define__VARIADICT__​/*为什么需要定义这个空函数,因为传参到最后传入最后一位参数时后面的一组参数已经没有了.就是0所以这个版本就是没有参数的.当最后一个变成0个的时候调用的是空方法*/......
  • C与C++在函数和数据的比较
    C与C++在函数和数据的比较CData(struct)数据是一个类型->根据数据的类型创建出真正的数据Function函数就是用来处理数据的缺陷:语言没提供关键字.所以数据是全局的->各个函数都可以处理数据C++Data将数据和处理这些数据的函数包裹在一起,其他函数看不到其他函数处理......