IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android R 系统设置导航模式NavigationBar的流程分析 -> 正文阅读

[移动开发]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();
        });
    }
}

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-22 14:48:20  更:2021-09-22 14:48:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 12:02:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码