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

Commit 1c6f9de1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Settings for new accessibility shortcut."

parents 1d0e6c8c ba29c47a
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -3986,12 +3986,6 @@
    <string name="accessibility_screen_magnification_summary"><b>To zoom</b>, quickly tap the screen 3 times with one finger.\n<ul><li>Drag 2 or more fingers to scroll</li>\n<li>Pinch 2 or more fingers together or apart to adjust zoom</li></ul>\n\n<b>To zoom temporarily</b>, quickly tap the screen 3 times and hold down your finger on the third tap.\n<ul><li>Drag your finger to move around the screen</li>\n<li>Lift your finger to zoom out</li></ul>\n\nYou can\'t zoom in on the keyboard and navigation bar.</string>
    <!-- Title for the preference to enable the global geture that turns on accessibility. [CHAR LIMIT=35] -->
    <string name="accessibility_global_gesture_preference_title">Accessibility shortcut</string>
    <!-- Summary for the preference to enable the global geture that turns on accessibility (on state). [CHAR LIMIT=60] -->
    <string name="accessibility_global_gesture_preference_summary_on">On</string>
    <!-- Summary for the preference screen to enable the global geture that turns on accessibility (off state). [CHAR LIMIT=35] -->
    <string name="accessibility_global_gesture_preference_summary_off">Off</string>
    <!--  Description for the preference screen to enable the global geture taht turns on accessibility. [CHAR LIMIT=none] -->
    <string name="accessibility_global_gesture_preference_description">When this feature is turned on, you can quickly activate accessibility features in two steps:\n\nStep 1: Press and hold the power button until you hear a sound or feel a vibration.\n\nStep 2: Touch and hold two fingers until you hear audio confirmation.\n\nIf the device has multiple users, using this shortcut on the lock screen temporarily enables accessibility until the device is unlocked.</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] -->
+2 −3
Original line number Diff line number Diff line
@@ -81,9 +81,8 @@
                android:summary="@string/accessibility_toggle_master_mono_summary"
                android:persistent="false"/>

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

        <Preference
+157 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */

package com.android.settings.accessibility;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.storage.StorageManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.android.settings.R;

import java.util.List;

/**
 * Utility class for creating the dialog that asks users for explicit permission to grant
 * all of the requested capabilities to an accessibility service before the service is enabled
 */
public class AccessibilityServiceWarning {
    public static Dialog createCapabilitiesDialog(Activity parentActivity,
            AccessibilityServiceInfo info, DialogInterface.OnClickListener listener) {
        final AlertDialog ad = new AlertDialog.Builder(parentActivity)
                .setTitle(parentActivity.getString(R.string.enable_service_title,
                        info.getResolveInfo().loadLabel(parentActivity.getPackageManager())))
                .setView(createEnableDialogContentView(parentActivity, info))
                .setCancelable(true)
                .setPositiveButton(android.R.string.ok, listener)
                .setNegativeButton(android.R.string.cancel, listener)
                .create();

        final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
            // Filter obscured touches by consuming them.
            if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    Toast.makeText(v.getContext(), R.string.touch_filtered_warning,
                            Toast.LENGTH_SHORT).show();
                }
                return true;
            }
            return false;
        };

        ad.create();
        ad.getButton(AlertDialog.BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
        return ad;
    }

    /**
     * Return whether the device is encrypted with legacy full disk encryption. Newer devices
     * should be using File Based Encryption.
     *
     * @return true if device is encrypted
     */
    private static boolean isFullDiskEncrypted() {
        return StorageManager.isNonDefaultBlockEncrypted();
    }

    private static View createEnableDialogContentView(Activity parentActivity,
            AccessibilityServiceInfo info) {
        LayoutInflater inflater = (LayoutInflater) parentActivity.getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);

        View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
                null);

        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()));
            encryptionWarningView.setText(text);
            encryptionWarningView.setVisibility(View.VISIBLE);
        } else {
            encryptionWarningView.setVisibility(View.GONE);
        }

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

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

        // This capability is implicit for all services.
        View capabilityView = inflater.inflate(
                com.android.internal.R.layout.app_permission_item_old, null);

        ImageView imageView = (ImageView) capabilityView.findViewById(
                com.android.internal.R.id.perm_icon);
        imageView.setImageDrawable(parentActivity.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(
                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));

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

        capabilitiesView.addView(capabilityView);

        // Service-specific capabilities.
        final int capabilityCount = capabilities.size();
        for (int i = 0; i < capabilityCount; i++) {
            AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);

            capabilityView = inflater.inflate(
                    com.android.internal.R.layout.app_permission_item_old, null);

            imageView = (ImageView) capabilityView.findViewById(
                    com.android.internal.R.id.perm_icon);
            imageView.setImageDrawable(parentActivity.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));

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

            capabilitiesView.addView(capabilityView);
        }

        return content;
    }
}
+101 −41
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
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;
@@ -87,8 +89,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
            "toggle_master_mono";
    private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
            "select_long_press_timeout_preference";
    private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
            "enable_global_gesture_preference_screen";
    private static final String ACCESSIBILITY_SHORTCUT_PREFERENCE =
            "accessibility_shortcut_preference";
    private static final String CAPTIONING_PREFERENCE_SCREEN =
            "captioning_preference_screen";
    private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
@@ -115,6 +117,9 @@ 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;

    // Auxiliary members.
    static final Set<ComponentName> sInstalledServices = new HashSet<>();

@@ -188,7 +193,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
    private Preference mDisplayMagnificationPreferenceScreen;
    private Preference mFontSizePreferenceScreen;
    private Preference mAutoclickPreferenceScreen;
    private Preference mGlobalGesturePreferenceScreen;
    private ListPreference mAccessibilityShortcutPreference;
    private Preference mDisplayDaltonizerPreferenceScreen;
    private SwitchPreference mToggleInversionPreference;

@@ -247,6 +252,9 @@ 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;
    }
@@ -263,6 +271,58 @@ 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) {
@@ -283,9 +343,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        } else if (mToggleMasterMonoPreference == preference) {
            handleToggleMasterMonoPreferenceClick();
            return true;
        } else if (mGlobalGesturePreferenceScreen == preference) {
            handleToggleEnableAccessibilityGesturePreferenceClick();
            return true;
        } else if (mDisplayMagnificationPreferenceScreen == preference) {
            handleDisplayMagnificationPreferenceScreenClick();
            return true;
@@ -329,17 +386,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                mToggleMasterMonoPreference.isChecked() ? 1 : 0, UserHandle.USER_CURRENT);
    }

    private void handleToggleEnableAccessibilityGesturePreferenceClick() {
        Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
        extras.putString(EXTRA_TITLE, getString(
                R.string.accessibility_global_gesture_preference_title));
        extras.putString(EXTRA_SUMMARY, getString(
                R.string.accessibility_global_gesture_preference_description));
        extras.putBoolean(EXTRA_CHECKED, Settings.Global.getInt(getContentResolver(),
                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1);
        super.onPreferenceTreeClick(mGlobalGesturePreferenceScreen);
    }

    private void handleDisplayMagnificationPreferenceScreenClick() {
        Bundle extras = mDisplayMagnificationPreferenceScreen.getExtras();
        extras.putString(EXTRA_TITLE, getString(
@@ -422,18 +468,10 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        // Display color adjustments.
        mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);

        // Global gesture.
        mGlobalGesturePreferenceScreen = findPreference(
                ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN);
        final int longPressOnPowerBehavior = getActivity().getResources().getInteger(
                com.android.internal.R.integer.config_longPressOnPowerBehavior);
        final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
        if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
                || longPressOnPowerBehavior != LONG_PRESS_POWER_GLOBAL_ACTIONS) {
            // Remove accessibility shortcut if power key is not present
            // nor long press power does not show global actions menu.
            mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
        }
        // Accessibility shortcut
        mAccessibilityShortcutPreference =
                (ListPreference) findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
        mAccessibilityShortcutPreference.setOnPreferenceChangeListener(this);
    }

    private void updateAllPreferences() {
@@ -598,16 +636,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements

        updateAutoclickSummary(mAutoclickPreferenceScreen);

        // Global gesture
        final boolean globalGestureEnabled = Settings.Global.getInt(getContentResolver(),
                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
        if (globalGestureEnabled) {
            mGlobalGesturePreferenceScreen.setSummary(
                    R.string.accessibility_global_gesture_preference_summary_on);
        } else {
            mGlobalGesturePreferenceScreen.setSummary(
                    R.string.accessibility_global_gesture_preference_summary_off);
        }
        updateAccessibilityShortcut();
    }

    private void updateFeatureSummary(String prefKey, Preference pref) {
@@ -656,6 +685,37 @@ 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);
    }

    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
            new BaseSearchIndexProvider() {
        @Override
@@ -663,8 +723,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
            List<SearchIndexableRaw> indexables = new ArrayList<SearchIndexableRaw>();

            PackageManager packageManager = context.getPackageManager();
            AccessibilityManager accessibilityManager = (AccessibilityManager)
                    context.getSystemService(Context.ACCESSIBILITY_SERVICE);
            AccessibilityManager accessibilityManager =
                    context.getSystemService(AccessibilityManager.class);

            String screenTitle = context.getResources().getString(
                    R.string.accessibility_services_title);
+2 −102

File changed.

Preview size limit exceeded, changes collapsed.

Loading