Accessibility: properly announce checkbox/switch preference changes
If a switch/checkbox preference is clicked it immediately fires an
accessibility event which captures the current state of the view to
which the prefernce is bound. If such a preference is a part of a pref
screen clicking it changes the preference and invalidates the adapter
which requests an async layout during which the correspinding view
will be updated. As a result the click accessibility event and node
infos in the view subtree capture the old state of the preference's
view resulting in an opposite feedback - bad. Now if accessibility is
enabled we immediately sync the view with the preference to ensure
the accessibility state reflects the latests view state.
bug:22596300
Change-Id: Idd6fb1c4143c15b62ce8c53fb118983f583305c0
diff --git a/v14/preference/src/android/support/v14/preference/SwitchPreference.java b/v14/preference/src/android/support/v14/preference/SwitchPreference.java
index 048bc6c..1a46cc4 100644
--- a/v14/preference/src/android/support/v14/preference/SwitchPreference.java
+++ b/v14/preference/src/android/support/v14/preference/SwitchPreference.java
@@ -23,6 +23,7 @@
import android.support.v7.preference.TwoStatePreference;
import android.util.AttributeSet;
import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Checkable;
import android.widget.CompoundButton;
import android.widget.Switch;
@@ -135,24 +136,8 @@
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
-
- View checkableView = holder.findViewById(R.id.switchWidget);
- if (checkableView != null && checkableView instanceof Checkable) {
- if (checkableView instanceof Switch) {
- final Switch switchView = (Switch) checkableView;
- switchView.setOnCheckedChangeListener(null);
- }
-
- ((Checkable) checkableView).setChecked(mChecked);
-
- if (checkableView instanceof Switch) {
- final Switch switchView = (Switch) checkableView;
- switchView.setTextOn(mSwitchOn);
- switchView.setTextOff(mSwitchOff);
- switchView.setOnCheckedChangeListener(mListener);
- }
- }
-
+ View switchView = holder.findViewById(R.id.switchWidget);
+ syncSwitchView(switchView);
syncSummaryView(holder);
}
@@ -211,4 +196,44 @@
public CharSequence getSwitchTextOff() {
return mSwitchOff;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ protected void performClick(View view) {
+ super.performClick(view);
+ syncViewIfAccessibilityEnabled(view);
+ }
+
+
+ private void syncViewIfAccessibilityEnabled(View view) {
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ if (!accessibilityManager.isEnabled()) {
+ return;
+ }
+
+ View switchView = view.findViewById(R.id.switchWidget);
+ syncSwitchView(switchView);
+
+ View summaryView = view.findViewById(android.R.id.summary);
+ syncSummaryView(summaryView);
+ }
+
+ private void syncSwitchView(View view) {
+ if (view instanceof Switch) {
+ final Switch switchView = (Switch) view;
+ switchView.setOnCheckedChangeListener(null);
+ }
+ if (view instanceof Checkable) {
+ ((Checkable) view).setChecked(mChecked);
+ }
+ if (view instanceof Switch) {
+ final Switch switchView = (Switch) view;
+ switchView.setTextOn(mSwitchOn);
+ switchView.setTextOff(mSwitchOff);
+ switchView.setOnCheckedChangeListener(mListener);
+ }
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java b/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java
index f49b0d6..61eb13c 100644
--- a/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java
+++ b/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java
@@ -21,6 +21,7 @@
import android.support.v4.content.res.TypedArrayUtils;
import android.util.AttributeSet;
import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Checkable;
/**
@@ -78,4 +79,33 @@
syncSummaryView(holder);
}
+
+ /**
+ * @hide
+ */
+ @Override
+ protected void performClick(View view) {
+ super.performClick(view);
+ syncViewIfAccessibilityEnabled(view);
+ }
+
+ private void syncViewIfAccessibilityEnabled(View view) {
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ if (!accessibilityManager.isEnabled()) {
+ return;
+ }
+
+ View checkboxView = view.findViewById(R.id.checkbox);
+ syncCheckboxView(checkboxView);
+
+ View summaryView = view.findViewById(android.R.id.summary);
+ syncSummaryView(summaryView);
+ }
+
+ private void syncCheckboxView(View view) {
+ if (view instanceof Checkable) {
+ ((Checkable) view).setChecked(mChecked);
+ }
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index 15033ff..ede1d71 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -133,7 +133,7 @@
private final View.OnClickListener mClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- performClick();
+ performClick(v);
}
};
@@ -918,6 +918,13 @@
}
/**
+ * @hide
+ */
+ protected void performClick(View view) {
+ performClick();
+ }
+
+ /**
* Called when a click should be performed.
*
* @hide
diff --git a/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java b/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java
index 2e0e38b..295d835 100644
--- a/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java
+++ b/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java
@@ -22,6 +22,7 @@
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;
import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Checkable;
import android.widget.CompoundButton;
@@ -133,24 +134,8 @@
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
-
- View checkableView = holder.findViewById(R.id.switchWidget);
- if (checkableView != null && checkableView instanceof Checkable) {
- if (checkableView instanceof SwitchCompat) {
- final SwitchCompat switchView = (SwitchCompat) checkableView;
- switchView.setOnCheckedChangeListener(null);
- }
-
- ((Checkable) checkableView).setChecked(mChecked);
-
- if (checkableView instanceof SwitchCompat) {
- final SwitchCompat switchView = (SwitchCompat) checkableView;
- switchView.setTextOn(mSwitchOn);
- switchView.setTextOff(mSwitchOff);
- switchView.setOnCheckedChangeListener(mListener);
- }
- }
-
+ View switchView = holder.findViewById(R.id.switchWidget);
+ syncSwitchView(switchView);
syncSummaryView(holder);
}
@@ -209,4 +194,43 @@
public CharSequence getSwitchTextOff() {
return mSwitchOff;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ protected void performClick(View view) {
+ super.performClick(view);
+ syncViewIfAccessibilityEnabled(view);
+ }
+
+ private void syncViewIfAccessibilityEnabled(View view) {
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ if (!accessibilityManager.isEnabled()) {
+ return;
+ }
+
+ View switchView = view.findViewById(R.id.switchWidget);
+ syncSwitchView(switchView);
+
+ View summaryView = view.findViewById(android.R.id.summary);
+ syncSummaryView(summaryView);
+ }
+
+ private void syncSwitchView(View view) {
+ if (view instanceof SwitchCompat) {
+ final SwitchCompat switchView = (SwitchCompat) view;
+ switchView.setOnCheckedChangeListener(null);
+ }
+ if (view instanceof Checkable) {
+ ((Checkable) view).setChecked(mChecked);
+ }
+ if (view instanceof SwitchCompat) {
+ final SwitchCompat switchView = (SwitchCompat) view;
+ switchView.setTextOn(mSwitchOn);
+ switchView.setTextOff(mSwitchOff);
+ switchView.setOnCheckedChangeListener(mListener);
+ }
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/TwoStatePreference.java b/v7/preference/src/android/support/v7/preference/TwoStatePreference.java
index e7748cc..939a50c 100644
--- a/v7/preference/src/android/support/v7/preference/TwoStatePreference.java
+++ b/v7/preference/src/android/support/v7/preference/TwoStatePreference.java
@@ -193,33 +193,40 @@
*/
protected void syncSummaryView(PreferenceViewHolder holder) {
// Sync the summary holder
- TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
- if (summaryView != null) {
- boolean useDefaultSummary = true;
- if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
- summaryView.setText(mSummaryOn);
- useDefaultSummary = false;
- } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
- summaryView.setText(mSummaryOff);
+ View view = holder.findViewById(android.R.id.summary);
+ syncSummaryView(view);
+ }
+
+ /**
+ * @hide
+ */
+ protected void syncSummaryView(View view) {
+ if (!(view instanceof TextView)) {
+ return;
+ }
+ TextView summaryView = (TextView) view;
+ boolean useDefaultSummary = true;
+ if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
+ summaryView.setText(mSummaryOn);
+ useDefaultSummary = false;
+ } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
+ summaryView.setText(mSummaryOff);
+ useDefaultSummary = false;
+ }
+ if (useDefaultSummary) {
+ final CharSequence summary = getSummary();
+ if (!TextUtils.isEmpty(summary)) {
+ summaryView.setText(summary);
useDefaultSummary = false;
}
-
- if (useDefaultSummary) {
- final CharSequence summary = getSummary();
- if (!TextUtils.isEmpty(summary)) {
- summaryView.setText(summary);
- useDefaultSummary = false;
- }
- }
-
- int newVisibility = View.GONE;
- if (!useDefaultSummary) {
- // Someone has written to it
- newVisibility = View.VISIBLE;
- }
- if (newVisibility != summaryView.getVisibility()) {
- summaryView.setVisibility(newVisibility);
- }
+ }
+ int newVisibility = View.GONE;
+ if (!useDefaultSummary) {
+ // Someone has written to it
+ newVisibility = View.VISIBLE;
+ }
+ if (newVisibility != summaryView.getVisibility()) {
+ summaryView.setVisibility(newVisibility);
}
}