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 android.app.tvsettings.TvSettingsEnums;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.text.TextUtils;
25 
26 import androidx.annotation.NonNull;
27 import androidx.preference.Preference;
28 import androidx.preference.PreferenceScreen;
29 import androidx.preference.SwitchPreference;
30 import androidx.preference.TwoStatePreference;
31 
32 import com.android.internal.logging.nano.MetricsProto;
33 import com.android.settingslib.accessibility.AccessibilityUtils;
34 import com.android.tv.settings.R;
35 import com.android.tv.settings.SettingsPreferenceFragment;
36 
37 import java.util.Set;
38 
39 /**
40  * Fragment for controlling accessibility service
41  */
42 public class AccessibilityServiceFragment extends SettingsPreferenceFragment implements
43         AccessibilityServiceConfirmationFragment.OnAccessibilityServiceConfirmedListener {
44     private static final String ARG_PACKAGE_NAME = "packageName";
45     private static final String ARG_SERVICE_NAME = "serviceName";
46     private static final String ARG_SETTINGS_ACTIVITY_NAME = "settingsActivityName";
47     private static final String ARG_LABEL = "label";
48 
49     private TwoStatePreference mEnablePref;
50 
51     /**
52      * Put args in bundle
53      * @param args Bundle to prepare
54      * @param packageName Package of accessibility service
55      * @param serviceName Class of accessibility service
56      * @param activityName Class of accessibility service settings activity
57      * @param label Screen title
58      */
prepareArgs(@onNull Bundle args, String packageName, String serviceName, String activityName, String label)59     public static void prepareArgs(@NonNull Bundle args, String packageName, String serviceName,
60             String activityName, String label) {
61         args.putString(ARG_PACKAGE_NAME, packageName);
62         args.putString(ARG_SERVICE_NAME, serviceName);
63         args.putString(ARG_SETTINGS_ACTIVITY_NAME, activityName);
64         args.putString(ARG_LABEL, label);
65     }
66 
67     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)68     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
69         final Context themedContext = getPreferenceManager().getContext();
70         final PreferenceScreen screen =
71                 getPreferenceManager().createPreferenceScreen(themedContext);
72         screen.setTitle(getArguments().getString(ARG_LABEL));
73 
74         mEnablePref = new SwitchPreference(themedContext);
75         mEnablePref.setTitle(R.string.system_accessibility_status);
76         mEnablePref.setFragment(AccessibilityServiceConfirmationFragment.class.getName());
77         screen.addPreference(mEnablePref);
78 
79         final Preference settingsPref = new Preference(themedContext);
80         settingsPref.setTitle(R.string.system_accessibility_config);
81         final String activityName = getArguments().getString(ARG_SETTINGS_ACTIVITY_NAME);
82         if (!TextUtils.isEmpty(activityName)) {
83             final String packageName = getArguments().getString(ARG_PACKAGE_NAME);
84             settingsPref.setIntent(new Intent(Intent.ACTION_MAIN)
85                     .setComponent(new ComponentName(packageName, activityName)));
86         } else {
87             settingsPref.setEnabled(false);
88         }
89         screen.addPreference(settingsPref);
90 
91         setPreferenceScreen(screen);
92     }
93 
94     @Override
onPreferenceTreeClick(Preference preference)95     public boolean onPreferenceTreeClick(Preference preference) {
96         if (preference == mEnablePref) {
97             // Prepare confirmation dialog and reverts switch until result comes back.
98             updateEnablePref();
99             // Pass to super to launch confirmation dialog.
100             super.onPreferenceTreeClick(preference);
101             return true;
102         } else {
103             return super.onPreferenceTreeClick(preference);
104         }
105     }
106 
updateEnablePref()107     private void updateEnablePref() {
108         final String packageName = getArguments().getString(ARG_PACKAGE_NAME);
109         final String serviceName = getArguments().getString(ARG_SERVICE_NAME);
110         final ComponentName serviceComponent = new ComponentName(packageName, serviceName);
111         final Set<ComponentName> enabledServices =
112                 AccessibilityUtils.getEnabledServicesFromSettings(getActivity());
113         final boolean enabled = enabledServices.contains(serviceComponent);
114         mEnablePref.setChecked(enabled);
115         AccessibilityServiceConfirmationFragment.prepareArgs(mEnablePref.getExtras(),
116                 new ComponentName(packageName, serviceName),
117                 getArguments().getString(ARG_LABEL), !enabled);
118     }
119 
120     @Override
onResume()121     public void onResume() {
122         super.onResume();
123         updateEnablePref();
124     }
125 
126     @Override
onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling)127     public void onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling) {
128         AccessibilityUtils.setAccessibilityServiceState(getActivity(),
129                 componentName, enabling);
130         if (mEnablePref != null) {
131             mEnablePref.setChecked(enabling);
132         }
133     }
134 
135     @Override
getMetricsCategory()136     public int getMetricsCategory() {
137         return MetricsProto.MetricsEvent.ACCESSIBILITY_SERVICE;
138     }
139 
140     @Override
getPageId()141     protected int getPageId() {
142         // Partial matching of Service's Android componentName for logging a11y services.
143         String serviceName = getArguments().getString(ARG_SERVICE_NAME);
144         if (TextUtils.isEmpty(serviceName)) {
145             return TvSettingsEnums.PAGE_CLASSIC_DEFAULT;
146         } else if (serviceName.contains("TalkBack")) {
147             return TvSettingsEnums.SYSTEM_A11Y_TALKBACK;
148         } else if (serviceName.contains("AccessibilityMenu")) {
149             return TvSettingsEnums.SYSTEM_A11Y_A11Y_MENU;
150         } else if (serviceName.contains("SelectToSpeak")) {
151             return TvSettingsEnums.SYSTEM_A11Y_STS;
152         } else if (serviceName.contains("SwitchAccess")) {
153             return TvSettingsEnums.SYSTEM_A11Y_SWITCH_ACCESS;
154         } else {
155             return TvSettingsEnums.PAGE_CLASSIC_DEFAULT;
156         }
157     }
158 }
159