提示:Android12-左右滑动手势导航失效-解决方案:记录一次查错经验分享
文章目录
- 前言-需求-问题
- 一、参考资料
- 二、修改文件
- 三、解决方案
- 四、经验分享-知识点扩充
-
- 如何实现系统默认手势导航
- ro.boot.vendor.overlay.theme-属性本质
- [Android 原生 4 个标准导航 overlay](#Android 原生 4 个标准导航 overlay)
-
- 1)三按键模式(经典)
- [2)双按键 + 上滑(旧款精简)](#2)双按键 + 上滑(旧款精简))
- 3)纯手势导航
- [4)无导航栏(部分平板 / 电视)](#4)无导航栏(部分平板 / 电视))
- [ro.boot.vendor.overlay.theme 属性配置-对照表](#ro.boot.vendor.overlay.theme 属性配置-对照表)
- 个人项目开发经验分享-如何配置属性和overlay
- 总结
前言-需求-问题
自己在开发项目当中,随着需求增多、改来改去的突然发现手势左右滑动导航失效了,查错验证到底哪里导致了手势导航左右滑动手势失效的问题。
解决方案思路:
- 要么去掉需求,一个一个的来重新对接,这是常规思路、也是最搞笑思路。当然在系统开发过程中可能比较慢,要一个一个验证。但是也是最靠谱的解决方案。
- 直接死磕问题-死磕解决方案:既然不知道哪里导致的,那就找导致问题的根本原因,结合代码直接修改,不要去分析问题原因的根源, 看是否用这个思路来解决实际问题。

但是底部导航手势是OK的,能够上划到最近历史任务界面。
实际上,自己把左右滑动手势问题解决OK了,又发现底部导航手势无用了,如下:

一、参考资料
这里结合之前总结的部分手势相关的文章,可参考,属于手势相关内容模块,可借鉴参考部分基础知识和延伸扩展知识:
MTK Android12 SystemUI 手势导航 隐藏导航栏底部布局
系统手势导航-虚拟导航切换
Android12-手势导航-三按键导航切换-三按键底部导航5秒消失功能实现
MTK - Android12 默认唯一Launcher作为HOME程序-手势导航左右滑动无效问题 : 多Launcher下,设置了默认的Launcher 下左右滑动手势无效问题
二、修改文件
java
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
三、解决方案
1、解决左右滑动无效问题

java
public void onSwipeFromLeft() {
Log.d(TAG,"================onSwipeFromLeft==============");
final Region excludedRegion = Region.obtain();
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
final boolean excluded =
mSystemGestures.currentGestureStartedInRegion(excludedRegion);
Log.d(TAG,"========mNavigationBar:"+mNavigationBar);
Log.d(TAG,"========mNavigationBarPosition:"+mNavigationBarPosition);
Log.d(TAG,"========NAV_BAR_LEFT:"+NAV_BAR_LEFT);
Log.d(TAG,"========excluded:"+excluded);
Log.d(TAG,"========mNavigationBarAlwaysShowOnSideGesture:"+mNavigationBarAlwaysShowOnSideGesture);
if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
|| !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
Log.d(TAG,"==============requestTransientBars(mNavigationBar)=====");
requestTransientBars(mNavigationBar);
}
if (mNavigationBar != null) {
Log.d(TAG,"================mNavigationBar != null=======requestTransientBars=====");
requestTransientBars(mNavigationBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
}
excludedRegion.recycle();
}
就是在 onSwipeFromLeft方法中查错,让 requestTransientBars(mNavigationBar);能够得到执行。 如上给了日志打印,对比来看就知道为什么左右滑动无效,这就是根源。【那根源找到了,那为什么会出现这样的问题呢?: 因为屏幕我们进行了旋转,所有左右滑动位置和实际的不一致,适配下或者直接干,让requestTransientBars 方法得到执行,不要拦截掉了。】
2、解决底部导航上划手势失效问题

在 requestTransientBars 方法中,屏蔽掉判断条件中 return 的部分,直接屏蔽掉。
java
private void requestTransientBars(WindowState swipeTarget) {
if (!mService.mPolicy.isUserSetupComplete()) {
// Swipe-up for navigation bar is disabled during setup
return;
}
final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
final InsetsControlTarget controlTarget = provider != null
? provider.getControlTarget() : null;
if (controlTarget == null || controlTarget == getNotificationShade()) {
// No transient mode on lockscreen (in notification shade window).
// return;
}
final @InsetsType int restorePositionTypes =
(controlTarget.getRequestedVisibility(ITYPE_NAVIGATION_BAR)
? Type.navigationBars() : 0)
| (controlTarget.getRequestedVisibility(ITYPE_STATUS_BAR)
? Type.statusBars() : 0)
| (mExtraNavBarAlt != null && controlTarget.getRequestedVisibility(
ITYPE_EXTRA_NAVIGATION_BAR)
? Type.navigationBars() : 0)
| (mClimateBarAlt != null && controlTarget.getRequestedVisibility(
ITYPE_CLIMATE_BAR)
? Type.statusBars() : 0);
if (swipeTarget == mNavigationBar
&& (restorePositionTypes & Type.navigationBars()) != 0) {
// Don't show status bar when swiping on already visible navigation bar.
// But restore the position of navigation bar if it has been moved by the control
// target.
// controlTarget.showInsets(Type.navigationBars(), false);
// return;
}
if (controlTarget.canShowTransient()) {
// Show transient bars if they are hidden; restore position if they are visible.
mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
controlTarget.showInsets(restorePositionTypes, false);
} else {
// Restore visibilities and positions of system bars.
Log.d(TAG,"=============== Restore visibilities and positions of system bars.=========");
controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
// To further allow the pull-down-from-the-top gesture to pull down the notification
// shade as a consistent motion, we reroute the touch events here from the currently
// touched window to the status bar after making it visible.
if (swipeTarget == mStatusBar) {
final boolean transferred = mStatusBar.transferTouch();
if (!transferred) {
Slog.i(TAG, "Could not transfer touch to the status bar");
}
}
}
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
四、经验分享-知识点扩充
如何实现系统默认手势导航
在 系统手势导航-虚拟导航切换 有相关介绍
配置文件修改-config.xml
路径:\frameworks\base\core\res\res\values\config.xml
java
\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">2</integer>
配置文件-主题-修改-device.mk
路径:device/mediatek/system/common/device.mk
配置属性:ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.gestural
ro.boot.vendor.overlay.theme-属性本质
java
ro.boot.vendor.overlay.theme=包名
ro.boot.xxx:开机时init阶段设定,只读,用于默认启用哪个RRO overlay包。vendor.overlay.theme:系统把它当作 "默认主题 / 导航模式overlay" 入口。- 这里的值都是
SystemUI导航栏模式专用overlay包名。
Android 原生 4 个标准导航 overlay
1)三按键模式(经典)
java
ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.threebutton
- 对应:3 键导航(返回 +
Home+ 多任务) config:config_navBarInteractionMode = 0- 屏幕底部常驻三个按钮。
2)双按键 + 上滑(旧款精简)
java
ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.twobutton
- 对应:2 键(返回 +
Home)+ 上滑出多任务 config:config_navBarInteractionMode = 1- 底部两个键,上滑触发
overview。
3)纯手势导航
java
ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.gestural
- 对应:全屏手势:左 / 右滑返回、底部上滑
Home、长上滑多任务 config:config_navBarInteractionMode = 2- 底部无常驻按键条,只有手势感应区。
4)无导航栏(部分平板 / 电视)
java
ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.no_navbar
- 对应:完全不显示导航栏
- config:内部强制隐藏 nav bar
- 一般用于纯电视 / 投影设备。
ro.boot.vendor.overlay.theme 属性配置-对照表
| 属性值 | 导航模式 | config 数值 | 表现 |
|---|---|---|---|
| threebutton | 三按键 | 0 | 常驻 3 键 |
| twobutton | 双按键 + 上滑 | 1 常驻 2 键 | |
| gestural | 纯手势 | 2 | 无按键,全手势 |
| no_navbar | 无导航栏 | - | 完全隐藏 |
个人项目开发经验分享-如何配置属性和overlay
如上讲解了部分手势导航的知识点,那么实际开发项目中常见的两种需求:配置三按键导航(添加定制部分菜单)、配置手势导航(可能左右手势都有自己的功能定义),那么如何配置。
配置底部虚拟导航栏:
默认就是这个配置。那么不要去配置overlay属性,直接配置config.xml文件中的config_navBarInteractionMode 值为2 即可。
配置手势导航
- 在 路径:
device/mediatek/system/common/device.mk配置属性:ro.boot.vendor.overlay.theme=com.android.internal.systemui.navbar.gestural - 在路径:
\frameworks\base\core\res\res\values\config.xml配置config_navBarInteractionMode值为2
java
\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">2</integer>
总结
- 这里通过手势失效问题,给出解决方案
- 通过手势失效,延伸了解、理解 手势和虚拟导航切换配置方案的介绍
- 核心源码
DisplayPolicy并没有去研究,这是一个WMS 及其重要的核心策略类,后续有机会在通过案例理解。