1 /* 2 * Copyright (C) 2015 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.system; 18 19 import android.accessibilityservice.AccessibilityServiceInfo; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.ServiceInfo; 24 import android.os.Bundle; 25 import android.provider.Settings; 26 import android.support.annotation.NonNull; 27 import android.support.v14.preference.SwitchPreference; 28 import android.support.v17.leanback.app.GuidedStepFragment; 29 import android.support.v17.leanback.widget.GuidanceStylist; 30 import android.support.v17.leanback.widget.GuidedAction; 31 import android.support.v17.preference.LeanbackPreferenceFragment; 32 import android.support.v7.preference.CheckBoxPreference; 33 import android.support.v7.preference.Preference; 34 import android.support.v7.preference.PreferenceCategory; 35 import android.support.v7.preference.PreferenceGroup; 36 import android.support.v7.preference.PreferenceScreen; 37 import android.text.TextUtils; 38 import android.view.accessibility.AccessibilityManager; 39 40 import com.android.settingslib.accessibility.AccessibilityUtils; 41 import com.android.tv.settings.R; 42 43 import java.util.List; 44 import java.util.Set; 45 46 public class AccessibilityFragment extends LeanbackPreferenceFragment { 47 private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE = 48 "toggle_high_text_contrast_preference"; 49 50 private PreferenceGroup mServicesPref; 51 newInstance()52 public static AccessibilityFragment newInstance() { 53 return new AccessibilityFragment(); 54 } 55 56 @Override onResume()57 public void onResume() { 58 super.onResume(); 59 if (mServicesPref != null) { 60 refreshServices(mServicesPref); 61 } 62 } 63 64 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)65 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 66 final Context themedContext = getPreferenceManager().getContext(); 67 final PreferenceScreen screen = 68 getPreferenceManager().createPreferenceScreen(themedContext); 69 screen.setTitle(R.string.system_accessibility); 70 71 final Preference captionsPreference = new Preference(themedContext); 72 captionsPreference.setTitle(R.string.accessibility_captions); 73 captionsPreference.setIntent(new Intent(Intent.ACTION_MAIN).setComponent( 74 new ComponentName(getActivity(), CaptionSetupActivity.class))); 75 screen.addPreference(captionsPreference); 76 77 final SwitchPreference highContrastPreference = new SwitchPreference(themedContext); 78 highContrastPreference.setKey(TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE); 79 highContrastPreference.setPersistent(false); 80 highContrastPreference.setTitle( 81 R.string.accessibility_toggle_high_text_contrast_preference_title); 82 highContrastPreference.setSummary(R.string.experimental_preference); 83 highContrastPreference.setChecked(Settings.Secure.getInt(getContext().getContentResolver(), 84 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1); 85 screen.addPreference(highContrastPreference); 86 87 mServicesPref = new PreferenceCategory(themedContext); 88 mServicesPref.setTitle(R.string.system_services); 89 screen.addPreference(mServicesPref); 90 refreshServices(mServicesPref); 91 92 final Preference ttsPref = new Preference(themedContext); 93 ttsPref.setTitle(R.string.system_accessibility_tts_output); 94 ttsPref.setFragment(TextToSpeechFragment.class.getName()); 95 screen.addPreference(ttsPref); 96 97 setPreferenceScreen(screen); 98 } 99 100 @Override onPreferenceTreeClick(Preference preference)101 public boolean onPreferenceTreeClick(Preference preference) { 102 if (TextUtils.equals(preference.getKey(), TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE)) { 103 Settings.Secure.putInt(getActivity().getContentResolver(), 104 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 105 (((SwitchPreference) preference).isChecked() ? 1 : 0)); 106 return true; 107 } else { 108 return super.onPreferenceTreeClick(preference); 109 } 110 } 111 refreshServices(PreferenceGroup group)112 private void refreshServices(PreferenceGroup group) { 113 final List<AccessibilityServiceInfo> installedServiceInfos = AccessibilityManager 114 .getInstance(getActivity()).getInstalledAccessibilityServiceList(); 115 final Set<ComponentName> enabledServices = 116 AccessibilityUtils.getEnabledServicesFromSettings(getActivity()); 117 final boolean accessibilityEnabled = Settings.Secure.getInt( 118 getActivity().getContentResolver(), 119 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; 120 121 for (final AccessibilityServiceInfo accInfo : installedServiceInfos) { 122 final ServiceInfo serviceInfo = accInfo.getResolveInfo().serviceInfo; 123 final ComponentName componentName = new ComponentName(serviceInfo.packageName, 124 serviceInfo.name); 125 126 final boolean serviceEnabled = accessibilityEnabled 127 && enabledServices.contains(componentName); 128 129 final String title = accInfo.getResolveInfo() 130 .loadLabel(getActivity().getPackageManager()).toString(); 131 132 final String key = "ServicePref:" + componentName.flattenToString(); 133 Preference servicePref = findPreference(key); 134 if (servicePref == null) { 135 servicePref = new Preference(group.getContext()); 136 servicePref.setKey(key); 137 } 138 servicePref.setTitle(title); 139 servicePref.setSummary(serviceEnabled ? R.string.settings_on : R.string.settings_off); 140 servicePref.setFragment(AccessibilityServiceFragment.class.getName()); 141 AccessibilityServiceFragment.prepareArgs(servicePref.getExtras(), 142 serviceInfo.packageName, 143 serviceInfo.name, 144 accInfo.getSettingsActivityName(), 145 title); 146 group.addPreference(servicePref); 147 } 148 } 149 150 public static class AccessibilityServiceFragment extends LeanbackPreferenceFragment { 151 private static final String ARG_PACKAGE_NAME = "packageName"; 152 private static final String ARG_SERVICE_NAME = "serviceName"; 153 private static final String ARG_SETTINGS_ACTIVITY_NAME = "settingsActivityName"; 154 private static final String ARG_LABEL = "label"; 155 156 private CheckBoxPreference mEnablePref; 157 prepareArgs(@onNull Bundle args, String packageName, String serviceName, String activityName, String label)158 public static void prepareArgs(@NonNull Bundle args, String packageName, String serviceName, 159 String activityName, String label) { 160 args.putString(ARG_PACKAGE_NAME, packageName); 161 args.putString(ARG_SERVICE_NAME, serviceName); 162 args.putString(ARG_SETTINGS_ACTIVITY_NAME, activityName); 163 args.putString(ARG_LABEL, label); 164 } 165 166 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)167 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 168 final Context themedContext = getPreferenceManager().getContext(); 169 final PreferenceScreen screen = 170 getPreferenceManager().createPreferenceScreen(themedContext); 171 screen.setTitle(getArguments().getString(ARG_LABEL)); 172 173 mEnablePref = new CheckBoxPreference(themedContext); 174 mEnablePref.setTitle(R.string.system_accessibility_status); 175 mEnablePref.setFragment(EnableDisableConfirmationFragment.class.getName()); 176 screen.addPreference(mEnablePref); 177 178 final Preference settingsPref = new Preference(themedContext); 179 settingsPref.setTitle(R.string.system_accessibility_config); 180 final String activityName = getArguments().getString(ARG_SETTINGS_ACTIVITY_NAME); 181 if (!TextUtils.isEmpty(activityName)) { 182 final String packageName = getArguments().getString(ARG_PACKAGE_NAME); 183 settingsPref.setIntent(new Intent(Intent.ACTION_MAIN) 184 .setComponent(new ComponentName(packageName, activityName))); 185 } else { 186 settingsPref.setEnabled(false); 187 } 188 screen.addPreference(settingsPref); 189 190 setPreferenceScreen(screen); 191 } 192 193 @Override onResume()194 public void onResume() { 195 super.onResume(); 196 197 final String packageName = getArguments().getString(ARG_PACKAGE_NAME); 198 final String serviceName = getArguments().getString(ARG_SERVICE_NAME); 199 200 final ComponentName serviceComponent = new ComponentName(packageName, serviceName); 201 final Set<ComponentName> enabledServices = 202 AccessibilityUtils.getEnabledServicesFromSettings(getActivity()); 203 final boolean enabled = enabledServices.contains(serviceComponent); 204 205 mEnablePref.setChecked(enabled); 206 EnableDisableConfirmationFragment.prepareArgs(mEnablePref.getExtras(), 207 new ComponentName(packageName, serviceName), 208 getArguments().getString(ARG_LABEL), !enabled); 209 } 210 211 public static class EnableDisableConfirmationFragment extends GuidedStepFragment { 212 private static final String ARG_LABEL = "label"; 213 private static final String ARG_COMPONENT = "component"; 214 private static final String ARG_ENABLING = "enabling"; 215 prepareArgs(@onNull Bundle args, ComponentName cn, String label, boolean enabling)216 public static void prepareArgs(@NonNull Bundle args, ComponentName cn, String label, 217 boolean enabling) { 218 args.putParcelable(ARG_COMPONENT, cn); 219 args.putString(ARG_LABEL, label); 220 args.putBoolean(ARG_ENABLING, enabling); 221 } 222 223 @NonNull 224 @Override onCreateGuidance(Bundle savedInstanceState)225 public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { 226 final String label = getArguments().getString(ARG_LABEL); 227 if (getArguments().getBoolean(ARG_ENABLING)) { 228 return new GuidanceStylist.Guidance( 229 getString(R.string.system_accessibility_service_on_confirm_title, 230 label), 231 getString(R.string.system_accessibility_service_on_confirm_desc, 232 label), 233 null, 234 getActivity().getDrawable(R.drawable.ic_accessibility_new_132dp) 235 ); 236 } else { 237 return new GuidanceStylist.Guidance( 238 getString(R.string.system_accessibility_service_off_confirm_title, 239 label), 240 getString(R.string.system_accessibility_service_off_confirm_desc, 241 label), 242 null, 243 getActivity().getDrawable(R.drawable.ic_accessibility_new_132dp) 244 ); 245 } 246 } 247 248 @Override onCreateActions(@onNull List<GuidedAction> actions, Bundle savedInstanceState)249 public void onCreateActions(@NonNull List<GuidedAction> actions, 250 Bundle savedInstanceState) { 251 final Context context = getActivity(); 252 actions.add(new GuidedAction.Builder(context) 253 .clickAction(GuidedAction.ACTION_ID_OK).build()); 254 actions.add(new GuidedAction.Builder(context) 255 .clickAction(GuidedAction.ACTION_ID_CANCEL).build()); 256 } 257 258 @Override onGuidedActionClicked(GuidedAction action)259 public void onGuidedActionClicked(GuidedAction action) { 260 if (action.getId() == GuidedAction.ACTION_ID_OK) { 261 final ComponentName component = getArguments().getParcelable(ARG_COMPONENT); 262 AccessibilityUtils.setAccessibilityServiceState(getActivity(), 263 component, getArguments().getBoolean(ARG_ENABLING)); 264 getFragmentManager().popBackStack(); 265 } else if (action.getId() == GuidedAction.ACTION_ID_CANCEL) { 266 getFragmentManager().popBackStack(); 267 } else { 268 super.onGuidedActionClicked(action); 269 } 270 } 271 } 272 } 273 } 274