diff --git a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java index 1e663d6..1fb3a37 100644 --- a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java +++ b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java @@ -19,6 +19,8 @@ package com.android.setupwizardlib.util; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; import android.support.v4.view.AccessibilityDelegateCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; @@ -38,12 +40,11 @@ import java.util.List; /** * An accessibility delegate that allows {@link android.text.style.ClickableSpan} to be focused and * clicked by accessibility services. - *
- * Note: From Android O on, there is native support for ClickableSpan - * accessibility, so this class is not needed (and indeed has no effect.) - *
* - * Sample usage: + *Note: This class is a no-op on Android O or above since there is native + * support for ClickableSpan accessibility. + * + *
Sample usage: *
* LinkAccessibilityHelper mAccessibilityHelper; * @@ -68,294 +69,255 @@ public class LinkAccessibilityHelper extends AccessibilityDelegateCompat { private static final String TAG = "LinkAccessibilityHelper"; - private final TextView mView; - private final Rect mTempRect = new Rect(); - private final ExploreByTouchHelper mExploreByTouchHelper; + private final AccessibilityDelegateCompat mDelegate; public LinkAccessibilityHelper(TextView 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 LinkAccessibilityHelper.this.getVirtualViewAt(x, y); - } + this(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O + // Platform support was added in O. This helper will be no-op + ? new AccessibilityDelegateCompat() + // Pre-O, we extend ExploreByTouchHelper to expose a virtual view hierarchy + : new PreOLinkAccessibilityHelper(view)); + } - @Override - protected void getVisibleVirtualViews(ListvirtualViewIds) { - LinkAccessibilityHelper.this.getVisibleVirtualViews(virtualViewIds); - } - - @Override - protected void onPopulateEventForVirtualView(int virtualViewId, - AccessibilityEvent event) { - LinkAccessibilityHelper - .this.onPopulateEventForVirtualView(virtualViewId, event); - } - - @Override - protected void onPopulateNodeForVirtualView(int virtualViewId, - AccessibilityNodeInfoCompat infoCompat) { - LinkAccessibilityHelper - .this.onPopulateNodeForVirtualView(virtualViewId, infoCompat); - - } - - @Override - protected boolean onPerformActionForVirtualView(int virtualViewId, int action, - Bundle arguments) { - return LinkAccessibilityHelper.this - .onPerformActionForVirtualView(virtualViewId, action, arguments); - } - }; - } else { - mExploreByTouchHelper = null; - } - mView = view; + @VisibleForTesting + LinkAccessibilityHelper(@NonNull AccessibilityDelegateCompat delegate) { + mDelegate = delegate; } @Override public void sendAccessibilityEvent(View host, int eventType) { - if (mExploreByTouchHelper != null) { - mExploreByTouchHelper.sendAccessibilityEvent(host, eventType); - } else { - super.sendAccessibilityEvent(host, eventType); - } + mDelegate.sendAccessibilityEvent(host, eventType); } @Override public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { - if (mExploreByTouchHelper != null) { - mExploreByTouchHelper.sendAccessibilityEventUnchecked(host, event); - } else { - super.sendAccessibilityEventUnchecked(host, event); - } + mDelegate.sendAccessibilityEventUnchecked(host, event); } @Override public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { - return (mExploreByTouchHelper != null) - ? mExploreByTouchHelper.dispatchPopulateAccessibilityEvent(host, event) - : super.dispatchPopulateAccessibilityEvent(host, event); + return mDelegate.dispatchPopulateAccessibilityEvent(host, event); } @Override public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { - if (mExploreByTouchHelper != null) { - mExploreByTouchHelper.onPopulateAccessibilityEvent(host, event); - } else { - super.onPopulateAccessibilityEvent(host, event); - } + mDelegate.onPopulateAccessibilityEvent(host, event); } @Override public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { - if (mExploreByTouchHelper != null) { - mExploreByTouchHelper.onInitializeAccessibilityEvent(host, event); - } else { - super.onInitializeAccessibilityEvent(host, event); - } + mDelegate.onInitializeAccessibilityEvent(host, event); } @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { - if (mExploreByTouchHelper != null) { - mExploreByTouchHelper.onInitializeAccessibilityNodeInfo(host, info); - } else { - super.onInitializeAccessibilityNodeInfo(host, info); - } + mDelegate.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); + return mDelegate.onRequestSendAccessibilityEvent(host, child, event); } @Override public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) { - return (mExploreByTouchHelper != null) - ? mExploreByTouchHelper.getAccessibilityNodeProvider(host) - : super.getAccessibilityNodeProvider(host); + return mDelegate.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); + return mDelegate.performAccessibilityAction(host, action, args); } /** - * Delegated to {@link ExploreByTouchHelper} + * Dispatches hover event to the virtual view hierarchy. This method should be called in + * {@link View#dispatchHoverEvent(MotionEvent)}. + * + * @see ExploreByTouchHelper#dispatchHoverEvent(MotionEvent) */ public final boolean dispatchHoverEvent(MotionEvent event) { - return (mExploreByTouchHelper != null) ? mExploreByTouchHelper.dispatchHoverEvent(event) - : false; + return mDelegate instanceof ExploreByTouchHelper + && ((ExploreByTouchHelper) mDelegate).dispatchHoverEvent(event); } - protected int getVirtualViewAt(float x, float y) { - final CharSequence text = mView.getText(); - if (text instanceof Spanned) { - final Spanned spannedText = (Spanned) text; - final int offset = getOffsetForPosition(mView, x, y); - ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class); - if (linkSpans.length == 1) { - ClickableSpan linkSpan = linkSpans[0]; - return spannedText.getSpanStart(linkSpan); + @VisibleForTesting + static class PreOLinkAccessibilityHelper extends ExploreByTouchHelper { + + private final Rect mTempRect = new Rect(); + private final TextView mView; + + PreOLinkAccessibilityHelper(TextView view) { + super(view); + mView = view; + } + + protected int getVirtualViewAt(float x, float y) { + final CharSequence text = mView.getText(); + if (text instanceof Spanned) { + final Spanned spannedText = (Spanned) text; + final int offset = getOffsetForPosition(mView, x, y); + ClickableSpan[] linkSpans = + spannedText.getSpans(offset, offset, ClickableSpan.class); + if (linkSpans.length == 1) { + ClickableSpan linkSpan = linkSpans[0]; + return spannedText.getSpanStart(linkSpan); + } + } + return ExploreByTouchHelper.INVALID_ID; + } + + protected void getVisibleVirtualViews(List virtualViewIds) { + final CharSequence text = mView.getText(); + if (text instanceof Spanned) { + final Spanned spannedText = (Spanned) text; + ClickableSpan[] linkSpans = spannedText.getSpans(0, spannedText.length(), + ClickableSpan.class); + for (ClickableSpan span : linkSpans) { + virtualViewIds.add(spannedText.getSpanStart(span)); + } } } - return ExploreByTouchHelper.INVALID_ID; - } - protected void getVisibleVirtualViews(List virtualViewIds) { - final CharSequence text = mView.getText(); - if (text instanceof Spanned) { - final Spanned spannedText = (Spanned) text; - ClickableSpan[] linkSpans = spannedText.getSpans(0, spannedText.length(), - ClickableSpan.class); - for (ClickableSpan span : linkSpans) { - virtualViewIds.add(spannedText.getSpanStart(span)); - } - } - } - - protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { - final ClickableSpan span = getSpanForOffset(virtualViewId); - if (span != null) { - event.setContentDescription(getTextForSpan(span)); - } else { - Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId); - event.setContentDescription(mView.getText()); - } - } - - protected void onPopulateNodeForVirtualView(int virtualViewId, - AccessibilityNodeInfoCompat info) { - final ClickableSpan span = getSpanForOffset(virtualViewId); - if (span != null) { - info.setContentDescription(getTextForSpan(span)); - } else { - Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId); - info.setContentDescription(mView.getText()); - } - info.setFocusable(true); - info.setClickable(true); - getBoundsForSpan(span, mTempRect); - if (mTempRect.isEmpty()) { - Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId); - mTempRect.set(0, 0, 1, 1); - } - info.setBoundsInParent(mTempRect); - info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); - } - - protected boolean onPerformActionForVirtualView(int virtualViewId, int action, - Bundle arguments) { - if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) { - ClickableSpan span = getSpanForOffset(virtualViewId); + protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { + final ClickableSpan span = getSpanForOffset(virtualViewId); if (span != null) { - span.onClick(mView); - return true; + event.setContentDescription(getTextForSpan(span)); } else { Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId); + event.setContentDescription(mView.getText()); } } - return false; - } - private ClickableSpan getSpanForOffset(int offset) { - CharSequence text = mView.getText(); - if (text instanceof Spanned) { - Spanned spannedText = (Spanned) text; - ClickableSpan[] spans = spannedText.getSpans(offset, offset, ClickableSpan.class); - if (spans.length == 1) { - return spans[0]; + protected void onPopulateNodeForVirtualView( + int virtualViewId, + AccessibilityNodeInfoCompat info) { + final ClickableSpan span = getSpanForOffset(virtualViewId); + if (span != null) { + info.setContentDescription(getTextForSpan(span)); + } else { + Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId); + info.setContentDescription(mView.getText()); } + info.setFocusable(true); + info.setClickable(true); + getBoundsForSpan(span, mTempRect); + if (mTempRect.isEmpty()) { + Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId); + mTempRect.set(0, 0, 1, 1); + } + info.setBoundsInParent(mTempRect); + info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); } - return null; - } - private CharSequence getTextForSpan(ClickableSpan span) { - CharSequence text = mView.getText(); - if (text instanceof Spanned) { - Spanned spannedText = (Spanned) text; - return spannedText.subSequence(spannedText.getSpanStart(span), - spannedText.getSpanEnd(span)); - } - return text; - } - - // Find the bounds of a span. If it spans multiple lines, it will only return the bounds for the - // section on the first line. - private Rect getBoundsForSpan(ClickableSpan span, Rect outRect) { - CharSequence text = mView.getText(); - outRect.setEmpty(); - if (text instanceof Spanned) { - final Layout layout = mView.getLayout(); - if (layout != null) { - Spanned spannedText = (Spanned) text; - final int spanStart = spannedText.getSpanStart(span); - final int spanEnd = spannedText.getSpanEnd(span); - final float xStart = layout.getPrimaryHorizontal(spanStart); - final float xEnd = layout.getPrimaryHorizontal(spanEnd); - final int lineStart = layout.getLineForOffset(spanStart); - final int lineEnd = layout.getLineForOffset(spanEnd); - layout.getLineBounds(lineStart, outRect); - if (lineEnd == lineStart) { - // If the span is on a single line, adjust both the left and right bounds - // so outrect is exactly bounding the span. - outRect.left = (int) Math.min(xStart, xEnd); - outRect.right = (int) Math.max(xStart, xEnd); + protected boolean onPerformActionForVirtualView( + int virtualViewId, + int action, + Bundle arguments) { + if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) { + ClickableSpan span = getSpanForOffset(virtualViewId); + if (span != null) { + span.onClick(mView); + return true; } else { - // If the span wraps across multiple lines, only use the first line (as returned - // by layout.getLineBounds above), and adjust the "start" of outrect to where - // the span starts, leaving the "end" of outrect at the end of the line. - // ("start" being left for LTR, and right for RTL) - if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) { - outRect.right = (int) xStart; - } else { - outRect.left = (int) xStart; - } + Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId); } - - // Offset for padding - outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop()); } + return false; } - return outRect; - } - // Compat implementation of TextView#getOffsetForPosition(). + private ClickableSpan getSpanForOffset(int offset) { + CharSequence text = mView.getText(); + if (text instanceof Spanned) { + Spanned spannedText = (Spanned) text; + ClickableSpan[] spans = spannedText.getSpans(offset, offset, ClickableSpan.class); + if (spans.length == 1) { + return spans[0]; + } + } + return null; + } - private static int getOffsetForPosition(TextView view, float x, float y) { - if (view.getLayout() == null) return -1; - final int line = getLineAtCoordinate(view, y); - return getOffsetAtCoordinate(view, line, x); - } + private CharSequence getTextForSpan(ClickableSpan span) { + CharSequence text = mView.getText(); + if (text instanceof Spanned) { + Spanned spannedText = (Spanned) text; + return spannedText.subSequence( + spannedText.getSpanStart(span), + spannedText.getSpanEnd(span)); + } + return text; + } - private static float convertToLocalHorizontalCoordinate(TextView view, float x) { - x -= view.getTotalPaddingLeft(); - // Clamp the position to inside of the view. - x = Math.max(0.0f, x); - x = Math.min(view.getWidth() - view.getTotalPaddingRight() - 1, x); - x += view.getScrollX(); - return x; - } + // Find the bounds of a span. If it spans multiple lines, it will only return the bounds for + // the section on the first line. + private Rect getBoundsForSpan(ClickableSpan span, Rect outRect) { + CharSequence text = mView.getText(); + outRect.setEmpty(); + if (text instanceof Spanned) { + final Layout layout = mView.getLayout(); + if (layout != null) { + Spanned spannedText = (Spanned) text; + final int spanStart = spannedText.getSpanStart(span); + final int spanEnd = spannedText.getSpanEnd(span); + final float xStart = layout.getPrimaryHorizontal(spanStart); + final float xEnd = layout.getPrimaryHorizontal(spanEnd); + final int lineStart = layout.getLineForOffset(spanStart); + final int lineEnd = layout.getLineForOffset(spanEnd); + layout.getLineBounds(lineStart, outRect); + if (lineEnd == lineStart) { + // If the span is on a single line, adjust both the left and right bounds + // so outrect is exactly bounding the span. + outRect.left = (int) Math.min(xStart, xEnd); + outRect.right = (int) Math.max(xStart, xEnd); + } else { + // If the span wraps across multiple lines, only use the first line (as + // returned by layout.getLineBounds above), and adjust the "start" of + // outrect to where the span starts, leaving the "end" of outrect at the end + // of the line. ("start" being left for LTR, and right for RTL) + if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) { + outRect.right = (int) xStart; + } else { + outRect.left = (int) xStart; + } + } - private static int getLineAtCoordinate(TextView view, float y) { - y -= view.getTotalPaddingTop(); - // Clamp the position to inside of the view. - y = Math.max(0.0f, y); - y = Math.min(view.getHeight() - view.getTotalPaddingBottom() - 1, y); - y += view.getScrollY(); - return view.getLayout().getLineForVertical((int) y); - } + // Offset for padding + outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop()); + } + } + return outRect; + } - private static int getOffsetAtCoordinate(TextView view, int line, float x) { - x = convertToLocalHorizontalCoordinate(view, x); - return view.getLayout().getOffsetForHorizontal(line, x); + // Compat implementation of TextView#getOffsetForPosition(). + + private static int getOffsetForPosition(TextView view, float x, float y) { + if (view.getLayout() == null) return -1; + final int line = getLineAtCoordinate(view, y); + return getOffsetAtCoordinate(view, line, x); + } + + private static float convertToLocalHorizontalCoordinate(TextView view, float x) { + x -= view.getTotalPaddingLeft(); + // Clamp the position to inside of the view. + x = Math.max(0.0f, x); + x = Math.min(view.getWidth() - view.getTotalPaddingRight() - 1, x); + x += view.getScrollX(); + return x; + } + + private static int getLineAtCoordinate(TextView view, float y) { + y -= view.getTotalPaddingTop(); + // Clamp the position to inside of the view. + y = Math.max(0.0f, y); + y = Math.min(view.getHeight() - view.getTotalPaddingBottom() - 1, y); + y += view.getScrollY(); + return view.getLayout().getLineForVertical((int) y); + } + + private static int getOffsetAtCoordinate(TextView view, int line, float x) { + x = convertToLocalHorizontalCoordinate(view, x); + return view.getLayout().getOffsetForHorizontal(line, x); + } } } diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java similarity index 75% rename from library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java rename to library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java index 844e73e..6228e6f 100644 --- a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java +++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java @@ -14,29 +14,35 @@ * limitations under the License. */ -package com.android.setupwizardlib.test; +package com.android.setupwizardlib.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.graphics.Rect; -import android.os.Build; import android.os.Bundle; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.support.v4.text.BidiFormatter; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; import android.support.v4.widget.ExploreByTouchHelper; import android.text.SpannableStringBuilder; import android.util.DisplayMetrics; import android.util.TypedValue; +import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import android.widget.FrameLayout; import android.widget.TextView; import com.android.setupwizardlib.span.LinkSpan; -import com.android.setupwizardlib.util.LinkAccessibilityHelper; +import com.android.setupwizardlib.util.LinkAccessibilityHelper.PreOLinkAccessibilityHelper; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,13 +58,12 @@ public class LinkAccessibilityHelperTest { private static final LinkSpan LINK_SPAN = new LinkSpan("foobar"); private TextView mTextView; - private TestLinkAccessibilityHelper mHelper; + private TestPreOLinkAccessibilityHelper mHelper; private DisplayMetrics mDisplayMetrics; @Test public void testGetVirtualViewAt() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10)); assertEquals("Virtual view ID should be 1", 1, virtualViewId); @@ -66,7 +71,6 @@ public class LinkAccessibilityHelperTest { @Test public void testGetVirtualViewAtHost() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100)); assertEquals("Virtual view ID should be INVALID_ID", @@ -75,7 +79,6 @@ public class LinkAccessibilityHelperTest { @Test public void testGetVisibleVirtualViews() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); List virtualViewIds = new ArrayList<>(); mHelper.getVisibleVirtualViews(virtualViewIds); @@ -86,7 +89,6 @@ public class LinkAccessibilityHelperTest { @Test public void testOnPopulateEventForVirtualView() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); AccessibilityEvent event = AccessibilityEvent.obtain(); mHelper.onPopulateEventForVirtualView(1, event); @@ -100,7 +102,6 @@ public class LinkAccessibilityHelperTest { @Test public void testOnPopulateEventForVirtualViewHost() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); AccessibilityEvent event = AccessibilityEvent.obtain(); mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event); @@ -113,7 +114,6 @@ public class LinkAccessibilityHelperTest { @Test public void testOnPopulateNodeForVirtualView() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); mHelper.onPopulateNodeForVirtualView(1, info); @@ -132,7 +132,6 @@ public class LinkAccessibilityHelperTest { @Test public void testNullLayout() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; initTextView(); // Setting the padding will cause the layout to be null-ed out. mTextView.setPadding(1, 1, 1, 1); @@ -150,7 +149,6 @@ public class LinkAccessibilityHelperTest { @Test public void testRtlLayout() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום"); ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); initTextView(ssb); @@ -170,7 +168,6 @@ public class LinkAccessibilityHelperTest { @Test public void testMultilineLink() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; SpannableStringBuilder ssb = new SpannableStringBuilder( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + "Praesent accumsan efficitur eros eu porttitor."); @@ -192,7 +189,6 @@ public class LinkAccessibilityHelperTest { @Test public void testRtlMultilineLink() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " + "דפים המחשב מיזמים ב."; @@ -216,7 +212,6 @@ public class LinkAccessibilityHelperTest { @Test public void testBidiMultilineLink() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) return; String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " + "דפים המחשב מיזמים ב."; @@ -243,6 +238,70 @@ public class LinkAccessibilityHelperTest { info.recycle(); } + @Test + public void testMethodDelegation() { + initTextView(); + ExploreByTouchHelper delegate = mock(TestPreOLinkAccessibilityHelper.class); + LinkAccessibilityHelper helper = new LinkAccessibilityHelper(delegate); + + AccessibilityEvent accessibilityEvent = + AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_CLICKED); + + helper.sendAccessibilityEvent(mTextView, AccessibilityEvent.TYPE_VIEW_CLICKED); + verify(delegate).sendAccessibilityEvent( + same(mTextView), + eq(AccessibilityEvent.TYPE_VIEW_CLICKED)); + + helper.sendAccessibilityEventUnchecked(mTextView, accessibilityEvent); + verify(delegate).sendAccessibilityEventUnchecked(same(mTextView), same(accessibilityEvent)); + + helper.performAccessibilityAction( + mTextView, + AccessibilityActionCompat.ACTION_CLICK.getId(), + Bundle.EMPTY); + verify(delegate).performAccessibilityAction( + same(mTextView), + eq(AccessibilityActionCompat.ACTION_CLICK.getId()), + eq(Bundle.EMPTY)); + + helper.dispatchPopulateAccessibilityEvent( + mTextView, + accessibilityEvent); + verify(delegate).dispatchPopulateAccessibilityEvent( + same(mTextView), + same(accessibilityEvent)); + + MotionEvent motionEvent = MotionEvent.obtain(0, 0, 0, 0, 0, 0); + helper.dispatchHoverEvent(motionEvent); + verify(delegate).dispatchHoverEvent(eq(motionEvent)); + + helper.getAccessibilityNodeProvider(mTextView); + verify(delegate).getAccessibilityNodeProvider(same(mTextView)); + + helper.onInitializeAccessibilityEvent(mTextView, accessibilityEvent); + verify(delegate).onInitializeAccessibilityEvent( + same(mTextView), + eq(accessibilityEvent)); + + AccessibilityNodeInfoCompat accessibilityNodeInfo = AccessibilityNodeInfoCompat.obtain(); + helper.onInitializeAccessibilityNodeInfo(mTextView, accessibilityNodeInfo); + verify(delegate).onInitializeAccessibilityNodeInfo( + same(mTextView), + same(accessibilityNodeInfo)); + + helper.onPopulateAccessibilityEvent(mTextView, accessibilityEvent); + verify(delegate).onPopulateAccessibilityEvent( + same(mTextView), + same(accessibilityEvent)); + + FrameLayout parent = new FrameLayout(InstrumentationRegistry.getTargetContext()); + helper.onRequestSendAccessibilityEvent(parent, mTextView, accessibilityEvent); + verify(delegate).onRequestSendAccessibilityEvent( + same(parent), + same(mTextView), + same(accessibilityEvent)); + } + private void initTextView() { SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); @@ -254,7 +313,7 @@ public class LinkAccessibilityHelperTest { mTextView.setSingleLine(false); mTextView.setText(text); mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - mHelper = new TestLinkAccessibilityHelper(mTextView); + mHelper = new TestPreOLinkAccessibilityHelper(mTextView); int measureExactly500dp = View.MeasureSpec.makeMeasureSpec(dp2Px(500), View.MeasureSpec.EXACTLY); @@ -270,9 +329,9 @@ public class LinkAccessibilityHelperTest { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics); } - private static class TestLinkAccessibilityHelper extends LinkAccessibilityHelper { + public static class TestPreOLinkAccessibilityHelper extends PreOLinkAccessibilityHelper { - TestLinkAccessibilityHelper(TextView view) { + TestPreOLinkAccessibilityHelper(TextView view) { super(view); } diff --git a/library/standalone.gradle b/library/standalone.gradle index a2119ac..132b908 100644 --- a/library/standalone.gradle +++ b/library/standalone.gradle @@ -16,5 +16,5 @@ apply from: 'standalone-rules.gradle' -android.compileSdkVersion 25 -android.buildToolsVersion '25.0.0' +android.compileSdkVersion 26 +android.buildToolsVersion '26.0.0' diff --git a/tools/gradle/android.properties b/tools/gradle/android.properties index 75de660..b4a1e0c 100644 --- a/tools/gradle/android.properties +++ b/tools/gradle/android.properties @@ -1,6 +1,6 @@ // Set the default SDK and build tools version for all apps -compileSdkVersion 25 -buildToolsVersion = '25.0.0' +compileSdkVersion 26 +buildToolsVersion = '26.0.0' // enable Java7 compileOptions.sourceCompatibility JavaVersion.VERSION_1_7