🎊 屏蔽app无障碍服务显示

屏蔽app无障碍服务显示

问题描述: 1)部分app 存在无障碍服务功能,需要关闭 2)对于客户自研App,自己具备系统签名自己直接开启了无障碍服务并且打开了无障碍服务快捷方式,如何关闭无障碍服务快捷开关

文章目录

问题现象问题描述

屏蔽app无障碍服务显示屏蔽快捷模式方案举例说明:针对酷狗音乐举例说明:针对智能家居 App测试

问题现象

现象如下图所示

问题描述

在无障碍功能列表里面一般都是第三方app,我们不允许客户能够具备这个权限,所以需要屏蔽掉针对自研具备系统签名app,不允许客户自己开启无障碍服务快捷方式、或者 我们每次自己去控制无障碍服务快捷开关

屏蔽app无障碍服务显示

思路如下

搜索无障碍服务相关文字搜索,如下:

"文字和显示"

"调暗屏幕"

"互动控制"

"时间控件"

"系统控件"

"已下载的应用"

"实验性功能"

通过1 找到无障碍模式布局文件 accessibility_settings.xml 从布局对比可以看到,这个已下载的应用,本身子数据也是动态添加的,其它的快捷菜单子数据是配置的。

android:key="user_installed_services_category"

android:persistent="false"

android:title="@string/user_installed_services_category_title"/>

通过2 找到 AccessibilitySettings.java 已下载的内容:CATEGORY_DOWNLOADED_SERVICES

private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";

-》 final PreferenceCategory downloadedServicesCategory =

mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);

-》集合mCategoryToPrefCategoryMap 赋值:

private void initializeAllPreferences() {

for (int i = 0; i < CATEGORIES.length; i++) {

PreferenceCategory prefCategory = findPreference(CATEGORIES[i]);

mCategoryToPrefCategoryMap.put(CATEGORIES[i], prefCategory);

}

}

根据2 中的推测,找到mCategoryToPrefCategoryMap 中,已下载的 赋值地方。

-> final PreferenceCategory downloadedServicesCategory =

mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);

downloadedServicesCategory 找到它赋值子类的地方:

->

for (int i = 0, count = preferenceList.size(); i < count; ++i) {

final RestrictedPreference preference = preferenceList.get(i);

final ComponentName componentName = preference.getExtras().getParcelable(

EXTRA_COMPONENT_NAME);

PreferenceCategory prefCategory = downloadedServicesCategory;

// Set the appropriate category if the service comes pre-installed.

if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) {

prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);

}

prefCategory.addPreference(preference);

mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);

}

这个地方,通过 componentName 的信息,如果含有了 需要屏蔽的包名 则 continue 即可,不让添加到prefCategory中 即可 修改后的代码如下:

for (int i = 0, count = preferenceList.size(); i < count; ++i) {

final RestrictedPreference preference = preferenceList.get(i);

final ComponentName componentName = preference.getExtras().getParcelable(

EXTRA_COMPONENT_NAME);

String pkgName= componentName.getPackageName();

Log.d(TAG,"pkgName:"+pkgName);

if("com.sohu.inputmethod.sogou".equals(pkgName)){ //这个地方通过包名来判断,进行屏蔽

Log.d(TAG,"ping bi:"+pkgName);

continue;

}

PreferenceCategory prefCategory = downloadedServicesCategory;

// Set the appropriate category if the service comes pre-installed.

if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) {

prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);

}

prefCategory.addPreference(preference);

mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);

}

屏蔽快捷模式方案

搜索代码 “快捷方式,找到对应位置”

"%1$s快捷方式"

通过R.string.accessibility_shortcut_title 找到 AccessibilityShortcutPreferenceFragment 找到一些相关的代码

相关代码加载布局

/**

* Base class for accessibility fragments shortcut functions and dialog management.

*/

@VisibleForTesting

void setupEditShortcutDialog(Dialog dialog) {

final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut);

mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox);

setDialogTextAreaClickListener(dialogSoftwareView, mSoftwareTypeCheckBox);

final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut);

mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox);

setDialogTextAreaClickListener(dialogHardwareView, mHardwareTypeCheckBox);

updateEditShortcutDialogCheckBox();

}

@Override

public Dialog onCreateDialog(int dialogId) {

final Dialog dialog;

switch (dialogId) {

case DialogEnums.EDIT_SHORTCUT:

final CharSequence dialogTitle = getPrefContext().getString(

R.string.accessibility_shortcut_title, getLabelName());

final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())

? AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC_SUW :

AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC;

dialog = AccessibilityDialogUtils.showEditShortcutDialog(

getPrefContext(), dialogType, dialogTitle,

this::callOnAlertDialogCheckboxClicked);

setupEditShortcutDialog(dialog);

return dialog;

case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:

dialog = AccessibilityGestureNavigationTutorial

.createAccessibilityTutorialDialog(getPrefContext(),

getUserShortcutTypes());

dialog.setCanceledOnTouchOutside(false);

return dialog;

default:

throw new IllegalArgumentException("Unsupported dialogId " + dialogId);

}

->AccessibilityGestureNavigationTutorial.java

checkBox 点击事件地方

@Override

public void onToggleClicked(ShortcutPreference preference) {

if (getComponentName() == null) {

return;

}

final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),

getComponentName().flattenToString(), AccessibilityUtil.UserShortcutType.SOFTWARE);

if (preference.isChecked()) {

AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,

getComponentName());

showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);

} else {

AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,

getComponentName());

}

mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));

}

这里AccessibilityUtil 有两个方法 optInAllValuesToSettings optOutAllValuesFromSettings 而且有 getComponentName 说明是对某个应用进行设置,进去看下具体代码

/**

* Opts in component name into multiple {@code shortcutTypes} colon-separated string in

* Settings.

*

* @param context The current context.

* @param shortcutTypes A combination of {@link UserShortcutType}.

* @param componentName The component name that need to be opted in Settings.

*/

static void optInAllValuesToSettings(Context context, int shortcutTypes,

@NonNull ComponentName componentName) {

if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {

optInValueToSettings(context, UserShortcutType.SOFTWARE, componentName);

}

if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {

optInValueToSettings(context, UserShortcutType.HARDWARE, componentName);

}

}

/**

* Opts out component name into multiple {@code shortcutTypes} colon-separated string in

* Settings.

*

* @param context The current context.

* @param shortcutTypes A combination of {@link UserShortcutType}.

* @param componentName The component name that need to be opted out from Settings.

*/

static void optOutAllValuesFromSettings(Context context, int shortcutTypes,

@NonNull ComponentName componentName) {

if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {

optOutValueFromSettings(context, UserShortcutType.SOFTWARE, componentName);

}

if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {

optOutValueFromSettings(context, UserShortcutType.HARDWARE, componentName);

}

}

实际根据AccessibilityUtil.java 日志分析,

举例说明:针对酷狗音乐

打开无障碍快捷方式:

AccessibilityUtil com.android.settings D optInAllValuesToSettings shortcutTypes:1 pkgName:com.kugou.android className:com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

AccessibilityUtil com.android.settings D optInAllValuesToSettings ->optInValueToSettings SOFTWARE

AccessibilityUtil com.android.settings D optInValueToSettings targetKey:accessibility_button_targets targetString:

AccessibilityUtil com.android.settings D optInValueToSettings componentName flattenToStr:com.kugou.android/com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

AccessibilityUtil com.android.settings D optInValueToSettings targetKey:accessibility_button_targets joiner:com.kugou.android/com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

最终 optInValueToSettings 方法,调用:

Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());

Log.d(TAG,"optInValueToSettings targetKey:"+targetKey+" joiner:"+ joiner.toString());

关闭无障碍快捷方式:

AccessibilityUtil com.android.settings D optOutAllValuesFromSettings shortcutTypes:1 pkgName:com.kugou.android className:com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

AccessibilityUtil com.android.settings D optOutValueFromSettings shortcutType:1 pkgName:com.kugou.android className:com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_button_targets targetString:com.kugou.android/com.kugou.ringtone.permission.accessibilitysuper.service.AccessibilitySuperService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_button_targets joiner.toString():

最终 optOutValueFromSettings 方法里面调用:

Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());

Log.d(TAG,"optOutValueFromSettings targetKey:"+targetKey+" joiner.toString():"+joiner.toString());

所以,针对 不同app,取消权限 需要调用 对应的targetkey 的value 置空即可

举例说明:针对智能家居 App测试

打开快捷方式 日志如下:

AccessibilityUtil com.android.settings D optInAllValuesToSettings shortcutTypes:3 pkgName:com.deling.launcher className:com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optInAllValuesToSettings ->optInValueToSettings SOFTWARE

AccessibilityUtil com.android.settings D optInValueToSettings targetKey:accessibility_button_targets targetString:

AccessibilityUtil com.android.settings D optInValueToSettings componentName flattenToStr:com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optInValueToSettings targetKey:accessibility_button_targets joiner:com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService

打开快捷方式开关:涉及到相关的componentName 如下:

pkgName:com.deling.launcher className:com.hrs.tools.services.ToolsAccessibilityService

componentName flattenToStr:com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService

两个app targetKey:accessibility_button_targets 一样的

关闭快捷方式,日志如下:

AccessibilityUtil com.android.settings D optOutAllValuesFromSettings shortcutTypes:3 pkgName:com.deling.launcher className:com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optOutValueFromSettings shortcutType:1 pkgName:com.deling.launcher className:com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_button_targets targetString:com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_button_targets joiner.toString():

AccessibilityUtil com.android.settings D optOutValueFromSettings shortcutType:2 pkgName:com.deling.launcher className:com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_shortcut_target_service targetString:com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService

AccessibilityUtil com.android.settings D optOutValueFromSettings targetKey:accessibility_shortcut_target_service joiner.toString():

所以解决方案,每次开机后,或者在哪个位置,关闭对应的快捷方式即可,方法:

Settings.Secure.putString(context.getContentResolver(), targetKey, "");

针对 X7 快捷,实现方式: 取消快捷

Settings.Secure.putString(context.getContentResolver(), "accessibility_button_targets", "");

Settings.Secure.putString(context.getContentResolver(), "accessibility_shortcut_target_service", "");

实际demo 功能验证:

//ToastUtils.showShort("测试快捷模式关闭");

Settings.Secure.putString(getContentResolver(), "accessibility_button_targets", "");

Settings.Secure.putString(getContentResolver(), "accessibility_shortcut_target_service", "");

// ToastUtils.showShort("测试快捷模式打开");

Settings.Secure.putString(getContentResolver(), "accessibility_button_targets", "com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService");

Settings.Secure.putString(getContentResolver(), "accessibility_shortcut_target_service", "com.deling.launcher/com.hrs.tools.services.ToolsAccessibilityService");

无障碍服务源码

🎈 相关推荐

崩坏3鲜血之舞怎么样?鲜血之舞技能/搭配全解析
🏷️ beat365登录平台

崩坏3鲜血之舞怎么样?鲜血之舞技能/搭配全解析

📅 09-07 👀 9392
WPS如何根据中文自动插入英文目录/引用目录
🏷️ office365桌面应用

WPS如何根据中文自动插入英文目录/引用目录

📅 07-09 👀 2221
QQ炫舞手游怎么找p点 找p点技巧介绍攻略
🏷️ Bet体育365提款验证

QQ炫舞手游怎么找p点 找p点技巧介绍攻略

📅 08-23 👀 4604
问道手游乖乖狗怎么样
🏷️ beat365登录平台

问道手游乖乖狗怎么样

📅 10-28 👀 8020
淘宝店宝宝怎么样?值得使用吗?
🏷️ office365桌面应用

淘宝店宝宝怎么样?值得使用吗?

📅 10-28 👀 9682
客源神器是真的吗 客源神器好用吗
🏷️ office365桌面应用

客源神器是真的吗 客源神器好用吗

📅 08-21 👀 6344