1296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver/*
2296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * Copyright (C) 2017 The Android Open Source Project
3296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver *
4296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * Licensed under the Apache License, Version 2.0 (the "License");
5296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * you may not use this file except in compliance with the License.
6296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * You may obtain a copy of the License at
7296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver *
8296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver *      http://www.apache.org/licenses/LICENSE-2.0
9296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver *
10296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * Unless required by applicable law or agreed to in writing, software
11296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * distributed under the License is distributed on an "AS IS" BASIS,
12296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * See the License for the specific language governing permissions and
14296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * limitations under the License.
15296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver */
16296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverpackage com.android.settings.accessibility;
17296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
18296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.accessibilityservice.AccessibilityServiceInfo;
19296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.content.ComponentName;
20296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.content.ContentResolver;
21296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.content.Context;
22296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.os.Bundle;
23296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.os.UserHandle;
24296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.provider.Settings;
25296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.support.v14.preference.SwitchPreference;
26296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.support.v7.preference.Preference;
27296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.text.TextUtils;
28296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.view.accessibility.AccessibilityManager;
29296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport android.widget.Switch;
30296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
31296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
32296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport com.android.settings.R;
33296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport com.android.settings.search.BaseSearchIndexProvider;
34296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport com.android.settings.search.Indexable;
35296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverimport com.android.settingslib.accessibility.AccessibilityUtils;
36296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
37296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver/**
38296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver * Settings page for accessibility shortcut
39296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver */
40296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaverpublic class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePreferenceFragment
41296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        implements Indexable {
42296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
43296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public static final String SHORTCUT_SERVICE_KEY = "accessibility_shortcut_service";
44296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public static final String ON_LOCK_SCREEN_KEY = "accessibility_shortcut_on_lock_screen";
45296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
46296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    private Preference mServicePreference;
47296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    private SwitchPreference mOnLockScreenSwitchPreference;
48296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
49296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    @Override
50296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public int getMetricsCategory() {
51296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
52296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
53296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
54296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    @Override
55179645eecd1a2321e7dd8992678b47799e60f9e6Fan Zhang    protected int getHelpResource() {
56179645eecd1a2321e7dd8992678b47799e60f9e6Fan Zhang        return R.string.help_url_accessibility_shortcut;
57179645eecd1a2321e7dd8992678b47799e60f9e6Fan Zhang    }
58179645eecd1a2321e7dd8992678b47799e60f9e6Fan Zhang
59179645eecd1a2321e7dd8992678b47799e60f9e6Fan Zhang    @Override
60296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public void onCreate(Bundle savedInstanceState) {
61296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        super.onCreate(savedInstanceState);
62296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
63296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        addPreferencesFromResource(R.xml.accessibility_shortcut_settings);
64296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mServicePreference = findPreference(SHORTCUT_SERVICE_KEY);
65296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mOnLockScreenSwitchPreference = (SwitchPreference) findPreference(ON_LOCK_SCREEN_KEY);
66296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mOnLockScreenSwitchPreference.setOnPreferenceChangeListener((Preference p, Object o) -> {
67296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver            Settings.Secure.putInt(getContentResolver(),
68296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                    Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
69296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                    ((Boolean) o) ? 1 : 0);
70296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver            return true;
71296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        });
72296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mFooterPreferenceMixin.createFooterPreference()
73296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                .setTitle(R.string.accessibility_shortcut_description);
74296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
75296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
76296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    @Override
77296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public void onResume() {
78296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        super.onResume();
79296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        updatePreferences();
80296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
81296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
82296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    @Override
83296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    protected void onInstallSwitchBarToggleSwitch() {
84296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        super.onInstallSwitchBarToggleSwitch();
85296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mSwitchBar.addOnSwitchChangeListener((Switch switchView, boolean enabled) -> {
868fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            Context context = getContext();
878fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            if (enabled && (getServiceInfo(context) == null)) {
888fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                // If no service is configured, we'll disable the shortcut shortly. Give the
898fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                // user a chance to select a service. We'll update the preferences when we resume.
908fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                Settings.Secure.putInt(
918fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                        getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1);
928fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                mServicePreference.setEnabled(true);
938fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                mServicePreference.performClick();
948fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            } else {
958fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                onPreferenceToggled(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, enabled);
968fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            }
97296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        });
98296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
99296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
100296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    @Override
101296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
102296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        Settings.Secure.putInt(getContentResolver(), preferenceKey, enabled ? 1 : 0);
1038fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        updatePreferences();
104296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
105296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
106296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    private void updatePreferences() {
107296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        ContentResolver cr = getContentResolver();
1088fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        Context context = getContext();
1098fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        mServicePreference.setSummary(getServiceName(context));
1108fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        if (getServiceInfo(context) == null) {
1118fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            // If no service is configured, make sure the overall shortcut is turned off
1128fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver            Settings.Secure.putInt(
1138fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                    getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0);
1148fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        }
115296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        boolean isEnabled = Settings.Secure
116296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                .getInt(cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1) == 1;
1178fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        mSwitchBar.setChecked(isEnabled);
118296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        mOnLockScreenSwitchPreference.setChecked(Settings.Secure.getInt(
119a989b19646bbeaebb233aa746a816fb97996e23bPhil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0) == 1);
1208fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        // Only enable changing the service and lock screen behavior if the shortcut is on
1218fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        mServicePreference.setEnabled(mToggleSwitch.isChecked());
1228fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        mOnLockScreenSwitchPreference.setEnabled(mToggleSwitch.isChecked());
123296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
124296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
125296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    /**
126296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver     * Get the user-visible name of the service currently selected for the shortcut.
127296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver     *
128296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver     * @param context The current context
129296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver     * @return The name of the service or a string saying that none is selected.
130296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver     */
131296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public static CharSequence getServiceName(Context context) {
1328fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        AccessibilityServiceInfo shortcutServiceInfo = getServiceInfo(context);
133296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        if (shortcutServiceInfo != null) {
134296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver            return shortcutServiceInfo.getResolveInfo().loadLabel(context.getPackageManager());
135296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        }
136296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver        return context.getString(R.string.accessibility_no_service_selected);
137296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    }
138296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver
1398fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver    private static AccessibilityServiceInfo getServiceInfo(Context context) {
1408fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        ComponentName shortcutServiceName = ComponentName.unflattenFromString(
1418fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                AccessibilityUtils.getShortcutTargetServiceComponentNameString(
1428fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                        context, UserHandle.myUserId()));
1438fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver        return AccessibilityManager.getInstance(context)
1448fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver                .getInstalledServiceInfoWithComponentName(shortcutServiceName);
1458fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver    }
1468fcf4d83493eef3a76bbf729277fdc08a383c9adPhil Weaver
147296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
148296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver            new BaseSearchIndexProvider() {
149296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                // This fragment is for details of the shortcut. Only the shortcut itself needs
150296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                // to be indexed.
151296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                protected boolean isPageSearchEnabled(Context context) {
152296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                    return false;
153296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver                }
154296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver            };
155296b7263ad5f9dfbfbe7833da02a551e3adf84ebPhil Weaver}
156