diff options
author | Alan Viverette <alanv@google.com> | 2013-07-18 17:49:33 -0700 |
---|---|---|
committer | Alan Viverette <alanv@google.com> | 2013-07-18 17:49:33 -0700 |
commit | 341ff66e0374a46f89c51bca2ef55da368b7e40f (patch) | |
tree | 9e7cbc5d091b82deb22c0be8249ccc3902682d4d /src/com/android/settings/accessibility | |
parent | 8e3405d85a334565e262f41c9a23740c043f83a4 (diff) | |
download | packages_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')
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); + } +} |