Polish of the accessibility settings.
Change-Id: Ifb32ec6745e566cf7ffafe20019b68d95661b45d
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cf35ba8..f812010 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2681,9 +2681,8 @@
<!-- Title for accessibility preference to enable touch exploration mode. [CHAR LIMIT=35] -->
<string name="accessibility_touch_exploration_title">Explore by touch</string>
<!-- Summary for accessibility of the touch exploration mode. [CHAR LIMIT=NONE] -->
- <string name="accessibility_touch_exploration_summary" >Allows exploring screen content and interacting with the device.\n\n
- Touch the screen to receive feedback of the content under your finger.\n\n Tap on the last explored location to activate.\n\n
- Use two fingers to drag. </string>
+ <string name="accessibility_touch_exploration_summary" >When Explore by Touch is turned on,
+ you can hear or see descriptions of what\'s under your finger.\n\n This feature is for low-vision users.</string>
<!-- Title for accessibility preference to choose long-press delay i.e. timeout before it is detected. [CHAR LIMIT=35] -->
<string name="accessibility_long_press_timeout_title">Touch & hold delay</string>
<!-- Title for accessibility preference to install accessibility scripts from Google. [CHAR LIMIT=35] -->
@@ -2710,31 +2709,37 @@
<string name="accessibility_script_injection_button_disallow">Don\'t Allow</string>
<!-- Warning message about security implications of enabling an accessibility service,
- displayed as a dialog message when the user selects to enable an accessibility service. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_security_warning">This accessibility service may be able to collect
- all the text you type, including personal data credit card numbers except passwords.
- It may also log your user interface interactions. It comes from the application
- <xliff:g id="accessibility_service_name">%1$s</xliff:g>. Use this accessibility service?</string>
- <!-- Warning about disabling accessibility displayed as a dialog message when the user
+ displayed as a dialog message when the user selects to enable an accessibility service (tablet). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_security_warning">
+ <xliff:g id="accessibility_service_name">%1$s</xliff:g> can
+ collect all of the text you type, except passwords. This includes personal data such as credit card
+ numbers. It can also collect data about your interactions with the device.</string>
+ <!-- Title for a warning about disabling accessibility displayed as a dialog message when the user
+ selects to disable accessibility. This avoids accidental disabling. [CHAR LIMIT=30] -->
+ <string name="accessibility_disable_warning_title">Turn accessibility off?</string>
+ <!-- Summary for a warning about disabling accessibility displayed as a dialog message when the user
selects to disable accessibility. This avoids accidental disabling. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_disable_warning">Disable accessibility?</string>
+ <string name="accessibility_disable_warning_summary">Touching OK will stop spoken
+ descriptions and all other accessibility features you\'ve been using.</string>
<!-- Title for the prompt that lets users know that they have no accessibility related apps
installed and that they can install TalkBack from Market. [CHAR LIMIT=50] -->
- <string name="accessibility_service_no_apps_title">No accessibility related applications found
+ <string name="accessibility_service_no_apps_title">No accessibility applications
</string>
<!-- Message for the prompt that lets users know that they have no accessibility related apps
installed and that they can install TalkBack from Market. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_no_apps_message">You do not have any accessibility-related
- applications installed.\n\nYou can download a screen reader for your device from Android
- Market.\n\nClick "OK" to install the screen reader.</string>
+ <string name="accessibility_service_no_apps_message">You don\'t have accessibility
+ applications installed. Do you want to download a screen reader from the Android Market?</string>
<!-- Warning message about security implications of downloading accessibility scripts,
displayed as a dialog message when the user selects to enable script downloading. [CHAR LIMIT=NONE] -->
- <string name="accessibility_script_injection_security_warning">Some applications can ask Google
- to download scripts to your device that make their content more accessible. Are you sure you
- want to allow Google to install accessibility scripts on your device?</string>
+ <string name="accessibility_script_injection_security_warning">Do you want applications to install
+ scripts from Google that will make their content more accessible?</string>
<!-- Warning message that the interaction model changes on enabling touch exploration. [CHAR LIMIT=NONE] -->
<string name="accessibility_touch_exploration_warning">Enabling explore by touch
- changes the interation model. Enable explore by touch?</string>
+ changes how the devices respons to touch. Enable explore by touch?</string>
+ <!-- Default description for an accessiiblity serivice if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_default_description">This accessibility service has no
+ description.\n\nAccessibility services provide various types of feedback when you interact
+ with the device. </string>
<!-- App Fuel Gauge strings -->
<skip />
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 78a857b..4dbca6d 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -30,12 +30,12 @@
<CheckBoxPreference
android:key="toggle_large_text_preference"
android:title="@string/accessibility_toggle_large_text_title"
- android:persistent="false"/>
+ android:persistent="true"/>
<CheckBoxPreference
android:key="toggle_power_button_ends_call_preference"
android:title="@string/accessibility_power_button_ends_call_title"
- android:persistent="false">
+ android:persistent="true">
</CheckBoxPreference>
<PreferenceScreen
@@ -55,10 +55,15 @@
android:entryValues="@array/long_press_timeout_selector_values"
android:persistent="true" />
- <Preference
+ <com.android.settings.AccessibilityEnableScriptInjectionPreference
android:key="toggle_script_injection_preference"
android:title="@string/accessibility_script_injection_title"
- android:persistent="false" />
+ android:dialogTitle="@android:string/dialog_alert_title"
+ android:dialogIcon="@android:drawable/ic_dialog_alert"
+ android:dialogMessage="@string/accessibility_script_injection_security_warning"
+ android:positiveButtonText="@string/accessibility_script_injection_button_allow"
+ android:negativeButtonText="@string/accessibility_script_injection_button_disallow"
+ android:persistent="true" />
</PreferenceCategory>
diff --git a/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java b/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java
new file mode 100644
index 0000000..a9338ed
--- /dev/null
+++ b/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.DialogPreference;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+/**
+ * Preference for enabling accessibility script injection. It displays a warning
+ * dialog before enabling the preference.
+ */
+public class AccessibilityEnableScriptInjectionPreference extends DialogPreference {
+
+ private boolean mInjectionAllowed;
+ private boolean mSendClickAccessibilityEvent;
+
+ public AccessibilityEnableScriptInjectionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ updateSummary();
+ }
+
+ public void setInjectionAllowed(boolean injectionAllowed) {
+ if (mInjectionAllowed != injectionAllowed) {
+ mInjectionAllowed = injectionAllowed;
+ persistBoolean(injectionAllowed);
+ updateSummary();
+ }
+ }
+
+ public boolean isInjectionAllowed() {
+ return mInjectionAllowed;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ View summaryView = view.findViewById(com.android.internal.R.id.summary);
+ 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(getContext());
+ if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ view.onInitializeAccessibilityEvent(event);
+ view.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+ mSendClickAccessibilityEvent = false;
+ }
+
+ @Override
+ protected void onClick() {
+ if (isInjectionAllowed()) {
+ setInjectionAllowed(false);
+ // Update the system setting only upon user action.
+ setSystemSetting(false);
+ mSendClickAccessibilityEvent = true;
+ } else {
+ super.onClick();
+ mSendClickAccessibilityEvent = false;
+ }
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getBoolean(index, false);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setInjectionAllowed(restoreValue
+ ? getPersistedBoolean(mInjectionAllowed)
+ : (Boolean) defaultValue);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean result) {
+ setInjectionAllowed(result);
+ if (result) {
+ // Update the system setting only upon user action.
+ setSystemSetting(true);
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ return superState;
+ }
+ SavedState myState = new SavedState(superState);
+ myState.mInjectionAllowed = mInjectionAllowed;
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setInjectionAllowed(myState.mInjectionAllowed);
+ }
+
+ private void updateSummary() {
+ setSummary(mInjectionAllowed
+ ? getContext().getString(R.string.accessibility_script_injection_allowed)
+ : getContext().getString(R.string.accessibility_script_injection_disallowed));
+ }
+
+ private void setSystemSetting(boolean enabled) {
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0);
+ }
+
+ private static class SavedState extends BaseSavedState {
+ private boolean mInjectionAllowed;
+
+ public SavedState(Parcel source) {
+ super(source);
+ mInjectionAllowed = (source.readInt() == 1);
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeInt(mInjectionAllowed ? 1 : 0);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @SuppressWarnings("all")
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index beef902..a4b7975 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.net.Uri;
@@ -37,6 +38,7 @@
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
@@ -49,6 +51,7 @@
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.Switch;
import android.widget.TextView;
@@ -73,6 +76,8 @@
private static final float LARGE_FONT_SCALE = 1.3f;
+ private static final String SYSTEM_PROPERTY_MARKET_URL = "ro.screenreader.market";
+
// 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.
@@ -80,8 +85,15 @@
private static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
+ private static final String KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE =
+ "key_accessibility_tutorial_launched_once";
+
+ 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";
@@ -95,18 +107,17 @@
"toggle_script_injection_preference";
// 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_WARNING_MESSAGE = "warning_message";
- static final String EXTRA_SETTINGS_TITLE = "settings_title";
- static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
+ private static final String EXTRA_PREFERENCE_KEY = "preference_key";
+ private static final String EXTRA_CHECKED = "checked";
+ private static final String EXTRA_TITLE = "title";
+ private static final String EXTRA_SUMMARY = "summary";
+ private static final String EXTRA_WARNING_MESSAGE = "warning_message";
+ private static final String EXTRA_SETTINGS_TITLE = "settings_title";
+ private static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
// Dialog IDs.
private static final int DIALOG_ID_DISABLE_ACCESSIBILITY = 1;
- private static final int DIALOG_ID_ENABLE_SCRIPT_INJECTION = 2;
- private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 3;
+ private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 2;
// Auxiliary members.
private final SimpleStringSplitter mStringColonSplitter =
@@ -123,7 +134,7 @@
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
- updateServicesPreferences();
+ updateServicesPreferences(mToggleAccessibilitySwitch.isChecked());
}
};
@@ -131,103 +142,96 @@
private ToggleSwitch mToggleAccessibilitySwitch;
private PreferenceCategory mServicesCategory;
+ private PreferenceCategory mSystemsCategory;
private CheckBoxPreference mToggleLargeTextPreference;
private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
- private Preference mTouchExplorationEnabledPreference;
+ private Preference mToggleTouchExplorationPreference;
private ListPreference mSelectLongPressTimeoutPreference;
- private Preference mToggleScriptInjectionPreference;
+ private AccessibilityEnableScriptInjectionPreference mToggleScriptInjectionPreference;
+
+ private int mLongPressTimeoutDefault;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.accessibility_settings);
- installToggleAccessibilitySwitch();
- findPreferences();
+ initializeAllPreferences();
}
@Override
public void onResume() {
super.onResume();
- updateServicesPreferences();
- updateSystemPreferences();
- updatePreferencesForAccessibilityState();
+ final boolean accessibilityEnabled = mToggleAccessibilitySwitch.isChecked();
+ updateAllPreferences(accessibilityEnabled);
+ if (accessibilityEnabled) {
+ offerInstallAccessibilitySerivceOnce();
+ }
mSettingsPackageMonitor.register(getActivity(), false);
}
@Override
public void onPause() {
- super.onPause();
mSettingsPackageMonitor.unregister();
+ super.onPause();
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ addToggleAccessibilitySwitch();
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onDestroyView() {
+ removeToggleAccessibilitySwitch();
+ super.onDestroyView();
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mSelectLongPressTimeoutPreference) {
- final int intValue = Integer.parseInt((String) newValue);
+ String stringValue = (String) newValue;
Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, intValue);
+ Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(String.valueOf(intValue)));
+ mLongPressTimeoutValuetoTitleMap.get(stringValue));
return true;
}
return false;
}
- private void updatePreferencesForAccessibilityState() {
- final boolean accessibilityEnabled = (Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
- mServicesCategory.setEnabled(accessibilityEnabled);
- mTouchExplorationEnabledPreference.setEnabled(accessibilityEnabled);
- mToggleScriptInjectionPreference.setEnabled(accessibilityEnabled);
- }
-
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
final String key = preference.getKey();
if (mToggleLargeTextPreference == preference) {
- handleToggleLargeTextPreference((CheckBoxPreference) preference);
+ handleToggleLargeTextPreferenceClick();
return true;
} else if (mTogglePowerButtonEndsCallPreference == preference) {
- handleTogglePowerButtonEndsCallPreference((CheckBoxPreference) preference);
- return true;
- } else if (mToggleScriptInjectionPreference == preference) {
- handleToggleAccessibilityScriptInjectionPreference(preference);
+ handleTogglePowerButtonEndsCallPreferenceClick();
return true;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
- private void handleTogglePowerButtonEndsCallPreference(CheckBoxPreference preference) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
- (preference.isChecked() ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
- : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
- }
-
- private void handleToggleLargeTextPreference(CheckBoxPreference preference) {
+ private void handleToggleLargeTextPreferenceClick() {
try {
- mCurConfig.fontScale = preference.isChecked() ? LARGE_FONT_SCALE : 1;
+ mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
- } catch (RemoteException e) {
+ } catch (RemoteException re) {
/* ignore */
}
}
- private void handleToggleAccessibilityScriptInjectionPreference(Preference preference) {
- String allowed = getString(R.string.accessibility_script_injection_disallowed);
- if (preference.getSummary().equals(allowed)) {
- // set right enabled state since the user may press back.
- showDialog(DIALOG_ID_ENABLE_SCRIPT_INJECTION);
- } else {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_disallowed));
- }
+ 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 installToggleAccessibilitySwitch() {
- mToggleAccessibilitySwitch = createActionBarToggleSwitch(getActivity());
+ private void addToggleAccessibilitySwitch() {
+ mToggleAccessibilitySwitch = createAndAddActionBarToggleSwitch(getActivity());
final boolean checked = (Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
mToggleAccessibilitySwitch.setChecked(checked);
@@ -236,34 +240,126 @@
@Override
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
if (!checked) {
- toggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+ toggleSwitch.setCheckedInternal(true);
showDialog(DIALOG_ID_DISABLE_ACCESSIBILITY);
return true;
}
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 1);
- updatePreferencesForAccessibilityState();
+ updateAllPreferences(true);
+ offerInstallAccessibilitySerivceOnce();
return false;
}
});
}
- private void findPreferences() {
- mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
-
- mToggleLargeTextPreference = (CheckBoxPreference) findPreference(
- TOGGLE_LARGE_TEXT_PREFERENCE);
- mTogglePowerButtonEndsCallPreference = (CheckBoxPreference) findPreference(
- TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
- mTouchExplorationEnabledPreference = findPreference(TOGGLE_TOUCH_EXPLORATION_PREFERENCE);
- mSelectLongPressTimeoutPreference = (ListPreference) findPreference(
- SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
- mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
- mToggleScriptInjectionPreference = findPreference(TOGGLE_SCRIPT_INJECTION_PREFERENCE);
- mToggleScriptInjectionPreference.setOnPreferenceChangeListener(this);
+ public void removeToggleAccessibilitySwitch() {
+ getActivity().getActionBar().setCustomView(null);
}
- private void updateServicesPreferences() {
+ private void initializeAllPreferences() {
+ // The basic logic here is if accessibility is not enabled all accessibility
+ // settings will have no effect but still their selected state should be kept
+ // unchanged, so the user can see what settings will be enabled when turning
+ // on accessibility.
+
+ final boolean accessibilityEnabled = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
+
+ mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
+ mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+
+ // Large text.
+ mToggleLargeTextPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
+ if (accessibilityEnabled) {
+ try {
+ mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
+ }
+
+ // Power button ends calls.
+ mTogglePowerButtonEndsCallPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
+ if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ && Utils.isVoiceCapable(getActivity())) {
+ if (accessibilityEnabled) {
+ 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);
+ }
+ } else {
+ mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+ }
+
+ // Touch exploration enabled.
+ mToggleTouchExplorationPreference = findPreference(TOGGLE_TOUCH_EXPLORATION_PREFERENCE);
+ final boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1);
+ if (touchExplorationEnabled) {
+ mToggleTouchExplorationPreference.setSummary(
+ getString(R.string.accessibility_service_state_on));
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
+ } else {
+ mToggleTouchExplorationPreference.setSummary(
+ getString(R.string.accessibility_service_state_off));
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
+ }
+
+ // 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]);
+ }
+ }
+ if (accessibilityEnabled) {
+ 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));
+ } else {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.LONG_PRESS_TIMEOUT,
+ mLongPressTimeoutDefault);
+ }
+
+ // Script injection.
+ mToggleScriptInjectionPreference = (AccessibilityEnableScriptInjectionPreference)
+ findPreference(TOGGLE_SCRIPT_INJECTION_PREFERENCE);
+ if (accessibilityEnabled) {
+ final boolean scriptInjectionAllowed = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
+ mToggleScriptInjectionPreference.setInjectionAllowed(scriptInjectionAllowed);
+ }
+ }
+
+ private void updateAllPreferences(boolean accessibilityEnabled) {
+ updateServicesPreferences(accessibilityEnabled);
+ updateSystemPreferences(accessibilityEnabled);
+ }
+
+ private void updateServicesPreferences(boolean accessibilityEnabled) {
+ // 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());
@@ -271,17 +367,6 @@
List<AccessibilityServiceInfo> installedServices =
accessibilityManager.getInstalledAccessibilityServiceList();
- if (installedServices.isEmpty() && accessibilityManager.isEnabled()) {
- // no service and accessibility is enabled => disable
- Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0);
- mToggleAccessibilitySwitch.setChecked(false);
- mToggleAccessibilitySwitch.setEnabled(false);
- // 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);
- return;
- }
-
Set<ComponentName> enabledComponentNames = new HashSet<ComponentName>();
String settingValue = Settings.Secure.getString(getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -317,12 +402,19 @@
preference.setOrder(i);
preference.setFragment(ToggleAccessibilityServiceFragment.class.getName());
+ preference.setPersistent(true);
Bundle extras = preference.getExtras();
extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
extras.putBoolean(EXTRA_CHECKED, enabled);
extras.putString(EXTRA_TITLE, title);
- extras.putString(EXTRA_SUMMARY, info.getDescription());
+
+ String description = info.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ description = getString(R.string.accessibility_service_default_description);
+ }
+ extras.putString(EXTRA_SUMMARY, description);
+
extras.putString(EXTRA_WARNING_MESSAGE, getString(
R.string.accessibility_service_security_warning,
info.getResolveInfo().loadLabel(getPackageManager())));
@@ -338,69 +430,99 @@
mServicesCategory.addPreference(preference);
}
+
+ // Update enabled state.
+ mServicesCategory.setEnabled(accessibilityEnabled);
}
- public void updateSystemPreferences() {
+ private void updateSystemPreferences(boolean accessibilityEnabled) {
+ // The basic logic here is if accessibility is not enabled all accessibility
+ // settings will have no effect but still their selected state should be kept
+ // unchanged, so the user can see what settings will be enabled when turning
+ // on accessibility.
+
// Large text.
+ mToggleLargeTextPreference.setEnabled(accessibilityEnabled);
+ if (accessibilityEnabled) {
+ mCurConfig.fontScale =
+ mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
+ } else {
+ mCurConfig.fontScale = 1;
+ }
try {
- mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
} catch (RemoteException re) {
/* ignore */
}
- mToggleLargeTextPreference.setChecked(Float.compare(mCurConfig.fontScale,
- LARGE_FONT_SCALE) == 0);
- // Power button ends call.
- 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);
- } else {
- getPreferenceScreen().removePreference(mTogglePowerButtonEndsCallPreference);
+ // Power button ends calls.
+ if (mTogglePowerButtonEndsCallPreference != null) {
+ mTogglePowerButtonEndsCallPreference.setEnabled(accessibilityEnabled);
+ final int powerButtonEndsCall;
+ if (accessibilityEnabled) {
+ powerButtonEndsCall = mTogglePowerButtonEndsCallPreference.isChecked()
+ ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+ : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
+ } else {
+ powerButtonEndsCall = Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
+ }
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ powerButtonEndsCall);
}
// Touch exploration enabled.
+ mToggleTouchExplorationPreference.setEnabled(accessibilityEnabled);
final boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1);
if (touchExplorationEnabled) {
- mTouchExplorationEnabledPreference.setSummary(
+ mToggleTouchExplorationPreference.setSummary(
getString(R.string.accessibility_service_state_on));
- mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
} else {
- mTouchExplorationEnabledPreference.setSummary(
+ mToggleTouchExplorationPreference.setSummary(
getString(R.string.accessibility_service_state_off));
- mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
}
// Long press timeout.
- if (mLongPressTimeoutValuetoTitleMap.isEmpty()) {
- String[] timeoutValues = getResources().getStringArray(
- R.array.long_press_timeout_selector_values);
- 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]);
- }
+ mSelectLongPressTimeoutPreference.setEnabled(accessibilityEnabled);
+ final int longPressTimeout;
+ if (accessibilityEnabled) {
+ longPressTimeout = Integer.parseInt(mSelectLongPressTimeoutPreference.getValue());
+ } else {
+ longPressTimeout = mLongPressTimeoutDefault;
}
- String longPressTimeout = String.valueOf(Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, 0));
- mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(longPressTimeout));
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.LONG_PRESS_TIMEOUT,
+ longPressTimeout);
+ String value = mSelectLongPressTimeoutPreference.getValue();
+ mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
// Script injection.
- final boolean scriptInjectionAllowed = (Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
- if (scriptInjectionAllowed) {
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_allowed));
+ mToggleScriptInjectionPreference.setEnabled(accessibilityEnabled);
+ final boolean scriptInjectionAllowed;
+ if (accessibilityEnabled) {
+ scriptInjectionAllowed = mToggleScriptInjectionPreference.isInjectionAllowed();
} else {
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_disallowed));
+ scriptInjectionAllowed = false;
+ }
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+ scriptInjectionAllowed ? 1 : 0);
+ }
+
+ private void offerInstallAccessibilitySerivceOnce() {
+ if (mServicesCategory.getPreferenceCount() > 0) {
+ return;
+ }
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean offerInstallService = !preferences.getBoolean(
+ KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE, false);
+ if (offerInstallService) {
+ 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);
}
}
@@ -409,48 +531,29 @@
switch (dialogId) {
case DIALOG_ID_DISABLE_ACCESSIBILITY:
return (new AlertDialog.Builder(getActivity()))
- .setTitle(android.R.string.dialog_alert_title)
+ .setTitle(R.string.accessibility_disable_warning_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(getResources().
- getString(R.string.accessibility_service_disable_warning))
+ getString(R.string.accessibility_disable_warning_summary))
.setCancelable(true)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0);
- mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+ mToggleAccessibilitySwitch.setCheckedInternal(
false);
- updatePreferencesForAccessibilityState();
+ updateAllPreferences(false);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+ mToggleAccessibilitySwitch.setCheckedInternal(
true);
}
})
.create();
- case DIALOG_ID_ENABLE_SCRIPT_INJECTION:
- return new AlertDialog.Builder(getActivity())
- .setTitle(android.R.string.dialog_alert_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getActivity().getString(
- R.string.accessibility_script_injection_security_warning))
- .setCancelable(true)
- .setPositiveButton(R.string.accessibility_script_injection_button_allow,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1);
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_allowed));
- }
- })
-
- .setNegativeButton(R.string.accessibility_script_injection_button_disallow, null)
- .create();
case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.accessibility_service_no_apps_title)
@@ -461,9 +564,10 @@
// dismiss the dialog before launching the activity otherwise
// the dialog removal occurs after onSaveInstanceState which
// triggers an exception
- dialog.dismiss();
+ removeDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
String screenreaderMarketLink = SystemProperties.get(
- "ro.screenreader.market", DEFAULT_SCREENREADER_MARKET_LINK);
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
Uri marketUri = Uri.parse(screenreaderMarketLink);
Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
startActivity(marketIntent);
@@ -503,7 +607,7 @@
}
}
- private static ToggleSwitch createActionBarToggleSwitch(Activity activity) {
+ private static ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
final int padding = activity.getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
@@ -542,7 +646,7 @@
super.setChecked(checked);
}
- public void setCheckedNoBeforeCheckedChangeListener(boolean checked) {
+ public void setCheckedInternal(boolean checked) {
super.setChecked(checked);
}
}
@@ -590,6 +694,17 @@
public void onPreferenceToggled(String preferenceKey, boolean enabled) {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0);
+ if (enabled) {
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean launchAccessibilityTutorial = !preferences.getBoolean(
+ KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE, false);
+ if (launchAccessibilityTutorial) {
+ preferences.edit().putBoolean(KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE,
+ true).commit();
+ Intent intent = new Intent(AccessibilityTutorialActivity.ACTION);
+ getActivity().startActivity(intent);
+ }
+ }
}
}
@@ -608,14 +723,9 @@
private CharSequence mSettingsTitle;
private Intent mSettingsIntent;
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- installActionBarToggleSwitch();
- processArguments();
- getListView().setDivider(null);
- getListView().setEnabled(false);
- super.onActivityCreated(savedInstanceState);
- }
+ // 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) {
@@ -629,6 +739,22 @@
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);
@@ -636,13 +762,31 @@
preferenceScreen.addPreference(mSummaryPreference);
}
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ installActionBarToggleSwitch();
+ processArguments();
+ getListView().setDivider(null);
+ getListView().setEnabled(false);
+ }
+
+ @Override
+ public void onDestroyView() {
+ getActivity().getActionBar().setCustomView(null);
+ if (mOldActivityTitle != null) {
+ getActivity().getActionBar().setTitle(mOldActivityTitle);
+ }
+ super.onDestroyView();
+ }
+
public abstract void onPreferenceToggled(String preferenceKey, boolean value);
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem menuItem = menu.add(mSettingsTitle);
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menuItem.setIntent(mSettingsIntent);
}
@@ -668,7 +812,7 @@
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
// OK, we got the user consent so set checked.
- mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+ mToggleSwitch.setCheckedInternal(true);
onPreferenceToggled(mPreferenceKey, true);
break;
case DialogInterface.BUTTON_NEGATIVE:
@@ -680,13 +824,13 @@
}
private void installActionBarToggleSwitch() {
- mToggleSwitch = createActionBarToggleSwitch(getActivity());
+ mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
@Override
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
if (checked) {
if (!TextUtils.isEmpty(mWarningMessage)) {
- toggleSwitch.setCheckedNoBeforeCheckedChangeListener(false);
+ toggleSwitch.setCheckedInternal(false);
showDialog(DIALOG_ID_WARNING);
return true;
}
@@ -707,11 +851,15 @@
// Enabled.
final boolean enabled = arguments.getBoolean(EXTRA_CHECKED);
- mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(enabled);
+ mToggleSwitch.setCheckedInternal(enabled);
// Title.
- String title = arguments.getString(EXTRA_TITLE);
- getActivity().getActionBar().setTitle(arguments.getCharSequence(EXTRA_TITLE));
+ PreferenceActivity activity = (PreferenceActivity) getActivity();
+ if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
+ mOldActivityTitle = getActivity().getTitle();
+ String title = arguments.getString(EXTRA_TITLE);
+ getActivity().getActionBar().setTitle(arguments.getCharSequence(EXTRA_TITLE));
+ }
// Summary.
String summary = arguments.getString(EXTRA_SUMMARY);
diff --git a/src/com/android/settings/AccessibilityTutorialActivity.java b/src/com/android/settings/AccessibilityTutorialActivity.java
index 9ea9917..da8350c 100644
--- a/src/com/android/settings/AccessibilityTutorialActivity.java
+++ b/src/com/android/settings/AccessibilityTutorialActivity.java
@@ -47,6 +47,8 @@
import android.widget.TextView;
import android.widget.ViewAnimator;
+import com.android.settings.R;
+
import java.util.List;
/**
@@ -54,6 +56,10 @@
* available in Touch Exploration.
*/
public class AccessibilityTutorialActivity extends Activity {
+
+ /** Intent action for launching this activity. */
+ public static final String ACTION = "android.settings.ACCESSIBILITY_TUTORIAL";
+
/** Instance state saving constant for the active module. */
private static final String KEY_ACTIVE_MODULE = "active_module";