Android R 系统设置导航模式NavigationBar的流程分析

系统设置中会设置手势导航模式 在Setting中可以进行设置查看原生代码发现系统导航类设置为 SystemNavigationGestureSettings 其中SystemNavigationGestureSettings是Preference定义在accessibility_settings.xml中在XML中对应的控制类是SystemNavigationPreferenceController通过代码查看到SystemNavigationGestureSettings.java继承之RadioButtonPickerFragment

涉及路径:

packages/apps/Settings/src/com/android/settings/widget/RadioButtonPickerFragment.java
packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
frameworks/base/core/java/android/content/om/OverlayManager.java
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java

我们先查看RadioButtonPickerFragment.java 中的点击按钮的实现,通过 setDefaultKey

抽象类调用到SystemNavigationGestureSettings中的setDefaultKey方法。

/packages/apps/Settings/src/com/android/settings/widget/RadioButtonPickerFragment.java

@Override
public void onRadioButtonClicked(RadioButtonPreference selected) {
    final String selectedKey = selected.getKey();
    onRadioButtonConfirmed(selectedKey);
}

protected void onRadioButtonConfirmed(String selectedKey) {
    //执行SystemNavigationGestureSettings 中的setDefaultKey方法 
    final boolean success = setDefaultKey(selectedKey);
    if (success) {
        //更新按钮
        updateCheckedState(selectedKey);
    }
    onSelectionPerformed(success);
}

//抽象方法,调用子类
protected abstract boolean setDefaultKey(String key);
SystemNavigationGestureSettings.java中的setDefaultKey方法

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

@Override
protected boolean setDefaultKey(String key) {
//通过使用overlaymanager设置对应不同的模式
 setCurrentSystemNavigationMode(mOverlayManager, key);
 //根据不同的navigationmode 设置不同的video资源
 setIllustrationVideo(mVideoPreference, key);
 //打开教程说明
 if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key) && (
isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) {
Intent intent = new Intent(getActivity(), SettingsTutorialDialogWrapperActivity.class);
 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 startActivity(intent);
 }
return true;
}

setCurrentSystemNavigationMode方法为手势导航和导航按钮两件三件的切换

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();
    }
}

接了下来我我们查看按键切换的OverlayManager.java类
frameworks/base/core/java/android/content/om/OverlayManager.java

public void setEnabledExclusiveInCategory(@NonNull final String packageName,
        @NonNull UserHandle user) throws SecurityException, IllegalStateException {
    try {
        //执行 IOverlayManager.aidl中setEnabledExclusiveInCategory方法实际是OverlayManagerService.java
        if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) {
            throw new IllegalStateException("setEnabledExclusiveInCategory failed");
        }
    } catch (SecurityException e) {
        rethrowSecurityException(e);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

可以看到mService.setEnabledExclusiveInCategory 中mService 指的是 IOverlayManager.aidl实现他的地方是OverlayManagerService.java
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java

private final IBinder mService = new IOverlayManager.Stub() {
//省略代码
@Override
public boolean setEnabledExclusiveInCategory(@Nullable String packageName,
final int userIdArg) {

try {
//省略代码
try {
synchronized (mLock) {
//转到OverlayManagerServiceImpl.java中
return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
realUserId);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
//省略代码
}

mImpl.setEnabledExclusive 重的 mImpl 指的是OverlayManagerServiceImpl.Java 中的接口方法

interface OverlayChangeListener {

    /**
     * An event triggered by changes made to overlay state or settings as well as changes that
     * add or remove target packages of overlays.
     **/
    void onOverlaysChanged(@NonNull String targetPackage, int userId);
}

实现 OverlayChangeListener中 onOverlaysChanged 方法的还是 OverlayManagerService.java

private final class OverlayChangeListener
implements OverlayManagerServiceImpl.OverlayChangeListener {
@Override
public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
//更新Setting文件
schedulePersistSettings();
FgThread.getHandler().post(() -> {
// MIUI MOD: START
final int[] liveUserIds;
if (targetPackageName != null && targetPackageName.equals("android")) {
liveUserIds = mUserManager.getUserIds();
} else {
liveUserIds = new int[] {userId};
}

for (int targetUserId : liveUserIds) {
updateAssets(targetUserId, targetPackageName);

final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
//只有注册了 FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 广播的才能接收到
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

try {
//发送 ACTION_OVERLAY_CHANGED 广播 ,
ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
targetUserId);
} catch (RemoteException e) {
// Intentionally left empty.
}
}
// END
});
}
}

在framework/base下面 NavigationModeController.java 注册了此广播监听

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java

public void updateCurrentInteractionMode(boolean notify) {
mCurrentUserContext = getCurrentUserContext();
//当前导航栏手势
int mode = getCurrentInteractionMode(mCurrentUserContext);
if (mode == NAV_BAR_MODE_GESTURAL) {
//如果当前是手势导航执行
switchToDefaultGestureNavOverlayIfNecessary();
}
mUiBgExecutor.execute(() ->
Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
Secure.NAVIGATION_MODE, String.valueOf(mode)));
//回调通知onNavigationModeChanged 这里我们不关心其他应用,只需要关心 NavigationBarFragment.java
//中的回调既可以
if (notify) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNavigationModeChanged(mode);
}
}
}

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java 

NavigationBarFragment.java 更新布局,重新加载布局.

@Override
public void onNavigationModeChanged(int mode) {
    mNavBarMode = mode;
    //更新 PinningGestures 导航
    updateScreenPinningGestures();

    int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
    if (userId != UserHandle.USER_SYSTEM) {
        mHandler.post(() -> {
            //重新加载fragment,更新布局文件
            FragmentHostManager fragmentHost = FragmentHostManager.get(mNavigationBarView);
            fragmentHost.reloadFragments();
        });
    }
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值