• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.settings.accessibility;
18 
19 import static android.content.Context.ACCESSIBILITY_SERVICE;
20 
21 import static com.android.tv.settings.util.InstrumentationUtils.logToggleInteracted;
22 
23 import android.accessibilityservice.AccessibilityServiceInfo;
24 import android.app.admin.DevicePolicyManager;
25 import android.app.tvsettings.TvSettingsEnums;
26 import android.content.ComponentName;
27 import android.content.pm.ServiceInfo;
28 import android.os.Bundle;
29 import android.os.UserHandle;
30 import android.provider.Settings;
31 import android.text.TextUtils;
32 import android.view.accessibility.AccessibilityManager;
33 
34 import androidx.annotation.Keep;
35 import androidx.preference.Preference;
36 import androidx.preference.PreferenceGroup;
37 import androidx.preference.SwitchPreference;
38 import androidx.preference.TwoStatePreference;
39 
40 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
41 import com.android.settingslib.RestrictedLockUtilsInternal;
42 import com.android.settingslib.RestrictedPreference;
43 import com.android.settingslib.accessibility.AccessibilityUtils;
44 import com.android.tv.settings.R;
45 import com.android.tv.settings.SettingsPreferenceFragment;
46 
47 import java.util.List;
48 import java.util.Set;
49 
50 /**
51  * Fragment for Accessibility settings
52  */
53 @Keep
54 public class AccessibilityFragment extends SettingsPreferenceFragment {
55     private static final String TOGGLE_HIGH_TEXT_CONTRAST_KEY = "toggle_high_text_contrast";
56     private static final String TOGGLE_AUDIO_DESCRIPTION_KEY = "toggle_audio_description";
57     private static final String ACCESSIBILITY_SERVICES_KEY = "system_accessibility_services";
58 
59     private PreferenceGroup mServicesPref;
60     private AccessibilityManager.AccessibilityStateChangeListener
61             mAccessibilityStateChangeListener = enabled -> refreshServices(mServicesPref);
62 
63     /**
64      * Create a new instance of the fragment
65      * @return New fragment instance
66      */
newInstance()67     public static AccessibilityFragment newInstance() {
68         return new AccessibilityFragment();
69     }
70 
71     @Override
onResume()72     public void onResume() {
73         super.onResume();
74         if (mServicesPref != null) {
75             refreshServices(mServicesPref);
76         }
77     }
78 
79     @Override
onStop()80     public void onStop() {
81         super.onStop();
82         AccessibilityManager am = (AccessibilityManager)
83                 getContext().getSystemService(ACCESSIBILITY_SERVICE);
84         if (am != null && mServicesPref != null) {
85             am.removeAccessibilityStateChangeListener(mAccessibilityStateChangeListener);
86         }
87     }
88 
89     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)90     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
91         setPreferencesFromResource(R.xml.accessibility, null);
92 
93         final TwoStatePreference highContrastPreference =
94                 (TwoStatePreference) findPreference(TOGGLE_HIGH_TEXT_CONTRAST_KEY);
95         highContrastPreference.setChecked(Settings.Secure.getInt(getContext().getContentResolver(),
96                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1);
97 
98         final TwoStatePreference audioDescriptionPreference =
99                 (TwoStatePreference) findPreference(TOGGLE_AUDIO_DESCRIPTION_KEY);
100         audioDescriptionPreference.setChecked(Settings.Secure.getInt(
101                 getContext().getContentResolver(),
102                 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, 0) == 1);
103 
104         mServicesPref = (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_KEY);
105         if (mServicesPref != null) {
106             refreshServices(mServicesPref);
107             AccessibilityManager am = (AccessibilityManager)
108                     getContext().getSystemService(ACCESSIBILITY_SERVICE);
109             if (am != null) {
110                 am.addAccessibilityStateChangeListener(mAccessibilityStateChangeListener);
111             }
112         }
113     }
114 
115     @Override
onPreferenceTreeClick(Preference preference)116     public boolean onPreferenceTreeClick(Preference preference) {
117         if (TextUtils.equals(preference.getKey(), TOGGLE_HIGH_TEXT_CONTRAST_KEY)) {
118             logToggleInteracted(
119                     TvSettingsEnums.SYSTEM_A11Y_HIGH_CONTRAST_TEXT,
120                     ((SwitchPreference) preference).isChecked());
121             Settings.Secure.putInt(getActivity().getContentResolver(),
122                     Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
123                     (((SwitchPreference) preference).isChecked() ? 1 : 0));
124             return true;
125         } else if (TextUtils.equals(preference.getKey(), TOGGLE_AUDIO_DESCRIPTION_KEY)) {
126             logToggleInteracted(
127                     TvSettingsEnums.SYSTEM_A11Y_AUDIO_DESCRIPTION,
128                     ((SwitchPreference) preference).isChecked());
129             Settings.Secure.putInt(getActivity().getContentResolver(),
130                     Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
131                     (((SwitchPreference) preference).isChecked() ? 1 : 0));
132             return true;
133         } else {
134             return super.onPreferenceTreeClick(preference);
135         }
136     }
137 
refreshServices(PreferenceGroup group)138     private void refreshServices(PreferenceGroup group) {
139         DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
140         final List<AccessibilityServiceInfo> installedServiceInfos =
141                 getActivity().getSystemService(AccessibilityManager.class)
142                         .getInstalledAccessibilityServiceList();
143         final Set<ComponentName> enabledServices =
144                 AccessibilityUtils.getEnabledServicesFromSettings(getActivity());
145         final List<String> permittedServices = dpm.getPermittedAccessibilityServices(
146                 UserHandle.myUserId());
147 
148         final boolean accessibilityEnabled = Settings.Secure.getInt(
149                 getActivity().getContentResolver(),
150                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
151 
152         for (final AccessibilityServiceInfo accInfo : installedServiceInfos) {
153             final ServiceInfo serviceInfo = accInfo.getResolveInfo().serviceInfo;
154             final ComponentName componentName = new ComponentName(serviceInfo.packageName,
155                     serviceInfo.name);
156 
157             final boolean serviceEnabled = accessibilityEnabled
158                     && enabledServices.contains(componentName);
159             // permittedServices null means all accessibility services are allowed.
160             final boolean serviceAllowed = permittedServices == null
161                     || permittedServices.contains(serviceInfo.packageName);
162 
163             final String title = accInfo.getResolveInfo()
164                     .loadLabel(getActivity().getPackageManager()).toString();
165 
166             final String key = "ServicePref:" + componentName.flattenToString();
167             RestrictedPreference servicePref = findPreference(key);
168             if (servicePref == null) {
169                 servicePref = new RestrictedPreference(group.getContext());
170                 servicePref.setKey(key);
171             }
172             servicePref.setTitle(title);
173             servicePref.setSummary(serviceEnabled ? R.string.settings_on : R.string.settings_off);
174             AccessibilityServiceFragment.prepareArgs(servicePref.getExtras(),
175                     serviceInfo.packageName,
176                     serviceInfo.name,
177                     accInfo.getSettingsActivityName(),
178                     title);
179 
180             if (serviceAllowed || serviceEnabled) {
181                 servicePref.setEnabled(true);
182                 servicePref.setFragment(AccessibilityServiceFragment.class.getName());
183             } else {
184                 // Disable accessibility service that are not permitted.
185                 final EnforcedAdmin admin =
186                         RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed(
187                                 getContext(), serviceInfo.packageName, UserHandle.myUserId());
188                 if (admin != null) {
189                     servicePref.setDisabledByAdmin(admin);
190                 } else {
191                     servicePref.setEnabled(false);
192                 }
193                 servicePref.setFragment(null);
194             }
195 
196             group.addPreference(servicePref);
197         }
198     }
199 
200     @Override
getPageId()201     protected int getPageId() {
202         return TvSettingsEnums.SYSTEM_A11Y;
203     }
204 }
205