summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/accessibility
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2013-07-18 17:49:33 -0700
committerAlan Viverette <alanv@google.com>2013-07-18 17:49:33 -0700
commit341ff66e0374a46f89c51bca2ef55da368b7e40f (patch)
tree9e7cbc5d091b82deb22c0be8249ccc3902682d4d /src/com/android/settings/accessibility
parent8e3405d85a334565e262f41c9a23740c043f83a4 (diff)
downloadpackages_apps_Settings-341ff66e0374a46f89c51bca2ef55da368b7e40f.zip
packages_apps_Settings-341ff66e0374a46f89c51bca2ef55da368b7e40f.tar.gz
packages_apps_Settings-341ff66e0374a46f89c51bca2ef55da368b7e40f.tar.bz2
Move accessibility settings to their own package
Change-Id: I5822bf4a81f5ade4ee0649ed30c2daa40d7e8fe2
Diffstat (limited to 'src/com/android/settings/accessibility')
-rw-r--r--src/com/android/settings/accessibility/AccessibilitySettings.java622
-rw-r--r--src/com/android/settings/accessibility/AccessibilityUtils.java37
-rw-r--r--src/com/android/settings/accessibility/SettingsContentObserver.java43
-rw-r--r--src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java312
-rw-r--r--src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java155
-rw-r--r--src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java44
-rw-r--r--src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java44
-rw-r--r--src/com/android/settings/accessibility/ToggleSwitch.java49
8 files changed, 1306 insertions, 0 deletions
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
new file mode 100644
index 0000000..d2198a7
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+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;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
+import com.android.settings.DialogCreatable;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Activity with the accessibility settings.
+ */
+public class AccessibilitySettings extends SettingsPreferenceFragment implements DialogCreatable,
+ Preference.OnPreferenceChangeListener {
+ private static final String DEFAULT_SCREENREADER_MARKET_LINK =
+ "market://search?q=pname:com.google.android.marvin.talkback";
+
+ private static final float LARGE_FONT_SCALE = 1.3f;
+
+ private static final String SYSTEM_PROPERTY_MARKET_URL = "ro.screenreader.market";
+
+ static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
+
+ private static final String KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE =
+ "key_install_accessibility_service_offered_once";
+
+ // Preference categories
+ private static final String SERVICES_CATEGORY = "services_category";
+ private static final String SYSTEM_CATEGORY = "system_category";
+
+ // Preferences
+ private static final String TOGGLE_LARGE_TEXT_PREFERENCE =
+ "toggle_large_text_preference";
+ private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
+ "toggle_power_button_ends_call_preference";
+ private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE =
+ "toggle_lock_screen_rotation_preference";
+ private static final String TOGGLE_SPEAK_PASSWORD_PREFERENCE =
+ "toggle_speak_password_preference";
+ private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
+ "select_long_press_timeout_preference";
+ private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
+ "enable_global_gesture_preference_screen";
+ private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
+ "screen_magnification_preference_screen";
+
+ // Extras passed to sub-fragments.
+ static final String EXTRA_PREFERENCE_KEY = "preference_key";
+ static final String EXTRA_CHECKED = "checked";
+ static final String EXTRA_TITLE = "title";
+ static final String EXTRA_SUMMARY = "summary";
+ static final String EXTRA_SETTINGS_TITLE = "settings_title";
+ static final String EXTRA_COMPONENT_NAME = "component_name";
+ static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
+
+ // 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_MILLIS = 1000;
+
+ // Dialog IDs.
+ private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1;
+
+ // Auxiliary members.
+ final static SimpleStringSplitter sStringColonSplitter =
+ new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
+
+ static final Set<ComponentName> sInstalledServices = new HashSet<ComponentName>();
+
+ private final Map<String, String> mLongPressTimeoutValuetoTitleMap =
+ new HashMap<String, String>();
+
+ private final Configuration mCurConfig = new Configuration();
+
+ private final Handler mHandler = new Handler();
+
+ private final Runnable mUpdateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ loadInstalledServices();
+ updateServicesPreferences();
+ }
+ };
+
+ private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageAppeared(String packageName, int reason) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ sendUpdate();
+ }
+
+ private void sendUpdate() {
+ mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS);
+ }
+ };
+
+ private final SettingsContentObserver mSettingsContentObserver =
+ new SettingsContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ loadInstalledServices();
+ updateServicesPreferences();
+ }
+ };
+
+ private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() {
+ @Override
+ public void onChange() {
+ updateLockScreenRotationCheckbox();
+ }
+ };
+
+ // Preference controls.
+ private PreferenceCategory mServicesCategory;
+ private PreferenceCategory mSystemsCategory;
+
+ private CheckBoxPreference mToggleLargeTextPreference;
+ private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
+ private CheckBoxPreference mToggleLockScreenRotationPreference;
+ private CheckBoxPreference mToggleSpeakPasswordPreference;
+ private ListPreference mSelectLongPressTimeoutPreference;
+ private Preference mNoServicesMessagePreference;
+ private PreferenceScreen mDisplayMagnificationPreferenceScreen;
+ private PreferenceScreen mGlobalGesturePreferenceScreen;
+
+ private int mLongPressTimeoutDefault;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.accessibility_settings);
+ initializeAllPreferences();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ loadInstalledServices();
+ updateAllPreferences();
+
+ offerInstallAccessibilitySerivceOnce();
+
+ mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
+ mSettingsContentObserver.register(getContentResolver());
+ if (RotationPolicy.isRotationSupported(getActivity())) {
+ RotationPolicy.registerRotationPolicyListener(getActivity(),
+ mRotationPolicyListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mSettingsPackageMonitor.unregister();
+ mSettingsContentObserver.unregister(getContentResolver());
+ if (RotationPolicy.isRotationSupported(getActivity())) {
+ RotationPolicy.unregisterRotationPolicyListener(getActivity(),
+ mRotationPolicyListener);
+ }
+ super.onPause();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mSelectLongPressTimeoutPreference) {
+ String stringValue = (String) newValue;
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
+ mSelectLongPressTimeoutPreference.setSummary(
+ mLongPressTimeoutValuetoTitleMap.get(stringValue));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (mToggleLargeTextPreference == preference) {
+ handleToggleLargeTextPreferenceClick();
+ return true;
+ } else if (mTogglePowerButtonEndsCallPreference == preference) {
+ handleTogglePowerButtonEndsCallPreferenceClick();
+ return true;
+ } else if (mToggleLockScreenRotationPreference == preference) {
+ handleLockScreenRotationPreferenceClick();
+ return true;
+ } else if (mToggleSpeakPasswordPreference == preference) {
+ handleToggleSpeakPasswordPreferenceClick();
+ return true;
+ } else if (mGlobalGesturePreferenceScreen == preference) {
+ handleTogglEnableAccessibilityGesturePreferenceClick();
+ return true;
+ } else if (mDisplayMagnificationPreferenceScreen == preference) {
+ handleDisplayMagnificationPreferenceScreenClick();
+ return true;
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void handleToggleLargeTextPreferenceClick() {
+ try {
+ mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
+ ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
+ private void handleTogglePowerButtonEndsCallPreferenceClick() {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ (mTogglePowerButtonEndsCallPreference.isChecked()
+ ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+ : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
+ }
+
+ private void handleLockScreenRotationPreferenceClick() {
+ RotationPolicy.setRotationLockForAccessibility(getActivity(),
+ !mToggleLockScreenRotationPreference.isChecked());
+ }
+
+ private void handleToggleSpeakPasswordPreferenceClick() {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
+ mToggleSpeakPasswordPreference.isChecked() ? 1 : 0);
+ }
+
+ private void handleTogglEnableAccessibilityGesturePreferenceClick() {
+ Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
+ extras.putString(EXTRA_TITLE, getString(
+ R.string.accessibility_global_gesture_preference_title));
+ extras.putString(EXTRA_SUMMARY, getString(
+ R.string.accessibility_global_gesture_preference_description));
+ extras.putBoolean(EXTRA_CHECKED, Settings.Global.getInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1);
+ super.onPreferenceTreeClick(mGlobalGesturePreferenceScreen,
+ mGlobalGesturePreferenceScreen);
+ }
+
+ private void handleDisplayMagnificationPreferenceScreenClick() {
+ Bundle extras = mDisplayMagnificationPreferenceScreen.getExtras();
+ extras.putString(EXTRA_TITLE, getString(
+ R.string.accessibility_screen_magnification_title));
+ extras.putCharSequence(EXTRA_SUMMARY, getActivity().getResources().getText(
+ R.string.accessibility_screen_magnification_summary));
+ extras.putBoolean(EXTRA_CHECKED, Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1);
+ super.onPreferenceTreeClick(mDisplayMagnificationPreferenceScreen,
+ mDisplayMagnificationPreferenceScreen);
+ }
+
+ private void initializeAllPreferences() {
+ mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
+ mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+
+ // Large text.
+ mToggleLargeTextPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
+
+ // Power button ends calls.
+ mTogglePowerButtonEndsCallPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
+ if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ || !Utils.isVoiceCapable(getActivity())) {
+ mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+ }
+
+ // Lock screen rotation.
+ mToggleLockScreenRotationPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
+ if (!RotationPolicy.isRotationSupported(getActivity())) {
+ mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
+ }
+
+ // Speak passwords.
+ mToggleSpeakPasswordPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_SPEAK_PASSWORD_PREFERENCE);
+
+ // Long press timeout.
+ mSelectLongPressTimeoutPreference =
+ (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
+ mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
+ if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
+ String[] timeoutValues = getResources().getStringArray(
+ R.array.long_press_timeout_selector_values);
+ mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
+ String[] timeoutTitles = getResources().getStringArray(
+ R.array.long_press_timeout_selector_titles);
+ final int timeoutValueCount = timeoutValues.length;
+ for (int i = 0; i < timeoutValueCount; i++) {
+ mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
+ }
+ }
+
+ // Display magnification.
+ mDisplayMagnificationPreferenceScreen = (PreferenceScreen) findPreference(
+ DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
+
+ // Global gesture.
+ mGlobalGesturePreferenceScreen =
+ (PreferenceScreen) findPreference(ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN);
+ final int longPressOnPowerBehavior = getActivity().getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnPowerBehavior);
+ final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
+ if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ || longPressOnPowerBehavior != LONG_PRESS_POWER_GLOBAL_ACTIONS) {
+ // Remove accessibility shortcut if power key is not present
+ // nor long press power does not show global actions menu.
+ mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
+ }
+ }
+
+ private void updateAllPreferences() {
+ updateServicesPreferences();
+ updateSystemPreferences();
+ }
+
+ private void updateServicesPreferences() {
+ // Since services category is auto generated we have to do a pass
+ // to generate it since services can come and go and then based on
+ // the global accessibility state to decided whether it is enabled.
+
+ // Generate.
+ mServicesCategory.removeAll();
+
+ AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
+
+ List<AccessibilityServiceInfo> installedServices =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+ Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
+ getActivity());
+
+ final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
+
+ for (int i = 0, count = installedServices.size(); i < count; ++i) {
+ AccessibilityServiceInfo info = installedServices.get(i);
+
+ PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
+ getActivity());
+ String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
+
+ ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
+ ComponentName componentName = new ComponentName(serviceInfo.packageName,
+ serviceInfo.name);
+
+ preference.setKey(componentName.flattenToString());
+
+ preference.setTitle(title);
+ final boolean serviceEnabled = accessibilityEnabled
+ && enabledServices.contains(componentName);
+ if (serviceEnabled) {
+ preference.setSummary(getString(R.string.accessibility_feature_state_on));
+ } else {
+ preference.setSummary(getString(R.string.accessibility_feature_state_off));
+ }
+
+ preference.setOrder(i);
+ preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
+ preference.setPersistent(true);
+
+ Bundle extras = preference.getExtras();
+ extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
+ extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
+ extras.putString(EXTRA_TITLE, title);
+
+ String description = info.loadDescription(getPackageManager());
+ if (TextUtils.isEmpty(description)) {
+ description = getString(R.string.accessibility_service_default_description);
+ }
+ extras.putString(EXTRA_SUMMARY, description);
+
+ String settingsClassName = info.getSettingsActivityName();
+ if (!TextUtils.isEmpty(settingsClassName)) {
+ extras.putString(EXTRA_SETTINGS_TITLE,
+ getString(R.string.accessibility_menu_item_settings));
+ extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
+ new ComponentName(info.getResolveInfo().serviceInfo.packageName,
+ settingsClassName).flattenToString());
+ }
+
+ extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
+
+ mServicesCategory.addPreference(preference);
+ }
+
+ if (mServicesCategory.getPreferenceCount() == 0) {
+ if (mNoServicesMessagePreference == null) {
+ mNoServicesMessagePreference = new Preference(getActivity()) {
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ TextView summaryView = (TextView) view.findViewById(R.id.summary);
+ String title = getString(R.string.accessibility_no_services_installed);
+ summaryView.setText(title);
+ }
+ };
+ mNoServicesMessagePreference.setPersistent(false);
+ mNoServicesMessagePreference.setLayoutResource(
+ R.layout.text_description_preference);
+ mNoServicesMessagePreference.setSelectable(false);
+ }
+ mServicesCategory.addPreference(mNoServicesMessagePreference);
+ }
+ }
+
+ private void updateSystemPreferences() {
+ // Large text.
+ try {
+ mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
+
+ // Power button ends calls.
+ if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ && Utils.isVoiceCapable(getActivity())) {
+ final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
+ final boolean powerButtonEndsCall =
+ (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
+ mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
+ }
+
+ // Auto-rotate screen
+ updateLockScreenRotationCheckbox();
+
+ // Speak passwords.
+ final boolean speakPasswordEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
+ mToggleSpeakPasswordPreference.setChecked(speakPasswordEnabled);
+
+ // Long press timeout.
+ final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
+ String value = String.valueOf(longPressTimeout);
+ mSelectLongPressTimeoutPreference.setValue(value);
+ mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
+
+ // Screen magnification.
+ final boolean magnificationEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;
+ if (magnificationEnabled) {
+ mDisplayMagnificationPreferenceScreen.setSummary(
+ R.string.accessibility_feature_state_on);
+ } else {
+ mDisplayMagnificationPreferenceScreen.setSummary(
+ R.string.accessibility_feature_state_off);
+ }
+
+ // Global gesture
+ final boolean globalGestureEnabled = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
+ if (globalGestureEnabled) {
+ mGlobalGesturePreferenceScreen.setSummary(
+ R.string.accessibility_global_gesture_preference_summary_on);
+ } else {
+ mGlobalGesturePreferenceScreen.setSummary(
+ R.string.accessibility_global_gesture_preference_summary_off);
+ }
+ }
+
+ private void updateLockScreenRotationCheckbox() {
+ Context context = getActivity();
+ if (context != null) {
+ mToggleLockScreenRotationPreference.setChecked(
+ !RotationPolicy.isRotationLocked(context));
+ }
+ }
+
+ private void offerInstallAccessibilitySerivceOnce() {
+ // There is always one preference - if no services it is just a message.
+ if (mServicesCategory.getPreference(0) != mNoServicesMessagePreference) {
+ return;
+ }
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean offerInstallService = !preferences.getBoolean(
+ KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE, false);
+ if (offerInstallService) {
+ String screenreaderMarketLink = SystemProperties.get(
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
+ Uri marketUri = Uri.parse(screenreaderMarketLink);
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
+
+ if (getPackageManager().resolveActivity(marketIntent, 0) == null) {
+ // Don't show the dialog if no market app is found/installed.
+ return;
+ }
+
+ preferences.edit().putBoolean(KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE,
+ true).commit();
+ // Notify user that they do not have any accessibility
+ // services installed and direct them to Market to get TalkBack.
+ showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(int dialogId) {
+ switch (dialogId) {
+ case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.accessibility_service_no_apps_title)
+ .setMessage(R.string.accessibility_service_no_apps_message)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // dismiss the dialog before launching
+ // the activity otherwise the dialog
+ // removal occurs after
+ // onSaveInstanceState which triggers an
+ // exception
+ removeDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
+ String screenreaderMarketLink = SystemProperties.get(
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
+ Uri marketUri = Uri.parse(screenreaderMarketLink);
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW,
+ marketUri);
+ startActivity(marketIntent);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ default:
+ return null;
+ }
+ }
+
+ private void loadInstalledServices() {
+ Set<ComponentName> installedServices = sInstalledServices;
+ installedServices.clear();
+
+ List<AccessibilityServiceInfo> installedServiceInfos =
+ AccessibilityManager.getInstance(getActivity())
+ .getInstalledAccessibilityServiceList();
+ if (installedServiceInfos == null) {
+ return;
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityUtils.java b/src/com/android/settings/accessibility/AccessibilityUtils.java
new file mode 100644
index 0000000..fd4a34f
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityUtils.java
@@ -0,0 +1,37 @@
+package com.android.settings.accessibility;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils.SimpleStringSplitter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * TODO: Insert description here. (generated by alanv)
+ */
+public class AccessibilityUtils {
+
+ static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
+ String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ if (enabledServicesSetting == null) {
+ enabledServicesSetting = "";
+ }
+ Set<ComponentName> enabledServices = new HashSet<ComponentName>();
+ SimpleStringSplitter colonSplitter = AccessibilitySettings.sStringColonSplitter;
+ colonSplitter.setString(enabledServicesSetting);
+ while (colonSplitter.hasNext()) {
+ String componentNameString = colonSplitter.next();
+ ComponentName enabledService = ComponentName.unflattenFromString(
+ componentNameString);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
+ }
+ return enabledServices;
+ }
+
+}
diff --git a/src/com/android/settings/accessibility/SettingsContentObserver.java b/src/com/android/settings/accessibility/SettingsContentObserver.java
new file mode 100644
index 0000000..c3baec5
--- /dev/null
+++ b/src/com/android/settings/accessibility/SettingsContentObserver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+
+abstract class SettingsContentObserver extends ContentObserver {
+ public SettingsContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register(ContentResolver contentResolver) {
+ contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_ENABLED), false, this);
+ contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES), false, this);
+ }
+
+ public void unregister(ContentResolver contentResolver) {
+ contentResolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public abstract void onChange(boolean selfChange, Uri uri);
+}
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
new file mode 100644
index 0000000..3059dcc
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+import java.util.List;
+import java.util.Set;
+
+public class ToggleAccessibilityServicePreferenceFragment
+ extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
+
+ private static final int DIALOG_ID_ENABLE_WARNING = 1;
+ private static final int DIALOG_ID_DISABLE_WARNING = 2;
+
+ private final SettingsContentObserver mSettingsContentObserver =
+ new SettingsContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ String settingValue = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ final boolean enabled = settingValue.contains(mComponentName.flattenToString());
+ mToggleSwitch.setCheckedInternal(enabled);
+ }
+ };
+
+ private ComponentName mComponentName;
+
+ private int mShownDialogId;
+
+ @Override
+ public void onResume() {
+ mSettingsContentObserver.register(getContentResolver());
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ mSettingsContentObserver.unregister(getContentResolver());
+ super.onPause();
+ }
+
+ @Override
+ public void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ // Parse the enabled services.
+ Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
+ getActivity());
+
+ // Determine enabled services and accessibility state.
+ ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
+ boolean accessibilityEnabled = false;
+ if (enabled) {
+ enabledServices.add(toggledService);
+ // Enabling at least one service enables accessibility.
+ accessibilityEnabled = true;
+ } else {
+ enabledServices.remove(toggledService);
+ // Check how many enabled and installed services are present.
+ Set<ComponentName> installedServices = AccessibilitySettings.sInstalledServices;
+ for (ComponentName enabledService : enabledServices) {
+ if (installedServices.contains(enabledService)) {
+ // Disabling the last service disables accessibility.
+ accessibilityEnabled = true;
+ break;
+ }
+ }
+ }
+
+ // 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(
+ AccessibilitySettings.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);
+ }
+
+ // IMPORTANT: Refresh the info since there are dynamically changing
+ // capabilities. For
+ // example, before JellyBean MR2 the user was granting the explore by touch
+ // one.
+ private AccessibilityServiceInfo getAccessibilityServiceInfo() {
+ List<AccessibilityServiceInfo> serviceInfos = AccessibilityManager.getInstance(
+ getActivity()).getInstalledAccessibilityServiceList();
+ final int serviceInfoCount = serviceInfos.size();
+ for (int i = 0; i < serviceInfoCount; i++) {
+ AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
+ ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
+ if (mComponentName.getPackageName().equals(resolveInfo.serviceInfo.packageName)
+ && mComponentName.getClassName().equals(resolveInfo.serviceInfo.name)) {
+ return serviceInfo;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Dialog onCreateDialog(int dialogId) {
+ switch (dialogId) {
+ case DIALOG_ID_ENABLE_WARNING: {
+ mShownDialogId = DIALOG_ID_ENABLE_WARNING;
+ AccessibilityServiceInfo info = getAccessibilityServiceInfo();
+ if (info == null) {
+ return null;
+ }
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getString(R.string.enable_service_title,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setView(createEnableDialogContentView(info))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ }
+ case DIALOG_ID_DISABLE_WARNING: {
+ mShownDialogId = DIALOG_ID_DISABLE_WARNING;
+ AccessibilityServiceInfo info = getAccessibilityServiceInfo();
+ if (info == null) {
+ return null;
+ }
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getString(R.string.disable_service_title,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(getString(R.string.disable_service_message,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ }
+ default: {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ private View createEnableDialogContentView(AccessibilityServiceInfo info) {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
+ null);
+
+ TextView capabilitiesHeaderView = (TextView) content.findViewById(
+ R.id.capabilities_header);
+ capabilitiesHeaderView.setText(getString(R.string.capabilities_list_title,
+ info.getResolveInfo().loadLabel(getPackageManager())));
+
+ LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
+
+ // This capability is implicit for all services.
+ View capabilityView = inflater.inflate(
+ com.android.internal.R.layout.app_permission_item_old, null);
+
+ ImageView imageView = (ImageView) capabilityView.findViewById(
+ com.android.internal.R.id.perm_icon);
+ imageView.setImageDrawable(getResources().getDrawable(
+ com.android.internal.R.drawable.ic_text_dot));
+
+ TextView labelView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_group);
+ labelView.setText(getString(R.string.capability_title_receiveAccessibilityEvents));
+
+ TextView descriptionView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_list);
+ descriptionView.setText(getString(R.string.capability_desc_receiveAccessibilityEvents));
+
+ List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
+ info.getCapabilityInfos();
+
+ capabilitiesView.addView(capabilityView);
+
+ // Service specific capabilities.
+ final int capabilityCount = capabilities.size();
+ for (int i = 0; i < capabilityCount; i++) {
+ AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);
+
+ capabilityView = inflater.inflate(
+ com.android.internal.R.layout.app_permission_item_old, null);
+
+ imageView = (ImageView) capabilityView.findViewById(
+ com.android.internal.R.id.perm_icon);
+ imageView.setImageDrawable(getResources().getDrawable(
+ com.android.internal.R.drawable.ic_text_dot));
+
+ labelView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_group);
+ labelView.setText(getString(capability.titleResId));
+
+ descriptionView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_list);
+ descriptionView.setText(getString(capability.descResId));
+
+ capabilitiesView.addView(capabilityView);
+ }
+
+ return content;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final boolean checked;
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ checked = (mShownDialogId == DIALOG_ID_ENABLE_WARNING);
+ mToggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ checked = (mShownDialogId == DIALOG_ID_DISABLE_WARNING);
+ mToggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ if (checked) {
+ toggleSwitch.setCheckedInternal(false);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, false);
+ showDialog(DIALOG_ID_ENABLE_WARNING);
+ } else {
+ toggleSwitch.setCheckedInternal(true);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, true);
+ showDialog(DIALOG_ID_DISABLE_WARNING);
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void onProcessArguments(Bundle arguments) {
+ super.onProcessArguments(arguments);
+ // Settings title and intent.
+ String settingsTitle = arguments.getString(AccessibilitySettings.EXTRA_SETTINGS_TITLE);
+ String settingsComponentName = arguments.getString(
+ AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
+ if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
+ Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
+ ComponentName.unflattenFromString(settingsComponentName.toString()));
+ if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
+ mSettingsTitle = settingsTitle;
+ mSettingsIntent = settingsIntent;
+ setHasOptionsMenu(true);
+ }
+ }
+
+ mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
new file mode 100644
index 0000000..171b1ac
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+public abstract class ToggleFeaturePreferenceFragment
+ extends SettingsPreferenceFragment {
+
+ protected ToggleSwitch mToggleSwitch;
+
+ protected String mPreferenceKey;
+ protected Preference mSummaryPreference;
+
+ protected CharSequence mSettingsTitle;
+ protected Intent mSettingsIntent;
+
+ // TODO: Showing sub-sub fragment does not handle the activity title
+ // so we do it but this is wrong. Do a real fix when there is time.
+ private CharSequence mOldActivityTitle;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
+ getActivity());
+ setPreferenceScreen(preferenceScreen);
+ mSummaryPreference = new Preference(getActivity()) {
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ TextView summaryView = (TextView) view.findViewById(R.id.summary);
+ summaryView.setText(getSummary());
+ sendAccessibilityEvent(summaryView);
+ }
+
+ private void sendAccessibilityEvent(View view) {
+ // Since the view is still not attached we create, populate,
+ // and send the event directly since we do not know when it
+ // will be attached and posting commands is not as clean.
+ AccessibilityManager accessibilityManager =
+ AccessibilityManager.getInstance(getActivity());
+ if (accessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ view.onInitializeAccessibilityEvent(event);
+ view.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+ }
+ };
+ mSummaryPreference.setPersistent(false);
+ mSummaryPreference.setLayoutResource(R.layout.text_description_preference);
+ preferenceScreen.addPreference(mSummaryPreference);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ onInstallActionBarToggleSwitch();
+ onProcessArguments(getArguments());
+ // Set a transparent drawable to prevent use of the default one.
+ getListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
+ getListView().setDivider(null);
+ }
+
+ @Override
+ public void onDestroyView() {
+ getActivity().getActionBar().setCustomView(null);
+ if (mOldActivityTitle != null) {
+ getActivity().getActionBar().setTitle(mOldActivityTitle);
+ }
+ mToggleSwitch.setOnBeforeCheckedChangeListener(null);
+ super.onDestroyView();
+ }
+
+ protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ MenuItem menuItem = menu.add(mSettingsTitle);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menuItem.setIntent(mSettingsIntent);
+ }
+
+ protected void onInstallActionBarToggleSwitch() {
+ mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
+ }
+
+ private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
+ ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
+ final int padding = activity.getResources().getDimensionPixelSize(
+ R.dimen.action_bar_switch_padding);
+ toggleSwitch.setPaddingRelative(0, 0, padding, 0);
+ activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+ ActionBar.DISPLAY_SHOW_CUSTOM);
+ activity.getActionBar().setCustomView(toggleSwitch,
+ new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
+ ActionBar.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_VERTICAL | Gravity.END));
+ return toggleSwitch;
+ }
+
+ protected void onProcessArguments(Bundle arguments) {
+ // Key.
+ mPreferenceKey = arguments.getString(AccessibilitySettings.EXTRA_PREFERENCE_KEY);
+ // Enabled.
+ final boolean enabled = arguments.getBoolean(AccessibilitySettings.EXTRA_CHECKED);
+ mToggleSwitch.setCheckedInternal(enabled);
+ // Title.
+ PreferenceActivity activity = (PreferenceActivity) getActivity();
+ if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
+ mOldActivityTitle = getActivity().getTitle();
+ String title = arguments.getString(AccessibilitySettings.EXTRA_TITLE);
+ getActivity().getActionBar().setTitle(title);
+ }
+ // Summary.
+ CharSequence summary = arguments.getCharSequence(AccessibilitySettings.EXTRA_SUMMARY);
+ mSummaryPreference.setSummary(summary);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java
new file mode 100644
index 0000000..f4ac2cc
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.provider.Settings;
+
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+public class ToggleGlobalGesturePreferenceFragment
+ extends ToggleFeaturePreferenceFragment {
+ @Override
+ protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, enabled ? 1 : 0);
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ toggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ return false;
+ }
+ });
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
new file mode 100644
index 0000000..27d07d2
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.provider.Settings;
+
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+public class ToggleScreenMagnificationPreferenceFragment
+ extends ToggleFeaturePreferenceFragment {
+ @Override
+ protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, enabled ? 1 : 0);
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ toggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ return false;
+ }
+ });
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleSwitch.java b/src/com/android/settings/accessibility/ToggleSwitch.java
new file mode 100644
index 0000000..e7c39e4
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleSwitch.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.widget.Switch;
+
+public class ToggleSwitch extends Switch {
+ private ToggleSwitch.OnBeforeCheckedChangeListener mOnBeforeListener;
+
+ public static interface OnBeforeCheckedChangeListener {
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
+ }
+
+ public ToggleSwitch(Context context) {
+ super(context);
+ }
+
+ public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
+ mOnBeforeListener = listener;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mOnBeforeListener != null
+ && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
+ return;
+ }
+ super.setChecked(checked);
+ }
+
+ public void setCheckedInternal(boolean checked) {
+ super.setChecked(checked);
+ }
+}