Revert "Revert "Remove obsolete workaround for ClickableSpan a11y""
This reverts commit ee3beb6434
.
Instead of using BuildCompat.isAtLeastO, use Build.VERSION.SDK_INT
check the disable LinkAccessibilityHelper on versions above N MR1.
This is required because BuildCompat.isAtLeastO requires support lib
version 26, and therefore targetSdk 26. But since GMS core has a
dependency on this library, and modules not in the O sidecar cannot
target API 26 yet, setup wizard lib cannot use that method.
Test: ./gradlew connectedAndroidTest test
Bug: 37792269
Change-Id: I2be64e41cc86b4695a1ffd1ee376a774a3570750
This commit is contained in:
parent
ee3beb6434
commit
ba44e63191
|
@ -17,13 +17,19 @@
|
||||||
package com.android.setupwizardlib.util;
|
package com.android.setupwizardlib.util;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.view.AccessibilityDelegateCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
|
||||||
import android.support.v4.widget.ExploreByTouchHelper;
|
import android.support.v4.widget.ExploreByTouchHelper;
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -32,6 +38,10 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* An accessibility delegate that allows {@link android.text.style.ClickableSpan} to be focused and
|
* An accessibility delegate that allows {@link android.text.style.ClickableSpan} to be focused and
|
||||||
* clicked by accessibility services.
|
* clicked by accessibility services.
|
||||||
|
* <p>
|
||||||
|
* <strong>Note: </strong> From Android O on, there is native support for ClickableSpan
|
||||||
|
* accessibility, so this class is not needed (and indeed has no effect.)
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* <p />Sample usage:
|
* <p />Sample usage:
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -54,19 +64,135 @@ import java.util.List;
|
||||||
* @see com.android.setupwizardlib.view.RichTextView
|
* @see com.android.setupwizardlib.view.RichTextView
|
||||||
* @see android.support.v4.widget.ExploreByTouchHelper
|
* @see android.support.v4.widget.ExploreByTouchHelper
|
||||||
*/
|
*/
|
||||||
public class LinkAccessibilityHelper extends ExploreByTouchHelper {
|
public class LinkAccessibilityHelper extends AccessibilityDelegateCompat {
|
||||||
|
|
||||||
private static final String TAG = "LinkAccessibilityHelper";
|
private static final String TAG = "LinkAccessibilityHelper";
|
||||||
|
|
||||||
private final TextView mView;
|
private final TextView mView;
|
||||||
private final Rect mTempRect = new Rect();
|
private final Rect mTempRect = new Rect();
|
||||||
|
private final ExploreByTouchHelper mExploreByTouchHelper;
|
||||||
|
|
||||||
public LinkAccessibilityHelper(TextView view) {
|
public LinkAccessibilityHelper(TextView view) {
|
||||||
super(view);
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
|
||||||
|
// Pre-O, we essentially extend ExploreByTouchHelper to expose a virtual view hierarchy
|
||||||
|
mExploreByTouchHelper = new ExploreByTouchHelper(view) {
|
||||||
|
@Override
|
||||||
|
protected int getVirtualViewAt(float x, float y) {
|
||||||
|
return this.getVirtualViewAt(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
|
||||||
|
this.getVisibleVirtualViews(virtualViewIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPopulateEventForVirtualView(int virtualViewId,
|
||||||
|
AccessibilityEvent event) {
|
||||||
|
this.onPopulateEventForVirtualView(virtualViewId, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPopulateNodeForVirtualView(int virtualViewId,
|
||||||
|
AccessibilityNodeInfoCompat infoCompat) {
|
||||||
|
this.onPopulateNodeForVirtualView(virtualViewId, infoCompat);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
|
||||||
|
Bundle arguments) {
|
||||||
|
return this.onPerformActionForVirtualView(virtualViewId, action, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
mExploreByTouchHelper = null;
|
||||||
|
}
|
||||||
mView = view;
|
mView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void sendAccessibilityEvent(View host, int eventType) {
|
||||||
|
if (mExploreByTouchHelper != null) {
|
||||||
|
mExploreByTouchHelper.sendAccessibilityEvent(host, eventType);
|
||||||
|
} else {
|
||||||
|
super.sendAccessibilityEvent(host, eventType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
|
||||||
|
if (mExploreByTouchHelper != null) {
|
||||||
|
mExploreByTouchHelper.sendAccessibilityEventUnchecked(host, event);
|
||||||
|
} else {
|
||||||
|
super.sendAccessibilityEventUnchecked(host, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
return (mExploreByTouchHelper != null)
|
||||||
|
? mExploreByTouchHelper.dispatchPopulateAccessibilityEvent(host, event)
|
||||||
|
: super.dispatchPopulateAccessibilityEvent(host, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
if (mExploreByTouchHelper != null) {
|
||||||
|
mExploreByTouchHelper.onPopulateAccessibilityEvent(host, event);
|
||||||
|
} else {
|
||||||
|
super.onPopulateAccessibilityEvent(host, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
if (mExploreByTouchHelper != null) {
|
||||||
|
mExploreByTouchHelper.onInitializeAccessibilityEvent(host, event);
|
||||||
|
} else {
|
||||||
|
super.onInitializeAccessibilityEvent(host, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
|
||||||
|
if (mExploreByTouchHelper != null) {
|
||||||
|
mExploreByTouchHelper.onInitializeAccessibilityNodeInfo(host, info);
|
||||||
|
} else {
|
||||||
|
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
|
||||||
|
AccessibilityEvent event) {
|
||||||
|
return (mExploreByTouchHelper != null)
|
||||||
|
? mExploreByTouchHelper.onRequestSendAccessibilityEvent(host, child, event)
|
||||||
|
: super.onRequestSendAccessibilityEvent(host, child, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
|
||||||
|
return (mExploreByTouchHelper != null)
|
||||||
|
? mExploreByTouchHelper.getAccessibilityNodeProvider(host)
|
||||||
|
: super.getAccessibilityNodeProvider(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||||
|
return (mExploreByTouchHelper != null)
|
||||||
|
? mExploreByTouchHelper.performAccessibilityAction(host, action, args)
|
||||||
|
: super.performAccessibilityAction(host, action, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegated to {@link ExploreByTouchHelper}
|
||||||
|
*/
|
||||||
|
public final boolean dispatchHoverEvent(MotionEvent event) {
|
||||||
|
return (mExploreByTouchHelper != null) ? mExploreByTouchHelper.dispatchHoverEvent(event)
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
protected int getVirtualViewAt(float x, float y) {
|
protected int getVirtualViewAt(float x, float y) {
|
||||||
final CharSequence text = mView.getText();
|
final CharSequence text = mView.getText();
|
||||||
if (text instanceof Spanned) {
|
if (text instanceof Spanned) {
|
||||||
|
@ -78,10 +204,9 @@ public class LinkAccessibilityHelper extends ExploreByTouchHelper {
|
||||||
return spannedText.getSpanStart(linkSpan);
|
return spannedText.getSpanStart(linkSpan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return INVALID_ID;
|
return ExploreByTouchHelper.INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
|
protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
|
||||||
final CharSequence text = mView.getText();
|
final CharSequence text = mView.getText();
|
||||||
if (text instanceof Spanned) {
|
if (text instanceof Spanned) {
|
||||||
|
@ -94,7 +219,6 @@ public class LinkAccessibilityHelper extends ExploreByTouchHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
|
protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
|
||||||
final ClickableSpan span = getSpanForOffset(virtualViewId);
|
final ClickableSpan span = getSpanForOffset(virtualViewId);
|
||||||
if (span != null) {
|
if (span != null) {
|
||||||
|
@ -105,7 +229,6 @@ public class LinkAccessibilityHelper extends ExploreByTouchHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPopulateNodeForVirtualView(int virtualViewId,
|
protected void onPopulateNodeForVirtualView(int virtualViewId,
|
||||||
AccessibilityNodeInfoCompat info) {
|
AccessibilityNodeInfoCompat info) {
|
||||||
final ClickableSpan span = getSpanForOffset(virtualViewId);
|
final ClickableSpan span = getSpanForOffset(virtualViewId);
|
||||||
|
@ -126,7 +249,6 @@ public class LinkAccessibilityHelper extends ExploreByTouchHelper {
|
||||||
info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
|
info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
|
protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
|
||||||
Bundle arguments) {
|
Bundle arguments) {
|
||||||
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
|
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
|
@ -57,6 +58,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetVirtualViewAt() {
|
public void testGetVirtualViewAt() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10));
|
final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10));
|
||||||
assertEquals("Virtual view ID should be 1", 1, virtualViewId);
|
assertEquals("Virtual view ID should be 1", 1, virtualViewId);
|
||||||
|
@ -64,6 +66,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetVirtualViewAtHost() {
|
public void testGetVirtualViewAtHost() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100));
|
final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100));
|
||||||
assertEquals("Virtual view ID should be INVALID_ID",
|
assertEquals("Virtual view ID should be INVALID_ID",
|
||||||
|
@ -72,6 +75,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetVisibleVirtualViews() {
|
public void testGetVisibleVirtualViews() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
List<Integer> virtualViewIds = new ArrayList<>();
|
List<Integer> virtualViewIds = new ArrayList<>();
|
||||||
mHelper.getVisibleVirtualViews(virtualViewIds);
|
mHelper.getVisibleVirtualViews(virtualViewIds);
|
||||||
|
@ -82,6 +86,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnPopulateEventForVirtualView() {
|
public void testOnPopulateEventForVirtualView() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
AccessibilityEvent event = AccessibilityEvent.obtain();
|
AccessibilityEvent event = AccessibilityEvent.obtain();
|
||||||
mHelper.onPopulateEventForVirtualView(1, event);
|
mHelper.onPopulateEventForVirtualView(1, event);
|
||||||
|
@ -95,6 +100,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnPopulateEventForVirtualViewHost() {
|
public void testOnPopulateEventForVirtualViewHost() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
AccessibilityEvent event = AccessibilityEvent.obtain();
|
AccessibilityEvent event = AccessibilityEvent.obtain();
|
||||||
mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event);
|
mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event);
|
||||||
|
@ -107,6 +113,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnPopulateNodeForVirtualView() {
|
public void testOnPopulateNodeForVirtualView() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
|
AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
|
||||||
mHelper.onPopulateNodeForVirtualView(1, info);
|
mHelper.onPopulateNodeForVirtualView(1, info);
|
||||||
|
@ -125,6 +132,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullLayout() {
|
public void testNullLayout() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
initTextView();
|
initTextView();
|
||||||
// Setting the padding will cause the layout to be null-ed out.
|
// Setting the padding will cause the layout to be null-ed out.
|
||||||
mTextView.setPadding(1, 1, 1, 1);
|
mTextView.setPadding(1, 1, 1, 1);
|
||||||
|
@ -142,6 +150,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRtlLayout() {
|
public void testRtlLayout() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום");
|
SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום");
|
||||||
ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
|
ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
|
||||||
initTextView(ssb);
|
initTextView(ssb);
|
||||||
|
@ -161,6 +170,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultilineLink() {
|
public void testMultilineLink() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
SpannableStringBuilder ssb = new SpannableStringBuilder(
|
SpannableStringBuilder ssb = new SpannableStringBuilder(
|
||||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
|
||||||
+ "Praesent accumsan efficitur eros eu porttitor.");
|
+ "Praesent accumsan efficitur eros eu porttitor.");
|
||||||
|
@ -182,6 +192,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRtlMultilineLink() {
|
public void testRtlMultilineLink() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
|
String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
|
||||||
+ "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
|
+ "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
|
||||||
+ "דפים המחשב מיזמים ב.";
|
+ "דפים המחשב מיזמים ב.";
|
||||||
|
@ -205,6 +216,7 @@ public class LinkAccessibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBidiMultilineLink() {
|
public void testBidiMultilineLink() {
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return;
|
||||||
String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
|
String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
|
||||||
+ "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
|
+ "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
|
||||||
+ "דפים המחשב מיזמים ב.";
|
+ "דפים המחשב מיזמים ב.";
|
||||||
|
|
Loading…
Reference in a new issue