From 232d031a13244e8a2a9a56909e9cdaa2b35f6e00 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Tue, 20 Sep 2011 11:10:44 -0700 Subject: [PATCH] Accessibility settings get into state not allowing to enable accessibility. If the setting for enabled accessibility serivces contains a service that is not installed on the device the system gets into a state that does not allow enabling accessibility. This state is not recoverable. bug:5343351 Change-Id: I6127ae00f7a16b190cfe43b68b8e71d49b10911e --- .../settings/AccessibilitySettings.java | 128 ++++++++++++------ 1 file changed, 85 insertions(+), 43 deletions(-) diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java index 3718cedf09e..3de275b0cc4 100644 --- a/src/com/android/settings/AccessibilitySettings.java +++ b/src/com/android/settings/AccessibilitySettings.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; import android.net.Uri; @@ -82,7 +83,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements // Timeout before we update the services if packages are added/removed since // the AccessibilityManagerService has to do that processing first to generate // the AccessibilityServiceInfo we need for proper presentation. - private static final long DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS = 1000; + private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000; private static final String ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ":"; @@ -125,9 +126,12 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1; // Auxiliary members. - private final SimpleStringSplitter mStringColonSplitter = + private final static SimpleStringSplitter sStringColonSplitter = new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR.charAt(0)); + private static final Set sInstalledServices = new HashSet(); + private static final Set sEnabledServices = new HashSet(); + private final Map mLongPressTimeoutValuetoTitleMap = new HashMap(); @@ -139,6 +143,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements @Override public void dispatchMessage(Message msg) { super.dispatchMessage(msg); + loadInstalledServices(); updateServicesPreferences(); } }; @@ -167,6 +172,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements @Override public void onResume() { super.onResume(); + loadInstalledServices(); updateAllPreferences(); if (mServicesCategory.getPreference(0) == mNoServicesMessagePreference) { offerInstallAccessibilitySerivceOnce(); @@ -296,7 +302,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements String settingValue = Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if (settingValue != null) { - SimpleStringSplitter splitter = mStringColonSplitter; + SimpleStringSplitter splitter = sStringColonSplitter; splitter.setString(settingValue); while (splitter.hasNext()) { enabledComponentNames.add(ComponentName.unflattenFromString(splitter.next())); @@ -493,30 +499,46 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements } } + private void loadInstalledServices() { + List installedServiceInfos = + AccessibilityManager.getInstance(getActivity()) + .getInstalledAccessibilityServiceList(); + Set installedServices = sInstalledServices; + installedServices.clear(); + final int installedServiceInfoCount = installedServiceInfos.size(); + for (int i = 0; i < installedServiceInfoCount; i++) { + ResolveInfo resolveInfo = installedServiceInfos.get(i).getResolveInfo(); + ComponentName installedService = new ComponentName( + resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name); + installedServices.add(installedService); + } + } + private class SettingsPackageMonitor extends PackageMonitor { @Override public void onPackageAdded(String packageName, int uid) { Message message = mHandler.obtainMessage(); - mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS); + mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS); } @Override public void onPackageAppeared(String packageName, int reason) { Message message = mHandler.obtainMessage(); - mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS); + mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS); } @Override public void onPackageDisappeared(String packageName, int reason) { Message message = mHandler.obtainMessage(); - mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS); + mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS); } @Override public void onPackageRemoved(String packageName, int uid) { Message message = mHandler.obtainMessage(); - mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS); + mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS); } } @@ -567,49 +589,69 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements public static class ToggleAccessibilityServiceFragment extends TogglePreferenceFragment { @Override public void onPreferenceToggled(String preferenceKey, boolean enabled) { - String enabledServices = Settings.Secure.getString(getContentResolver(), + String enabledServicesSetting = Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); - if (enabledServices == null) { - enabledServices = ""; + if (enabledServicesSetting == null) { + enabledServicesSetting = ""; } - // Due to a legacy bug we can get an enabled services value ending with a - // separator. Make sure to catch and fix that before handling. - if (enabledServices.endsWith(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR)) { - enabledServices = enabledServices.substring(0, enabledServices.length() - 1); + + // Parse the enabled services. + Set enabledServices = sEnabledServices; + enabledServices.clear(); + SimpleStringSplitter colonSplitter = sStringColonSplitter; + colonSplitter.setString(enabledServicesSetting); + while (colonSplitter.hasNext()) { + String componentNameString = colonSplitter.next(); + ComponentName enabledService = ComponentName.unflattenFromString( + componentNameString); + if (enabledService != null) { + enabledServices.add(enabledService); + } } - final int length = enabledServices.length(); + + // Determine enabled services and accessibility state. + ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey); + final boolean accessibilityEnabled; if (enabled) { - if (enabledServices.contains(preferenceKey)) { - return; - } - if (length == 0) { - enabledServices += preferenceKey; - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices); - // Enabling the first service enables accessibility. - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 1); - } else if (length > 0) { - enabledServices += ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR + preferenceKey; - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices); - } + // Enabling at least one service enables accessibility. + accessibilityEnabled = true; + enabledServices.add(toggledService); } else { - final int index = enabledServices.indexOf(preferenceKey); - if (index == 0) { - enabledServices = enabledServices.replace(preferenceKey, ""); - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices); - // Disabling the last service disables accessibility). - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0); - } else if (index > 0) { - enabledServices = enabledServices.replace( - ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR + preferenceKey, ""); - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices); + // Check how many enabled and installed services are present. + int enabledAndInstalledServiceCount = 0; + Set installedServices = sInstalledServices; + for (ComponentName enabledService : enabledServices) { + if (installedServices.contains(enabledService)) { + enabledAndInstalledServiceCount++; + } } + // Disabling the last service disables accessibility. + accessibilityEnabled = enabledAndInstalledServiceCount > 1 + || (enabledAndInstalledServiceCount == 1 + && !installedServices.contains(toggledService)); + enabledServices.remove(toggledService); } + + // Update the enabled services setting. + StringBuilder enabledServicesBuilder = new StringBuilder(); + // Keep the enabled services even if they are not installed since we have + // no way to know whether the application restore process has completed. + // In general the system should be responsible for the clean up not settings. + for (ComponentName enabledService : enabledServices) { + enabledServicesBuilder.append(enabledService.flattenToString()); + enabledServicesBuilder.append(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR); + } + final int enabledServicesBuilderLength = enabledServicesBuilder.length(); + if (enabledServicesBuilderLength > 0) { + enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1); + } + Settings.Secure.putString(getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + enabledServicesBuilder.toString()); + + // Update accessibility enabled. + Settings.Secure.putInt(getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0); } }