OSDN Git Service

Revert "Accessibility: filter touches to Enable button"
[android-x86/packages-apps-Settings.git] / src / com / android / settings / accessibility / ToggleAccessibilityServicePreferenceFragment.java
1 /*
2  * Copyright (C) 2013 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.settings.accessibility;
18
19 import android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.pm.ResolveInfo;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.provider.Settings;
31 import android.text.TextUtils;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.accessibility.AccessibilityManager;
35 import android.widget.ImageView;
36 import android.widget.LinearLayout;
37 import android.widget.TextView;
38
39 import com.android.settings.R;
40 import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
41
42 import java.util.Collections;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Set;
46
47 public class ToggleAccessibilityServicePreferenceFragment
48         extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
49
50     private static final int DIALOG_ID_ENABLE_WARNING = 1;
51     private static final int DIALOG_ID_DISABLE_WARNING = 2;
52
53     private final SettingsContentObserver mSettingsContentObserver =
54             new SettingsContentObserver(new Handler()) {
55             @Override
56                 public void onChange(boolean selfChange, Uri uri) {
57                     String settingValue = Settings.Secure.getString(getContentResolver(),
58                             Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
59                     final boolean enabled = settingValue.contains(mComponentName.flattenToString());
60                     mToggleSwitch.setCheckedInternal(enabled);
61                 }
62             };
63
64     private ComponentName mComponentName;
65
66     private int mShownDialogId;
67
68     @Override
69     public void onResume() {
70         mSettingsContentObserver.register(getContentResolver());
71         super.onResume();
72     }
73
74     @Override
75     public void onPause() {
76         mSettingsContentObserver.unregister(getContentResolver());
77         super.onPause();
78     }
79
80     @Override
81     public void onPreferenceToggled(String preferenceKey, boolean enabled) {
82         // Parse the enabled services.
83         Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
84                 getActivity());
85
86         if (enabledServices == (Set<?>) Collections.emptySet()) {
87             enabledServices = new HashSet<ComponentName>();
88         }
89
90         // Determine enabled services and accessibility state.
91         ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
92         boolean accessibilityEnabled = false;
93         if (enabled) {
94             enabledServices.add(toggledService);
95             // Enabling at least one service enables accessibility.
96             accessibilityEnabled = true;
97         } else {
98             enabledServices.remove(toggledService);
99             // Check how many enabled and installed services are present.
100             Set<ComponentName> installedServices = AccessibilitySettings.sInstalledServices;
101             for (ComponentName enabledService : enabledServices) {
102                 if (installedServices.contains(enabledService)) {
103                     // Disabling the last service disables accessibility.
104                     accessibilityEnabled = true;
105                     break;
106                 }
107             }
108         }
109
110         // Update the enabled services setting.
111         StringBuilder enabledServicesBuilder = new StringBuilder();
112         // Keep the enabled services even if they are not installed since we
113         // have no way to know whether the application restore process has
114         // completed. In general the system should be responsible for the
115         // clean up not settings.
116         for (ComponentName enabledService : enabledServices) {
117             enabledServicesBuilder.append(enabledService.flattenToString());
118             enabledServicesBuilder.append(
119                     AccessibilitySettings.ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
120         }
121         final int enabledServicesBuilderLength = enabledServicesBuilder.length();
122         if (enabledServicesBuilderLength > 0) {
123             enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
124         }
125         Settings.Secure.putString(getContentResolver(),
126                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
127                 enabledServicesBuilder.toString());
128
129         // Update accessibility enabled.
130         Settings.Secure.putInt(getContentResolver(),
131                 Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
132     }
133
134     // IMPORTANT: Refresh the info since there are dynamically changing
135     // capabilities. For
136     // example, before JellyBean MR2 the user was granting the explore by touch
137     // one.
138     private AccessibilityServiceInfo getAccessibilityServiceInfo() {
139         List<AccessibilityServiceInfo> serviceInfos = AccessibilityManager.getInstance(
140                 getActivity()).getInstalledAccessibilityServiceList();
141         final int serviceInfoCount = serviceInfos.size();
142         for (int i = 0; i < serviceInfoCount; i++) {
143             AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
144             ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
145             if (mComponentName.getPackageName().equals(resolveInfo.serviceInfo.packageName)
146                     && mComponentName.getClassName().equals(resolveInfo.serviceInfo.name)) {
147                 return serviceInfo;
148             }
149         }
150         return null;
151     }
152
153     @Override
154     public Dialog onCreateDialog(int dialogId) {
155         switch (dialogId) {
156             case DIALOG_ID_ENABLE_WARNING: {
157             mShownDialogId = DIALOG_ID_ENABLE_WARNING;
158             AccessibilityServiceInfo info = getAccessibilityServiceInfo();
159             if (info == null) {
160                 return null;
161             }
162             return new AlertDialog.Builder(getActivity())
163             .setTitle(getString(R.string.enable_service_title,
164                     info.getResolveInfo().loadLabel(getPackageManager())))
165                     .setIconAttribute(android.R.attr.alertDialogIcon)
166                     .setView(createEnableDialogContentView(info))
167                     .setCancelable(true)
168                     .setPositiveButton(android.R.string.ok, this)
169                     .setNegativeButton(android.R.string.cancel, this)
170                     .create();
171         }
172             case DIALOG_ID_DISABLE_WARNING: {
173             mShownDialogId = DIALOG_ID_DISABLE_WARNING;
174             AccessibilityServiceInfo info = getAccessibilityServiceInfo();
175             if (info == null) {
176                 return null;
177             }
178             return new AlertDialog.Builder(getActivity())
179             .setTitle(getString(R.string.disable_service_title,
180                     info.getResolveInfo().loadLabel(getPackageManager())))
181                     .setIconAttribute(android.R.attr.alertDialogIcon)
182                     .setMessage(getString(R.string.disable_service_message,
183                             info.getResolveInfo().loadLabel(getPackageManager())))
184                     .setCancelable(true)
185                     .setPositiveButton(android.R.string.ok, this)
186                     .setNegativeButton(android.R.string.cancel, this)
187                     .create();
188         }
189             default: {
190             throw new IllegalArgumentException();
191         }
192         }
193     }
194
195     private View createEnableDialogContentView(AccessibilityServiceInfo info) {
196         LayoutInflater inflater = (LayoutInflater) getSystemService(
197                 Context.LAYOUT_INFLATER_SERVICE);
198
199         View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
200                 null);
201
202         TextView capabilitiesHeaderView = (TextView) content.findViewById(
203                 R.id.capabilities_header);
204         capabilitiesHeaderView.setText(getString(R.string.capabilities_list_title,
205                 info.getResolveInfo().loadLabel(getPackageManager())));
206
207         LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
208
209         // This capability is implicit for all services.
210         View capabilityView = inflater.inflate(
211                 com.android.internal.R.layout.app_permission_item_old, null);
212
213         ImageView imageView = (ImageView) capabilityView.findViewById(
214                 com.android.internal.R.id.perm_icon);
215         imageView.setImageDrawable(getResources().getDrawable(
216                 com.android.internal.R.drawable.ic_text_dot));
217
218         TextView labelView = (TextView) capabilityView.findViewById(
219                 com.android.internal.R.id.permission_group);
220         labelView.setText(getString(R.string.capability_title_receiveAccessibilityEvents));
221
222         TextView descriptionView = (TextView) capabilityView.findViewById(
223                 com.android.internal.R.id.permission_list);
224         descriptionView.setText(getString(R.string.capability_desc_receiveAccessibilityEvents));
225
226         List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
227                 info.getCapabilityInfos();
228
229         capabilitiesView.addView(capabilityView);
230
231         // Service specific capabilities.
232         final int capabilityCount = capabilities.size();
233         for (int i = 0; i < capabilityCount; i++) {
234             AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);
235
236             capabilityView = inflater.inflate(
237                     com.android.internal.R.layout.app_permission_item_old, null);
238
239             imageView = (ImageView) capabilityView.findViewById(
240                     com.android.internal.R.id.perm_icon);
241             imageView.setImageDrawable(getResources().getDrawable(
242                     com.android.internal.R.drawable.ic_text_dot));
243
244             labelView = (TextView) capabilityView.findViewById(
245                     com.android.internal.R.id.permission_group);
246             labelView.setText(getString(capability.titleResId));
247
248             descriptionView = (TextView) capabilityView.findViewById(
249                     com.android.internal.R.id.permission_list);
250             descriptionView.setText(getString(capability.descResId));
251
252             capabilitiesView.addView(capabilityView);
253         }
254
255         return content;
256     }
257
258     @Override
259     public void onClick(DialogInterface dialog, int which) {
260         final boolean checked;
261         switch (which) {
262             case DialogInterface.BUTTON_POSITIVE:
263                 checked = (mShownDialogId == DIALOG_ID_ENABLE_WARNING);
264                 mToggleSwitch.setCheckedInternal(checked);
265                 getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
266                 onPreferenceToggled(mPreferenceKey, checked);
267                 break;
268             case DialogInterface.BUTTON_NEGATIVE:
269                 checked = (mShownDialogId == DIALOG_ID_DISABLE_WARNING);
270                 mToggleSwitch.setCheckedInternal(checked);
271                 getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
272                 onPreferenceToggled(mPreferenceKey, checked);
273                 break;
274             default:
275                 throw new IllegalArgumentException();
276         }
277     }
278
279     @Override
280     protected void onInstallActionBarToggleSwitch() {
281         super.onInstallActionBarToggleSwitch();
282         mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
283                 @Override
284             public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
285                 if (checked) {
286                     toggleSwitch.setCheckedInternal(false);
287                     getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, false);
288                     showDialog(DIALOG_ID_ENABLE_WARNING);
289                 } else {
290                     toggleSwitch.setCheckedInternal(true);
291                     getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, true);
292                     showDialog(DIALOG_ID_DISABLE_WARNING);
293                 }
294                 return true;
295             }
296         });
297     }
298
299     @Override
300     protected void onProcessArguments(Bundle arguments) {
301         super.onProcessArguments(arguments);
302         // Settings title and intent.
303         String settingsTitle = arguments.getString(AccessibilitySettings.EXTRA_SETTINGS_TITLE);
304         String settingsComponentName = arguments.getString(
305                 AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
306         if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
307             Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
308                     ComponentName.unflattenFromString(settingsComponentName.toString()));
309             if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
310                 mSettingsTitle = settingsTitle;
311                 mSettingsIntent = settingsIntent;
312                 setHasOptionsMenu(true);
313             }
314         }
315
316         mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
317     }
318 }