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

Commit c82cf951 authored by Matthew Fritze's avatar Matthew Fritze Committed by android-build-merger
Browse files

Merge "Add A11y Slices" into pi-dev

am: bc4c392f

Change-Id: I255331e6b490f29011818feca9ff97e2d37dff1b
parents b0cf8a6e bc4c392f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -128,4 +128,7 @@
         doesn't interact well with scroll view -->
    <bool name="config_lock_pattern_minimal_ui">true</bool>

    <!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
    <string-array name="config_settings_slices_accessibility_components" translatable="false"/>

</resources>
+18 −9
Original line number Diff line number Diff line
@@ -342,6 +342,21 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
        return super.onPreferenceTreeClick(preference);
    }

    public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
            boolean serviceEnabled) {
        final String serviceState = serviceEnabled
                ? context.getString(R.string.accessibility_summary_state_enabled)
                : context.getString(R.string.accessibility_summary_state_disabled);
        final CharSequence serviceSummary = info.loadSummary(context.getPackageManager());
        final String stateSummaryCombo = context.getString(
                R.string.preference_summary_default_combination,
                serviceState, serviceSummary);

        return (TextUtils.isEmpty(serviceSummary))
                ? serviceState
                : stateSummaryCombo;
    }

    private void handleToggleTextContrastPreferenceClick() {
        Settings.Secure.putInt(getContentResolver(),
                Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
@@ -543,15 +558,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                preference.setSummary(R.string.accessibility_summary_state_stopped);
                description = getString(R.string.accessibility_description_state_stopped);
            } else {
                final String serviceState = serviceEnabled ?
                        getString(R.string.accessibility_summary_state_enabled) :
                        getString(R.string.accessibility_summary_state_disabled);
                final CharSequence serviceSummary = info.loadSummary(getPackageManager());
                final String stateSummaryCombo = getString(
                        R.string.preference_summary_default_combination,
                        serviceState, serviceSummary);
                preference.setSummary((TextUtils.isEmpty(serviceSummary)) ? serviceState
                        : stateSummaryCombo);
                final CharSequence serviceSummary = getServiceSummary(getContext(), info,
                        serviceEnabled);
                preference.setSummary(serviceSummary);
            }

            // Disable all accessibility services that are not permitted.
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;

import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.core.TogglePreferenceController;
import com.android.settingslib.accessibility.AccessibilityUtils;

import java.util.List;
import java.util.Set;

/**
 * PreferenceController for accessibility services to be used by Slices.
 * Wraps the common logic which enables accessibility services and checks their availability.
 * <p>
 * Should not be used in a {@link com.android.settings.dashboard.DashboardFragment}.
 */
public class AccessibilitySlicePreferenceController extends TogglePreferenceController {

    private final ComponentName mComponentName;

    private final int ON = 1;
    private final int OFF = 0;

    public AccessibilitySlicePreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mComponentName = ComponentName.unflattenFromString(getPreferenceKey());

        if (mComponentName == null) {
            throw new IllegalArgumentException(
                    "Illegal Component Name from: " + preferenceKey);
        }
    }

    @Override
    public CharSequence getSummary() {
        final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo();
        return serviceInfo == null
                ? "" : AccessibilitySettings.getServiceSummary(mContext, serviceInfo, isChecked());
    }

    @Override
    public boolean isChecked() {
        final ContentResolver contentResolver = mContext.getContentResolver();
        final boolean accessibilityEnabled = Settings.Secure.getInt(contentResolver,
                Settings.Secure.ACCESSIBILITY_ENABLED, OFF) == ON;

        if (!accessibilityEnabled) {
            return false;
        }

        final Set<ComponentName> componentNames =
                AccessibilityUtils.getEnabledServicesFromSettings(mContext);

        return componentNames.contains(mComponentName);
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        if (getAccessibilityServiceInfo() == null) {
            return false;
        }
        AccessibilityUtils.setAccessibilityServiceState(mContext, mComponentName, isChecked);
        return isChecked == isChecked(); // Verify that it was probably changed.
    }

    @Override
    public int getAvailabilityStatus() {
        // Return unsupported when the service is disabled or not installed.
        return getAccessibilityServiceInfo() == null ? DISABLED_UNSUPPORTED : AVAILABLE;
    }

    private AccessibilityServiceInfo getAccessibilityServiceInfo() {
        final AccessibilityManager accessibilityManager = mContext.getSystemService(
                AccessibilityManager.class);
        final List<AccessibilityServiceInfo> serviceList =
                accessibilityManager.getInstalledAccessibilityServiceList();

        for (AccessibilityServiceInfo serviceInfo : serviceList) {
            if (mComponentName.equals(serviceInfo.getComponentName())) {
                return serviceInfo;
            }
        }

        return null;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -234,7 +234,7 @@ public class SettingsSliceProvider extends SliceProvider {
    void loadSlice(Uri uri) {
        long startBuildTime = System.currentTimeMillis();

        SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
        final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
        mSliceDataCache.put(uri, sliceData);
        getContext().getContentResolver().notifyChange(uri, null /* content observer */);

+9 −9
Original line number Diff line number Diff line
@@ -113,13 +113,13 @@ public class SliceBuilderUtils {
     * - key
     * <p>
     * Examples of valid paths are:
     * - intent/wifi
     * - intent/bluetooth
     * - action/wifi
     * - action/accessibility/servicename
     * - /intent/wifi
     * - /intent/bluetooth
     * - /action/wifi
     * - /action/accessibility/servicename
     *
     * @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
     * @return Pair whose first element {@code true} if the path is prepended with "action", and
     * @return Pair whose first element {@code true} if the path is prepended with "intent", and
     * second is a key.
     */
    public static Pair<Boolean, String> getPathData(Uri uri) {
@@ -133,10 +133,10 @@ public class SliceBuilderUtils {
            return null;
        }

        final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
        final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
                split[1]);

        return new Pair<>(isInline, split[2]);
        return new Pair<>(isIntent, split[2]);
    }

    /**
@@ -215,8 +215,8 @@ public class SliceBuilderUtils {
    static Intent getContentIntent(Context context, SliceData sliceData) {
        final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
        final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
                sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
                0 /* TODO */);
                sliceData.getFragmentClassName(), sliceData.getKey(),
                sliceData.getScreenTitle().toString(), 0 /* TODO */);
        intent.setClassName(context.getPackageName(), SubSettings.class.getName());
        intent.setData(contentUri);
        return intent;
Loading