无障碍服务屏蔽_关闭无障碍服务快捷方式

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


问题现象

现象如下图所示
在这里插入图片描述
在这里插入图片描述

问题描述

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

屏蔽app无障碍服务显示

思路如下

  1. 搜索无障碍服务相关文字搜索,如下:
 <string name="accessibility_text_and_display_title" msgid="1398507755501334961">"文字和显示"</string>
    <string name="accessibility_turn_screen_darker_title" msgid="5986223133285858349">"调暗屏幕"</string>
    <string name="interaction_control_category_title" msgid="2696474616743882372">"互动控制"</string>
    <string name="accessibility_tap_assistance_title" msgid="1058913033421048284">"时间控件"</string>
    <string name="accessibility_system_controls_title" msgid="6403287349518987624">"系统控件"</string>
    <string name="user_installed_services_category_title" msgid="2639470729311439731">"已下载的应用"</string>
    <string name="experimental_category_title" msgid="898904396646344152">"实验性功能"</string>
	
  1. 通过1 找到无障碍模式布局文件 accessibility_settings.xml
    从布局对比可以看到,这个已下载的应用,本身子数据也是动态添加的,其它的快捷菜单子数据是配置的。
      <PreferenceCategory
        android:key="user_installed_services_category"
        android:persistent="false"
        android:title="@string/user_installed_services_category_title"/>
  1. 通过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. 搜索代码 “快捷方式,找到对应位置”
  <string name="accessibility_shortcut_title" msgid="8125867833704517463">"<xliff:g id="SERVICE">%1$s</xliff:g>快捷方式"</string>
  1. 通过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");
             

无障碍服务源码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值