记录修改系统默认导航模式

公司内部的一个ROM,基于高通平台的,默认为手势导航,即设置-系统-默认选中手势导航,现在需要改成默认“三按钮”导航。

通过Settings的源码,在手动切换导航模式的时候会调用SystemNavigationGestureSettings.java的以下方法

`static void setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key) {
        String overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
        switch (key) {
            case KEY_SYSTEM_NAV_GESTURAL:
                overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
                break;
            case KEY_SYSTEM_NAV_2BUTTONS:
                overlayPackage = NAV_BAR_MODE_2BUTTON_OVERLAY;
                break;
            case KEY_SYSTEM_NAV_3BUTTONS:
                overlayPackage = NAV_BAR_MODE_3BUTTON_OVERLAY;
                break;
        }

        try {
            overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }`

其中,NAV_BAR_MODE_GESTURAL_OVERLAY,NAV_BAR_MODE_2BUTTON_OVERLAY,NAV_BAR_MODE_3BUTTON_OVERLAY这三个常量代表三个overlay的包名,在源码里可以找到对应的apk
frameworks/base/packages/overlays/NavigationBarModeGesturalOverlay
frameworks/base/packages/overlays/NavigationBarMode2ButtonOverlay
frameworks/base/packages/overlays/NavigationBarMode3ButtonOverlay

setEnabledExclusiveInCategory就是告诉系统使用哪个overlay的资源,这里是切换的时候直接传入overlay的包名就可以了。但这里我们需要找到的是初始化的时候,系统使用的是哪个overlay的资源

未修改前,我们是默认手势导航的,刷完机,可以使用命令行:adb shell dumpsys overlay
在这里插入图片描述查看当前系统所有overlay资源的使用情况
在这里插入图片描述此处我们可以看到对应NavigationBarModeGesturalOverlay这个overlay的一些配置信息,其中一个重要的属性mIsEnabled为true,表示当前系统使用的是这个overlay包的资源,该文件里还能找到对应其他两个overlay的配置信息,他们的mIsEnabled都为false.

关于Overlay的机制,本文不详细展开,有兴趣的同学自己去跟源码,系统启动的时候,OverlayManagerService这个服务会被拉起,该服务会注册以下广播

private final class UserReceiver extends BroadcastReceiver {
522          @Override
523          public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
524              final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
525              switch (intent.getAction()) {
526                  case ACTION_USER_ADDED:
527                      if (userId != UserHandle.USER_NULL) {
528                          try {
529                              traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
530                              synchronized (mLock) {
531                                  updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId));
532                              }
533                          } finally {
534                              traceEnd(TRACE_TAG_RRO);
535                          }
536                      }
537                      break;
538  
539                  case ACTION_USER_REMOVED:
540                      if (userId != UserHandle.USER_NULL) {
541                          try {
542                              traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED");
543                              synchronized (mLock) {
544                                  mImpl.onUserRemoved(userId);
545                                  mPackageManager.forgetAllPackageInfos(userId);
546                              }
547                          } finally {
548                              traceEnd(TRACE_TAG_RRO);
549                          }
550                      }
551                      break;
552                  default:
553                      // do nothing
554                      break;
555              }
556          }
557      }

用于监听overlay apk的安装,其中mImpl为OverlayManagerServiceImpl对象,初始化如下:

mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
                      OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());

在看看getDefaultOverlayPackages的实现:

private static String[] getDefaultOverlayPackages() {
346          final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
347          if (TextUtils.isEmpty(str)) {
348              return EmptyArray.STRING;
349          }
350  
351          final ArraySet<String> defaultPackages = new ArraySet<>();
352          for (String packageName : str.split(";")) {
353              if (!TextUtils.isEmpty(packageName)) {
354                  defaultPackages.add(packageName);
355              }
356          }
357          return defaultPackages.toArray(new String[defaultPackages.size()]);
358      }

其中,DEFAULT_OVERLAYS_PROP值如下

 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";

在回到该方法mImpl.updateOverlaysForUser(userId)

 // Enable the default overlay if its category does not have a single overlay enabled.
212          for (final String defaultOverlay : mDefaultOverlays) {
213              try {
214                  // OverlayConfig is the new preferred way to enable overlays by default. This legacy
215                  // default enabled method was created before overlays could have a name specified.
216                  // Only allow enabling overlays without a name using this mechanism.
217                  final OverlayIdentifier overlay = new OverlayIdentifier(defaultOverlay);
218  
219                  final OverlayInfo oi = mSettings.getOverlayInfo(overlay, newUserId);
220                  if (!enabledCategories.contains(oi.category)) {
221                      Slog.w(TAG, "Enabling default overlay '" + defaultOverlay + "' for target '"
222                              + oi.targetPackageName + "' in category '" + oi.category + "' for user "
223                              + newUserId);
224                      mSettings.setEnabled(overlay, newUserId, true);
225                      if (updateState(oi, newUserId, 0)) {
226                          CollectionUtils.add(updatedTargets,
227                                  new PackageAndUser(oi.targetPackageName, oi.userId));
228                      }
229                  }
230              } catch (OverlayManagerSettings.BadKeyException e) {
231                  Slog.e(TAG, "Failed to set default overlay '" + defaultOverlay + "' for user "
232                          + newUserId, e);
233              }
234          }

此处的mDefaultOverlays,就是刚刚从OverlayManagerService中通过构造方法传进来的这个值:
private static final String DEFAULT_OVERLAYS_PROP = “ro.boot.vendor.overlay.theme”,该方法内部调用mSettings.setEnabled把对应的overlay的mIsEnabled属性设为true,从而使系统用该overlay的资源,所以找到该属性赋值的地方,在源码里面全局搜索ro.boot.vendor.overlay.theme,会在vendor下面找到一个mk配置文件,给该属性赋了值
在这里插入图片描述最后把com.android.internal.systemui.navbar.gestural这个包名改为三按钮导航的overlay包名com.android.internal.systemui.navbar.threebutton就可以了.

重新编译,见证奇迹的时刻…

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值