Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 296b7263 authored by Phil Weaver's avatar Phil Weaver
Browse files

A11y shortcut settings enhancement

Adding shortcut on/off switch, improving the service picker,
and adding a switch to enable the shortcut on the lock screen.

Also adjusted setting search code to avoid indexing the
accessibility shortcut aside from the main accessibility settings
page.

Bug: 35872328
Bug: 35219988
Test: Ran in a variety of conditions, ran existing settings test.
Also added basic robo test, verified existing robo tests pass.
Change-Id: I4da9bad74caf96d9c8f3640e7db5417b4ee5d602
parent d3505c76
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -4095,8 +4095,14 @@
    <string name="accessibility_screen_magnification_navbar_summary">When magnification is turned on, use the Accessibility button at the bottom of the screen to quickly magnify.\n\n<b>To zoom</b>, tap the Accessibility button, then tap anywhere on the screen.\n<ul><li>Drag 2 or more fingers to scroll</li>\n<li>Pinch 2 or more fingers to adjust zoom</li></ul>\n\n<b>To zoom temporarily</b>, tap the Accessibility button, then touch &amp; hold anywhere on the screen.\n<ul><li>Drag to move around the screen</li>\n<li>Lift finger to zoom out</li></ul>\n\nYou can’t zoom in on the keyboard or navigation bar.</string>
    <!-- Summary text appearing on the accessibility preference screen to enable screen magnification from the nav bar when the feature is enabled, but the accessibility button is not configured correctly for the feature to be used [CHAR LIMIT=none] -->
    <string name="accessibility_screen_magnification_navbar_configuration_warning">The Accessibility button is set to <xliff:g id="service" example="Select to Speak">%1$s</xliff:g>. To use magnification, touch &amp; hold the Accessibility button, then select magnification.</string>
    <!-- Title for the preference to enable the global geture that turns on accessibility. [CHAR LIMIT=35] -->
    <!-- Title for the preference to configure the accessibility shortcut. [CHAR LIMIT=35] -->
    <string name="accessibility_global_gesture_preference_title">Accessibility shortcut</string>
    <!-- Title for the preference to choose the service that is turned on and off by the accessibility shortcut. [CHAR LIMIT=35] -->
    <string name="accessibility_shortcut_service_title">Shortcut service</string>
    <!-- Title for the switch preference that controls whether or not the accessibility shortcut works on the lock screen. [CHAR LIMIT=35] -->
    <string name="accessibility_shortcut_service_on_lock_screen_title">Allow from lock screen</string>
    <!-- Description of accessibility shortcut. [CHAR LIMIT=NONE] -->
    <string name="accessibility_shortcut_description">When the shortcut is on, you can press both volume buttons for 3 seconds to start an accessibility feature.</string>
    <!-- Title for the accessibility preference to high contrast text. [CHAR LIMIT=35] -->
    <string name="accessibility_toggle_high_text_contrast_preference_title">High contrast text</string>
    <!-- Title for the accessibility preference to auto update screen magnification. [CHAR LIMIT=35] -->
@@ -4280,6 +4286,9 @@
    <!-- Title for the prompt shown as a placeholder if no accessibility services are installed. [CHAR LIMIT=50] -->
    <string name="accessibility_no_services_installed">No services installed</string>
    <!-- Title for the acccessibility shortcut's summary if no service is selected for use with the shortcut. [CHAR LIMIT=50] -->
    <string name="accessibility_no_service_selected">No service selected</string>
    <!-- Default description for an accessibility service if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
    <string name="accessibility_service_default_description">No description provided.</string>
+2 −1
Original line number Diff line number Diff line
@@ -18,8 +18,9 @@
        android:title="@string/accessibility_settings"
        android:persistent="true">

    <ListPreference
    <Preference
            android:key="accessibility_shortcut_preference"
            android:fragment="com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment"
            android:title="@string/accessibility_global_gesture_preference_title"/>

    <PreferenceCategory
+27 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                  android:title="@string/accessibility_global_gesture_preference_title" >

    <Preference
            android:key="accessibility_shortcut_service"
            android:title="@string/accessibility_shortcut_service_title"
            android:fragment="com.android.settings.accessibility.ShortcutServicePickerFragment"/>

    <SwitchPreference
            android:key="accessibility_shortcut_on_lock_screen"
            android:title="@string/accessibility_shortcut_service_on_lock_screen_title"/>
</PreferenceScreen>
 No newline at end of file
+20 −13
Original line number Diff line number Diff line
@@ -78,9 +78,16 @@ public class AccessibilityServiceWarning {
        return StorageManager.isNonDefaultBlockEncrypted();
    }

    private static View createEnableDialogContentView(Activity parentActivity,
    /**
     * Get a content View for a dialog to confirm that they want to enable a service.
     *
     * @param context A valid context
     * @param info The info about a service
     * @return A content view suitable for viewing
     */
    private static View createEnableDialogContentView(Context context,
            AccessibilityServiceInfo info) {
        LayoutInflater inflater = (LayoutInflater) parentActivity.getSystemService(
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);

        View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
@@ -89,8 +96,8 @@ public class AccessibilityServiceWarning {
        TextView encryptionWarningView = (TextView) content.findViewById(
                R.id.encryption_warning);
        if (isFullDiskEncrypted()) {
            String text = parentActivity.getString(R.string.enable_service_encryption_warning,
                    info.getResolveInfo().loadLabel(parentActivity.getPackageManager()));
            String text = context.getString(R.string.enable_service_encryption_warning,
                    info.getResolveInfo().loadLabel(context.getPackageManager()));
            encryptionWarningView.setText(text);
            encryptionWarningView.setVisibility(View.VISIBLE);
        } else {
@@ -99,8 +106,8 @@ public class AccessibilityServiceWarning {

        TextView capabilitiesHeaderView = (TextView) content.findViewById(
                R.id.capabilities_header);
        capabilitiesHeaderView.setText(parentActivity.getString(R.string.capabilities_list_title,
                info.getResolveInfo().loadLabel(parentActivity.getPackageManager())));
        capabilitiesHeaderView.setText(context.getString(R.string.capabilities_list_title,
                info.getResolveInfo().loadLabel(context.getPackageManager())));

        LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);

@@ -110,21 +117,21 @@ public class AccessibilityServiceWarning {

        ImageView imageView = (ImageView) capabilityView.findViewById(
                com.android.internal.R.id.perm_icon);
        imageView.setImageDrawable(parentActivity.getDrawable(
        imageView.setImageDrawable(context.getDrawable(
                com.android.internal.R.drawable.ic_text_dot));

        TextView labelView = (TextView) capabilityView.findViewById(
                com.android.internal.R.id.permission_group);
        labelView.setText(parentActivity.getString(
        labelView.setText(context.getString(
                R.string.capability_title_receiveAccessibilityEvents));

        TextView descriptionView = (TextView) capabilityView.findViewById(
                com.android.internal.R.id.permission_list);
        descriptionView.setText(
                parentActivity.getString(R.string.capability_desc_receiveAccessibilityEvents));
                context.getString(R.string.capability_desc_receiveAccessibilityEvents));

        List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
                info.getCapabilityInfos(parentActivity);
                info.getCapabilityInfos(context);

        capabilitiesView.addView(capabilityView);

@@ -138,16 +145,16 @@ public class AccessibilityServiceWarning {

            imageView = (ImageView) capabilityView.findViewById(
                    com.android.internal.R.id.perm_icon);
            imageView.setImageDrawable(parentActivity.getDrawable(
            imageView.setImageDrawable(context.getDrawable(
                    com.android.internal.R.drawable.ic_text_dot));

            labelView = (TextView) capabilityView.findViewById(
                    com.android.internal.R.id.permission_group);
            labelView.setText(parentActivity.getString(capability.titleResId));
            labelView.setText(context.getString(capability.titleResId));

            descriptionView = (TextView) capabilityView.findViewById(
                    com.android.internal.R.id.permission_list);
            descriptionView.setText(parentActivity.getString(capability.descResId));
            descriptionView.setText(context.getString(capability.descResId));

            capabilitiesView.addView(capabilityView);
        }
+17 −93
Original line number Diff line number Diff line
@@ -17,11 +17,9 @@
package com.android.settings.accessibility;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
@@ -130,9 +128,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
    // presentation.
    private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;

    // ID for dialog that confirms shortcut capabilities
    private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1;

    private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>();

    private final Handler mHandler = new Handler();
@@ -205,7 +200,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
    private Preference mDisplayMagnificationPreferenceScreen;
    private Preference mFontSizePreferenceScreen;
    private Preference mAutoclickPreferenceScreen;
    private ListPreference mAccessibilityShortcutPreference;
    private Preference mAccessibilityShortcutPreferenceScreen;
    private Preference mDisplayDaltonizerPreferenceScreen;
    private SwitchPreference mToggleInversionPreference;

@@ -264,9 +259,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        } else if (mToggleInversionPreference == preference) {
            handleToggleInversionPreferenceChange((Boolean) newValue);
            return true;
        } else if (mAccessibilityShortcutPreference == preference) {
            handleAccessibilityShortcutPreferenceChange((String) newValue);
            return true;
        }
        return false;
    }
@@ -283,58 +275,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (checked ? 1 : 0));
    }

    private void handleAccessibilityShortcutPreferenceChange(String serviceComponentName) {
        // When assigning a service to the shortcut the user must explicitly agree to the same
        // capabilities that are present if the service were being enabled.
        // No need if clearing the setting or the service is already enabled.
        if (TextUtils.isEmpty(serviceComponentName)
                || AccessibilityUtils.getEnabledServicesFromSettings(getActivity())
                        .contains(ComponentName.unflattenFromString(serviceComponentName))) {
            Settings.Secure.putString(getContentResolver(),
                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, serviceComponentName);
            updateAccessibilityShortcut();
            return;
        }
        if (!serviceComponentName.equals(mAccessibilityShortcutPreference.getValue())) {
            showDialog(DIALOG_ID_ADD_SHORTCUT_WARNING);
        }
    }

    @Override
    public Dialog onCreateDialog(int dialogId) {
        switch (dialogId) {
            case DIALOG_ID_ADD_SHORTCUT_WARNING: {
                DialogInterface.OnClickListener listener =
                        (DialogInterface dialogInterface, int buttonId) -> {
                            if (buttonId == DialogInterface.BUTTON_POSITIVE) {
                                Settings.Secure.putString(getContentResolver(),
                                        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                                        mAccessibilityShortcutPreference.getValue());
                            }
                            updateAccessibilityShortcut();
                        };
                AccessibilityServiceInfo info = AccessibilityManager.getInstance(getActivity())
                        .getInstalledServiceInfoWithComponentName(
                                ComponentName.unflattenFromString(
                                        mAccessibilityShortcutPreference.getValue()));
                if (info == null) {
                    return null;
                }
                return AccessibilityServiceWarning
                        .createCapabilitiesDialog(getActivity(), info, listener);
            }
            default: {
                throw new IllegalArgumentException();
            }
        }
    }

    @Override
    public int getDialogMetricsCategory(int dialogId) {
        // The only dialog is the one that confirms the properties for the accessibility shortcut
        return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (mToggleHighTextContrastPreference == preference) {
@@ -458,9 +398,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);

        // Accessibility shortcut
        mAccessibilityShortcutPreference =
                (ListPreference) findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
        mAccessibilityShortcutPreference.setOnPreferenceChangeListener(this);
        mAccessibilityShortcutPreferenceScreen = findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
    }

    private void updateAllPreferences() {
@@ -651,7 +589,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements

        updateAutoclickSummary(mAutoclickPreferenceScreen);

        updateAccessibilityShortcut();
        updateAccessibilityShortcut(mAccessibilityShortcutPreferenceScreen);
    }

    private void updateFeatureSummary(String prefKey, Preference pref) {
@@ -700,35 +638,21 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        mToggleMasterMonoPreference.setChecked(masterMono);
    }

    private void updateAccessibilityShortcut() {
        String currentShortcutNameString =
                AccessibilityUtils.getShortcutTargetServiceComponentNameString(getActivity(),
                        UserHandle.myUserId());
        final PackageManager pm = getPackageManager();
        final AccessibilityManager accessibilityManager = getActivity()
                .getSystemService(AccessibilityManager.class);
        final List<AccessibilityServiceInfo> installedServices =
                accessibilityManager.getInstalledAccessibilityServiceList();
        final int numInstalledServices = installedServices.size();

        CharSequence[] entries = new CharSequence[numInstalledServices + 1];
        CharSequence[] entryValues = new CharSequence[numInstalledServices + 1];
        int currentSettingIndex = numInstalledServices;
        for (int i = 0; i < numInstalledServices; i++) {
            AccessibilityServiceInfo installedService = installedServices.get(i);
            entries[i] = installedService.getResolveInfo().loadLabel(pm);
            entryValues[i] = installedService.getComponentName().flattenToShortString();
            if (installedService.getId().equals(currentShortcutNameString)) {
                currentSettingIndex = i;
            }
        }
        entries[numInstalledServices] =
                getString(com.android.internal.R.string.disable_accessibility_shortcut);
        entryValues[numInstalledServices] = "";
        mAccessibilityShortcutPreference.setEntryValues(entryValues);
        mAccessibilityShortcutPreference.setEntries(entries);
        mAccessibilityShortcutPreference.setSummary(entries[currentSettingIndex]);
        mAccessibilityShortcutPreference.setValueIndex(currentSettingIndex);
    private void updateAccessibilityShortcut(Preference preference) {
        if (AccessibilityManager.getInstance(getActivity())
                .getInstalledAccessibilityServiceList().isEmpty()) {
            mAccessibilityShortcutPreferenceScreen
                    .setSummary(getString(R.string.accessibility_no_services_installed));
            mAccessibilityShortcutPreferenceScreen.setEnabled(false);
        } else {
            mAccessibilityShortcutPreferenceScreen.setEnabled(true);
            boolean shortcutEnabled =
                    AccessibilityUtils.isShortcutEnabled(getContext(), UserHandle.myUserId());
            CharSequence summary = shortcutEnabled
                    ? AccessibilityShortcutPreferenceFragment.getServiceName(getContext())
                    : getString(R.string.accessibility_feature_state_off);
            mAccessibilityShortcutPreferenceScreen.setSummary(summary);
        }
    }

    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
Loading