Home | History | Annotate | Download | only in system
      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 
     52     public static AccessibilityFragment newInstance() {
     53         return new AccessibilityFragment();
     54     }
     55 
     56     @Override
     57     public void onResume() {
     58         super.onResume();
     59         if (mServicesPref != null) {
     60             refreshServices(mServicesPref);
     61         }
     62     }
     63 
     64     @Override
     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
    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 
    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 
    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
    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
    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 
    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
    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
    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
    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