• 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 com.android.tv.settings.util.InstrumentationUtils.logToggleInteracted;
20 
21 import android.app.admin.DevicePolicyManager;
22 import android.app.tvsettings.TvSettingsEnums;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.os.Bundle;
27 import android.os.UserHandle;
28 import android.text.TextUtils;
29 
30 import androidx.annotation.NonNull;
31 import androidx.preference.Preference;
32 import androidx.preference.PreferenceScreen;
33 
34 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
35 import com.android.settingslib.RestrictedLockUtilsInternal;
36 import com.android.settingslib.RestrictedSwitchPreference;
37 import com.android.settingslib.accessibility.AccessibilityUtils;
38 import com.android.tv.settings.R;
39 import com.android.tv.settings.SettingsPreferenceFragment;
40 
41 import java.util.List;
42 import java.util.Set;
43 
44 /**
45  * Fragment for controlling accessibility service
46  */
47 public class AccessibilityServiceFragment extends SettingsPreferenceFragment implements
48         AccessibilityServiceConfirmationFragment.OnAccessibilityServiceConfirmedListener {
49     private static final String ARG_PACKAGE_NAME = "packageName";
50     private static final String ARG_SERVICE_NAME = "serviceName";
51     private static final String ARG_SETTINGS_ACTIVITY_NAME = "settingsActivityName";
52     private static final String ARG_LABEL = "label";
53 
54     private RestrictedSwitchPreference mEnablePref;
55 
56     /**
57      * Put args in bundle
58      * @param args Bundle to prepare
59      * @param packageName Package of accessibility service
60      * @param serviceName Class of accessibility service
61      * @param activityName Class of accessibility service settings activity
62      * @param label Screen title
63      */
prepareArgs(@onNull Bundle args, String packageName, String serviceName, String activityName, String label)64     public static void prepareArgs(@NonNull Bundle args, String packageName, String serviceName,
65             String activityName, String label) {
66         args.putString(ARG_PACKAGE_NAME, packageName);
67         args.putString(ARG_SERVICE_NAME, serviceName);
68         args.putString(ARG_SETTINGS_ACTIVITY_NAME, activityName);
69         args.putString(ARG_LABEL, label);
70     }
71 
72     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)73     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
74         final Context themedContext = getPreferenceManager().getContext();
75         final PreferenceScreen screen =
76                 getPreferenceManager().createPreferenceScreen(themedContext);
77         screen.setTitle(getArguments().getString(ARG_LABEL));
78 
79         mEnablePref = new RestrictedSwitchPreference(themedContext);
80         mEnablePref.setTitle(R.string.system_accessibility_status);
81         mEnablePref.setFragment(AccessibilityServiceConfirmationFragment.class.getName());
82         screen.addPreference(mEnablePref);
83 
84         final Preference settingsPref = new Preference(themedContext);
85         settingsPref.setTitle(R.string.system_accessibility_config);
86         final String activityName = getArguments().getString(ARG_SETTINGS_ACTIVITY_NAME);
87         final String packageName = getArguments().getString(ARG_PACKAGE_NAME);
88         if (!TextUtils.isEmpty(activityName) && !TextUtils.isEmpty(packageName)) {
89             settingsPref.setIntent(new Intent(Intent.ACTION_MAIN)
90                     .setComponent(new ComponentName(packageName, activityName)));
91         } else {
92             settingsPref.setEnabled(false);
93         }
94         screen.addPreference(settingsPref);
95 
96         final String serviceName = getArguments().getString(ARG_SERVICE_NAME);
97         ComponentName serviceComponent=null;
98         if(!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(serviceName)){
99             serviceComponent = new ComponentName(packageName, serviceName);
100         }
101         if (serviceComponent != null
102             && serviceComponent
103             .flattenToString()
104             .equals(
105                 getResources()
106                     .getString(R.string.
107                                    accessibility_screen_reader_flattened_component_name))) {
108             final Preference screenReaderPref = new Preference(themedContext);
109             screenReaderPref.setTitle(
110                 getResources().getString(
111                     R.string.screen_reader_service_title));
112             screenReaderPref.setSummary(R.string.screen_reader_summary);
113             screenReaderPref.setEnabled(false);
114             screen.addPreference(screenReaderPref);
115         }
116 
117         setPreferenceScreen(screen);
118     }
119 
120     @Override
onPreferenceTreeClick(Preference preference)121     public boolean onPreferenceTreeClick(Preference preference) {
122         if (preference == mEnablePref && !mEnablePref.isDisabledByAdmin()) {
123             // Prepare confirmation dialog and reverts switch until result comes back.
124             updateEnablePref();
125             // Pass to super to launch confirmation dialog.
126             super.onPreferenceTreeClick(preference);
127             return true;
128         } else {
129             return super.onPreferenceTreeClick(preference);
130         }
131     }
132 
updateEnablePref()133     private void updateEnablePref() {
134         final String packageName = getArguments().getString(ARG_PACKAGE_NAME);
135         final String serviceName = getArguments().getString(ARG_SERVICE_NAME);
136         final ComponentName serviceComponent = new ComponentName(packageName, serviceName);
137         final Set<ComponentName> enabledServices =
138                 AccessibilityUtils.getEnabledServicesFromSettings(getActivity());
139         final boolean enabled = enabledServices.contains(serviceComponent);
140         mEnablePref.setChecked(enabled);
141         AccessibilityServiceConfirmationFragment.prepareArgs(mEnablePref.getExtras(),
142                 new ComponentName(packageName, serviceName),
143                 getArguments().getString(ARG_LABEL), !enabled);
144 
145         DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
146         final List<String> permittedServices = dpm.getPermittedAccessibilityServices(
147                 UserHandle.myUserId());
148         final boolean serviceAllowed = permittedServices == null
149                 || permittedServices.contains(packageName);
150 
151         if (serviceAllowed || enabled) {
152             mEnablePref.setEnabled(true);
153         } else {
154             // Disable accessibility service that are not permitted.
155             final EnforcedAdmin admin =
156                     RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed(
157                             getContext(), packageName, UserHandle.myUserId());
158             if (admin != null) {
159                 mEnablePref.setDisabledByAdmin(admin);
160             } else {
161                 mEnablePref.setEnabled(false);
162             }
163         }
164     }
165 
166     @Override
onResume()167     public void onResume() {
168         super.onResume();
169         updateEnablePref();
170     }
171 
172     @Override
onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling)173     public void onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling) {
174         AccessibilityUtils.setAccessibilityServiceState(getActivity(), componentName, enabling);
175         if (mEnablePref != null) {
176         mEnablePref.setChecked(enabling);
177         // Check if component is talkback, then log
178         if (componentName != null
179             && componentName.flattenToString().equals(
180                 getResources().getString(
181                     R.string.accessibility_screen_reader_flattened_component_name))) {
182             logToggleInteracted(TvSettingsEnums.SYSTEM_A11Y_TALKBACK_ON_OFF, enabling);
183         }
184         }
185     }
186 
187     @Override
getPageId()188     protected int getPageId() {
189         // Partial matching of Service's Android componentName for logging a11y services.
190         String serviceName = getArguments().getString(ARG_SERVICE_NAME);
191         if (TextUtils.isEmpty(serviceName)) {
192             return TvSettingsEnums.PAGE_CLASSIC_DEFAULT;
193         } else if (serviceName.contains("TalkBack")) {
194             return TvSettingsEnums.SYSTEM_A11Y_TALKBACK;
195         } else if (serviceName.contains("AccessibilityMenu")) {
196             return TvSettingsEnums.SYSTEM_A11Y_A11Y_MENU;
197         } else if (serviceName.contains("SelectToSpeak")) {
198             return TvSettingsEnums.SYSTEM_A11Y_STS;
199         } else if (serviceName.contains("SwitchAccess")) {
200             return TvSettingsEnums.SYSTEM_A11Y_SWITCH_ACCESS;
201         } else {
202             return TvSettingsEnums.PAGE_CLASSIC_DEFAULT;
203         }
204     }
205 }
206