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.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.tvsettings.TvSettingsEnums;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.pm.PackageManager;
24 import android.os.Bundle;
25 import android.provider.Settings;
26 import android.text.TextUtils;
27 import android.view.accessibility.AccessibilityManager;
28 
29 import androidx.annotation.Keep;
30 import androidx.fragment.app.Fragment;
31 import androidx.leanback.preference.LeanbackSettingsFragmentCompat;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceScreen;
34 
35 import com.android.tv.settings.R;
36 import com.android.tv.settings.RadioPreference;
37 import com.android.tv.settings.SettingsPreferenceFragment;
38 import com.android.tv.twopanelsettings.TwoPanelSettingsFragment;
39 
40 import java.util.List;
41 
42 /**
43  * Fragment imitating a single-selection list for picking the accessibility shortcut service
44  */
45 @Keep
46 public class AccessibilityShortcutServiceFragment extends SettingsPreferenceFragment implements
47         AccessibilityServiceConfirmationFragment.OnAccessibilityServiceConfirmedListener {
48     private static final String SERVICE_RADIO_GROUP = "service_group";
49 
50     private final Preference.OnPreferenceChangeListener mPreferenceChangeListener =
51             (preference, newValue) -> {
52                 final String newCompString = preference.getKey();
53                 final String currentService =
54                         AccessibilityShortcutFragment.getCurrentService(getContext());
55                 if ((Boolean) newValue && !TextUtils.equals(newCompString, currentService)) {
56                     final ComponentName cn = ComponentName.unflattenFromString(newCompString);
57                     final CharSequence label = preference.getTitle();
58                     final Fragment confirmFragment =
59                             AccessibilityServiceConfirmationFragment.newInstance(cn, label, true);
60                     confirmFragment.setTargetFragment(AccessibilityShortcutServiceFragment.this, 0);
61 
62                     final Fragment settingsFragment = getCallbackFragment();
63                     if (settingsFragment instanceof LeanbackSettingsFragmentCompat) {
64                         ((LeanbackSettingsFragmentCompat) settingsFragment)
65                                 .startImmersiveFragment(confirmFragment);
66                     } else if (settingsFragment instanceof TwoPanelSettingsFragment) {
67                         ((TwoPanelSettingsFragment) settingsFragment)
68                                 .startImmersiveFragment(confirmFragment);
69                     } else {
70                         throw new IllegalStateException("Not attached to settings fragment??");
71                     }
72                 }
73                 return false;
74             };
75 
76     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)77     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
78         setPreferencesFromResource(R.xml.accessibility_shortcut_service, null);
79 
80         final PreferenceScreen screen = getPreferenceScreen();
81         final Context themedContext = getPreferenceManager().getContext();
82 
83         final List<AccessibilityServiceInfo> installedServices = getContext()
84                 .getSystemService(AccessibilityManager.class)
85                 .getInstalledAccessibilityServiceList();
86         final PackageManager packageManager = getContext().getPackageManager();
87         final String currentService = AccessibilityShortcutFragment.getCurrentService(getContext());
88         for (AccessibilityServiceInfo service : installedServices) {
89             final RadioPreference preference = new RadioPreference(themedContext);
90             preference.setPersistent(false);
91             preference.setRadioGroup(SERVICE_RADIO_GROUP);
92             preference.setOnPreferenceChangeListener(mPreferenceChangeListener);
93 
94             final String serviceString = service.getComponentName().flattenToString();
95             if (TextUtils.equals(currentService, serviceString)) {
96                 preference.setChecked(true);
97             }
98             preference.setKey(serviceString);
99             preference.setTitle(service.getResolveInfo().loadLabel(packageManager));
100 
101             screen.addPreference(preference);
102         }
103     }
104 
105     @Override
onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling)106     public void onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling) {
107         final String componentString = componentName.flattenToString();
108         Settings.Secure.putString(getContext().getContentResolver(),
109                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
110                 componentString);
111 
112         if (!(getCallbackFragment() instanceof TwoPanelSettingsFragment)) {
113             getFragmentManager().popBackStack();
114         }
115 
116         if (enabling) {
117             // the listener is only triggered when enabling a new service
118             int prefCount = getPreferenceScreen().getPreferenceCount();
119             for (int i = 0; i < prefCount; i++) {
120                 RadioPreference pref = (RadioPreference) getPreferenceScreen().getPreference(i);
121                 boolean shouldEnable = componentString.equals(pref.getKey());
122                 if (pref != null) {
123                     pref.setChecked(shouldEnable);
124                 }
125             }
126         }
127     }
128 
129     @Override
getPageId()130     protected int getPageId() {
131         return TvSettingsEnums.SYSTEM_A11Y_SHORTCUT_SERVICE;
132     }
133 }
134