系统手势导航-虚拟导航切换

问题讨论-需求场景

何为手势和物理按键、虚拟导航

Android11 开始支持了手势操作,如大家目前手机基本上都是手势操作形式;早期都是物理按键或者虚拟按键的操作。

手势导航和虚拟导航如何选择

系统层面:设置->系统->手势->手势切换

如何应用程序中让用户自己选择,自由选择设置

强制手势或者底部虚拟导航

定制的很多案子,强制使用手势或者底部虚拟导航:手势导航和虚拟导航二选一,那么如何定制客户选择其一时候有要求虚拟导航或者底部导航,不允许修改的。如何不让用户修改。

参考资料

Android导航方式切换
SystemUI导航栏

如何配置导航方式

mtk 、RK 配置都在同一个路径下,修改文件

\frameworks\base\core\res\res\values\config.xml <!-- Controls the navigation bar interaction mode:0: 3 button mode (back, home, overview buttons)1: 2 button mode (back, home buttons + swipe up for overview)2: gestures only for back, home and overview --><integer name="config_navBarInteractionMode">0</integer>

应用层如何设置导航方式

源码分析:

/packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationGestureSettings.java

导航栏切换逻辑在 SystemNavigationGestureSettings.java 文件中

在线源码SystemNavigationGestureSettings.java 源码

获取当前导航方式和设置导航方式 核心代码如下

@VisibleForTesting
202      static String getCurrentSystemNavigationMode(Context context) {
203          if (SystemNavigationPreferenceController.isGestureNavigationEnabled(context)) {
204              return KEY_SYSTEM_NAV_GESTURAL;
205          } else if (SystemNavigationPreferenceController.is2ButtonNavigationEnabled(context)) {
206              return KEY_SYSTEM_NAV_2BUTTONS;
207          } else {
208              return KEY_SYSTEM_NAV_3BUTTONS;
209          }
210      }
211  
212      @VisibleForTesting
213      static void setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key) {
214          String overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
215          switch (key) {
216              case KEY_SYSTEM_NAV_GESTURAL:
217                  overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
218                  break;
219              case KEY_SYSTEM_NAV_2BUTTONS:
220                  overlayPackage = NAV_BAR_MODE_2BUTTON_OVERLAY;
221                  break;
222              case KEY_SYSTEM_NAV_3BUTTONS:
223                  overlayPackage = NAV_BAR_MODE_3BUTTON_OVERLAY;
224                  break;
225          }
226  
227          try {
228              overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);
229          } catch (RemoteException e) {
230              throw e.rethrowFromSystemServer();
231          }
232      }

获取当前导航方式

Settings数据库中:

adb shell settings get Secure navigation_mode

位置:

    frameworks/base/core/java/android/provider/Settings.java/*** Navigation bar mode.*  0 = 3 button*  1 = 2 button*  2 = fully gestural* @hide*/@Readablepublic static final String NAVIGATION_MODE ="navigation_mode";

所以直接通过系统标准API 获取Setting 相关属性值来获取当前导航方式

 public static Mode getNavigationMode(Context context) {try {ContentResolver resolver = context.getApplicationContext().getContentResolver();int mode = Settings.Secure.getInt(resolver, "navigation_mode");if (mode == 0) {return Mode.THREEBUTTON;} else if (mode == 2) {return Mode.GESTURAL;}} catch (Exception e) {e.printStackTrace();}return null;}

设置导航栏

回归到 SystemNavigationGestureSettings.java 类的 setCurrentSystemNavigationMode 方法,最终调用

 overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);

思路:拿到 overlayManager 然后调用 setEnabledExclusiveInCategory 方法即可。

SystemNavigationGestureSettings 类中,overlayManager 获取: 不就是获取OVERLAY_SERVICE 的服务吗

       mOverlayManager = IOverlayManager.Stub.asInterface(ServiceManager.getService(Context.OVERLAY_SERVICE));

在应用中获取思路

Object mIOverlayManager = context.getSystemService("overlay")

然后调用 setEnabledExclusiveInCategory 方法, 但是服务的方法本身不是对外释放的,那就反射。

@Overridepublic boolean setEnabledExclusiveInCategory(@Nullable String packageName,final int userIdArg) {if (packageName == null) {return false;}try {traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);final OverlayIdentifier overlay = new OverlayIdentifier(packageName);final int realUserId = handleIncomingUser(userIdArg,"setEnabledExclusiveInCategory");enforceActor(overlay, "setEnabledExclusiveInCategory", realUserId);final long ident = Binder.clearCallingIdentity();try {synchronized (mLock) {try {mImpl.setEnabledExclusive(overlay,true /* withinCategory */, realUserId).ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);return true;} catch (OperationFailedException e) {return false;}}} finally {Binder.restoreCallingIdentity(ident);}} finally {traceEnd(TRACE_TAG_RRO);}}

规避客户切换导航栏

在默认了系统导航栏 上面已经给出了用户可以切换导航栏的。 很多产品在默认导航栏后不允许客户切换导航方式的。 那么就需要在系统设置里面规避,隐藏切换方式。

涉及到的源码修改:

/packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationPreferenceController.javagetAvailabilityStatus 方法,修改如下:@Overridepublic int getAvailabilityStatus() {//  return isGestureAvailable(mContext) ? UNSUPPORTED_ON_DEVICE : UNSUPPORTED_ON_DEVICE;return isGestureAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;}   
  如果允许设置里面修改,用默认的:return isGestureAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;如果不允许修改,那么 返回如下://  return isGestureAvailable(mContext) ? UNSUPPORTED_ON_DEVICE : UNSUPPORTED_ON_DEVICE;

其它扩展知识

导航栏高度:navigation_bar_height

frameworks/base/core/res/res/values/dimens.xml  <!-- Height of the bottom navigation / system bar. --><dimen name="navigation_bar_height">48dp</dimen><!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height --><dimen name="navigation_bar_height_landscape">48dp</dimen>

涉及到部分图示和工具类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设置和获取手导航


import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;public class NavigationHelper {/*** 设置导航模式** @param context* @param mode    GESTURAL:手势 TWOBUTTON:二按钮 THREEBUTTON:三按钮*/public static void setNavigationMode(Context context, Mode mode) {try {//  Object mIOverlayManager = context.getSystemService("overlay");@SuppressLint("WrongConstant") Object mIOverlayManager = context.getSystemService(Context.OVERLAY_SERVICE);Method setEnabledExclusiveInCategory = mIOverlayManager.getClass().getMethod("setEnabledExclusiveInCategory", String.class, UserHandle.class);setEnabledExclusiveInCategory.setAccessible(true);String overlayPackage = "com.android.internal.systemui.navbar.gestural";if (mode == Mode.TWOBUTTON) {overlayPackage = "com.android.internal.systemui.navbar.twobutton";} else if (mode == Mode.THREEBUTTON) {overlayPackage = "com.android.internal.systemui.navbar.threebutton";}UserHandle userHandle = (UserHandle) newInstance(UserHandle.class, new Class[]{int.class}, 0);setEnabledExclusiveInCategory.invoke(mIOverlayManager, overlayPackage, userHandle);} catch (Throwable e) {e.printStackTrace();}}/*** 获取导航模式* @param context* @return*/public static Mode getNavigationMode(Context context) {try {ContentResolver resolver = context.getApplicationContext().getContentResolver();int mode = Settings.Secure.getInt(resolver, "navigation_mode");if (mode == 0) {return Mode.THREEBUTTON;} else if (mode == 2) {return Mode.GESTURAL;}} catch (Exception e) {e.printStackTrace();}return null;}/*** 开启经典导航模式** @param enable*/public static void setClassicNavigationMode(boolean enable) {try {Class c = Class.forName("android.os.SystemProperties");Method method = c.getMethod("set", String.class, String.class);method.setAccessible(true);method.invoke(null, "persist.sys.classic.navigation.mode", String.valueOf(enable));} catch (Throwable e) {e.printStackTrace();}}private static Object newInstance(Class clazz, Class[] argsType, Object... args) {Object instance = null;try {Constructor constructor = clazz.getConstructor(argsType);constructor.setAccessible(true);instance = constructor.newInstance(args);} catch (Throwable e) {e.printStackTrace();}return instance;}public enum Mode {GESTURAL,TWOBUTTON,THREEBUTTON}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识java(4)

今天给大家分享一下java中内置类型定义时的一些要点&#xff0c;我已经整理成笔记&#xff0c;现在分享给大家。 整型变量: 注:在定义int变量时,所赋值不能超过int的范围; 了 intd:1234567890127411编译时报错,初值超过胃int 当你赋值的过而值大于这个变量能够保存的最大值…

Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:电影院后台管理系统(前后端源码 + 数据库 sql 脚本)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 项目介绍 2.0 用户登录功能 3.0 用户管理功能 4.0 影院管理功能 5.0 电影管理功能 6.0 影厅管理功能 7.0 电影排片管理功能 8.0 用户评论管理功能 9.0 用户购票功…

蓝桥杯嵌入式入门指南-ADC【6】

tips:可以不用开启过采样 adc读取函数 float adc_read(ADC_HandleTypeDef *hadc) {uint16_t adc_val;float adc_f;HAL_ADC_Start (hadc);adc_val HAL_ADC_GetValue(hadc);adc_f adc_val*3.3f/4096.0f;return adc_f; }setup()初始化 HAL_ADCEx_Calibration_Start(&hadc2 …

【头歌实训:递归实现斐波那契数列】

头歌实训&#xff1a;递归实现斐波那契数列 文章目录 任务描述相关知识递归相关知识递归举例何时使用递归定义是递归的数据结构是递归的问题的求解方法是递归的 编程要求测试说明源代码&#xff1a; 任务描述 本关任务&#xff1a;递归求解斐波那契数列。 相关知识 为了完成…

【CSP CCF记录】201803-2第13次认证 碰撞的小球

题目 样例输入1 3 10 5 4 6 8 样例输出1 7 9 9 样例输入2 10 22 30 14 12 16 6 10 2 8 20 18 4 样例输出2 6 6 8 2 4 0 4 12 10 2 思路 梳理题意&#xff0c;本题主要考虑三种情况&#xff1a; 1.小球正常运动 2.小球抵达线段两段 3.两个小球在线段某位置相撞 前两种情况很…

ML 系列:第 35 节 - 机器学习中的数据可视化

ML 系列&#xff1a;第 35 天 - 机器学习中的数据可视化 文章目录 一、说明二、数据可视化2.1 直方图2.2 箱线图2.3 散点图2.4 条形图2.5 线图2.6 热图 三、结尾 一、说明 描述性统计和数据可视化是理解和解释机器学习数据的基础。它们有助于总结和直观地呈现数据&#xff0c…

数字化转型背景下,高职院校计算机网络应用的革新策略

在当今信息化时代&#xff0c;计算机网络已经成为高职院校教育不可或缺的一部分&#xff0c;它不仅极大地丰富了教育资源&#xff0c;提高了交流的便捷性&#xff0c;还催生了多样化的教学模式。对于高职院校来说&#xff0c;加强计算机网络应用的建设不仅是顺应时代潮流的必然…

【C/C++】数据库链接入门教程:从零开始的详细指南!MySQL集成与操作

文章目录 环境配置&#xff1a;搭建开发环境的基础步骤2.1 安装MySQL数据库2.2 配置C/C开发环境2.3 下载并安装MySQL Connector/C 基础操作&#xff1a;实现C/C与MySQL的基本交互3.1 建立数据库连接3.2 执行SQL语句3.3 处理查询结果 进阶技巧&#xff1a;提升数据库操作效率与安…

漫谈推理谬误——错误因果

相关文章 漫谈推理谬误——错误假设-CSDN博客文章浏览阅读736次&#xff0c;点赞22次&#xff0c;收藏3次。在日常生活中&#xff0c;我们会面临各种逻辑推理&#xff0c;有些看起来一目了然&#xff0c;有些非常的科学严谨&#xff0c;但也有很多似是而非&#xff0c;隐藏了陷…

redis中的哨兵

redis中的哨兵 一、哨兵机制的概念二、redis哨兵的部署2.1 docker的安装2.2 编排redis主从节点2.3 配置哨兵节点 三、redis哨兵的选举机制3.1 redis-master宕机之后的情况3.2 重启redis-master后的情况 四、redis哨兵机制的原理4.1主观下线4.2客观下线4.3选举leader节点4.4选出…

如何在 IIS 上部署 .NET Core 应用程序 ?

在 Internet 信息服务 (IIS) 上部署 .NET Core 应用程序起初可能看起来令人生畏&#xff0c;但只要步骤正确&#xff0c;它就是一个简单的过程。本指南将引导您在 IIS 上部署 .NET Core 应用程序。 Step 1: 安装 .NET Core Hosting Bundle (1) 前往官方下载页面 .NET downloa…

蓝桥杯每日真题 - 第24天

题目&#xff1a;&#xff08;货物摆放&#xff09; 题目描述&#xff08;12届 C&C B组D题&#xff09; 解题思路&#xff1a; 这道题的核心是求因数以及枚举验证。具体步骤如下&#xff1a; 因数分解&#xff1a; 通过逐一尝试小于等于的数&#xff0c;找到 n 的所有因数…

【前端】Next.js 服务器端渲染(SSR)与客户端渲染(CSR)的最佳实践

关于Next.js 服务器端渲染&#xff08;SSR&#xff09;与客户端渲染&#xff08;CSR&#xff09;的实践内容方面&#xff0c;我们按下面几点进行阐述。 1. 原理 服务器端渲染 (SSR): 在服务器上生成完整的HTML页面&#xff0c;然后发送给客户端。这使得用户在首次访问时能够…

【机器学习】机器学习的基本分类-监督学习-逻辑回归-对数似然损失函数(Log-Likelihood Loss Function)

对数似然损失函数&#xff08;Log-Likelihood Loss Function&#xff09; 对数似然损失函数是机器学习和统计学中广泛使用的一种损失函数&#xff0c;特别是在分类问题&#xff08;例如逻辑回归、神经网络&#xff09;中应用最为广泛。它基于最大似然估计原理&#xff0c;通过…

基于BERT的语义分析实现

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

HarmonyOS NEXT应用开发,关于useNormalizedOHMUrl选项的坑

起因是这样的&#xff1a;我这库打包发布出问题了&#xff0c;这个有遇到的吗&#xff1f; 源码里面就没有 request .d.ts,这打包后哪来个这文件&#xff1f;且漏掉了其他文件。 猫哥csdn.yyz_1987 为啥我打包的har里面&#xff0c;只有接口&#xff0c;没有具体实现呢&#x…

单点登录原理

允许跨域–>单点登录。 例如https://www.jd.com/ 同一个浏览器下&#xff1a;通过登录页面产生的cookie里的一个随机字符串的标识&#xff0c;在其他子域名下访问共享cookie获取标识进行单点登录&#xff0c;如果没有该标识则返回登录页进行登录。 在hosts文件下面做的域名…

基于Java的小程序电商商城开源设计源码

近年来电商模式的发展越来越成熟&#xff0c;基于 Java 开发的小程序电商商城开源源码&#xff0c;为众多开发者和企业提供了构建个性化电商平台的有力工具。 基于Java的电子商城购物平台小程序的设计在手机上运行&#xff0c;可以实现管理员&#xff1b;首页、个人中心、用户…

Linux查看网络基础命令

文章目录 Linux网络基础命令1. ifconfig 和 ip一、ifconfig命令二、ip命令 2. ss命令一、基本用法二、常用选项三、输出信息四、使用示例 3. sar 命令一、使用sar查看网络使用情况 4. ping 命令一、基本用法二、常用选项三、输出结果四、使用示例 Linux网络基础命令 1. ifconf…

SpringMVC工作原理【流程图+文字详解SpringMVC工作原理】

SpringMVC工作原理 前端控制器&#xff1a;DispactherServlet处理器映射器&#xff1a;HandlerMapping处理器适配器&#xff1a;HandlerAdapter处理器&#xff1a;Handler&#xff0c;视图解析器&#xff1a;ViewResolver视图&#xff1a;View 首先用户通过浏览器发起HTTP请求…