summaryrefslogtreecommitdiff
path: root/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java')
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java467
1 files changed, 232 insertions, 235 deletions
diff --git a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
index 2a378e8..c416a9e 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
@@ -19,6 +19,12 @@ package com.android.setupwizardlib.util;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
import android.text.Layout;
import android.text.Spanned;
import android.text.style.ClickableSpan;
@@ -28,14 +34,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.view.AccessibilityDelegateCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
-import androidx.customview.widget.ExploreByTouchHelper;
-
import java.util.List;
/**
@@ -46,6 +44,7 @@ import java.util.List;
* support for ClickableSpan accessibility.
*
* <p>Sample usage:
+ *
* <pre>
* LinkAccessibilityHelper mAccessibilityHelper;
*
@@ -68,262 +67,260 @@ import java.util.List;
*/
public class LinkAccessibilityHelper extends AccessibilityDelegateCompat {
- private static final String TAG = "LinkAccessibilityHelper";
-
- private final AccessibilityDelegateCompat mDelegate;
-
- public LinkAccessibilityHelper(TextView view) {
- 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));
- }
-
- @VisibleForTesting
- LinkAccessibilityHelper(@NonNull AccessibilityDelegateCompat delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public void sendAccessibilityEvent(View host, int eventType) {
- mDelegate.sendAccessibilityEvent(host, eventType);
+ private static final String TAG = "LinkAccessibilityHelper";
+
+ private final AccessibilityDelegateCompat delegate;
+
+ public LinkAccessibilityHelper(TextView view) {
+ 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));
+ }
+
+ @VisibleForTesting
+ LinkAccessibilityHelper(@NonNull AccessibilityDelegateCompat delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void sendAccessibilityEvent(View host, int eventType) {
+ delegate.sendAccessibilityEvent(host, eventType);
+ }
+
+ @Override
+ public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+ delegate.sendAccessibilityEventUnchecked(host, event);
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ return delegate.dispatchPopulateAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ delegate.onPopulateAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+ delegate.onInitializeAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+ delegate.onInitializeAccessibilityNodeInfo(host, info);
+ }
+
+ @Override
+ public boolean onRequestSendAccessibilityEvent(
+ ViewGroup host, View child, AccessibilityEvent event) {
+ return delegate.onRequestSendAccessibilityEvent(host, child, event);
+ }
+
+ @Override
+ public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
+ return delegate.getAccessibilityNodeProvider(host);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ return delegate.performAccessibilityAction(host, action, args);
+ }
+
+ /**
+ * Dispatches hover event to the virtual view hierarchy. This method should be called in {@link
+ * View#dispatchHoverEvent(MotionEvent)}.
+ *
+ * @see ExploreByTouchHelper#dispatchHoverEvent(MotionEvent)
+ */
+ public boolean dispatchHoverEvent(MotionEvent event) {
+ return delegate instanceof ExploreByTouchHelper
+ && ((ExploreByTouchHelper) delegate).dispatchHoverEvent(event);
+ }
+
+ @VisibleForTesting
+ static class PreOLinkAccessibilityHelper extends ExploreByTouchHelper {
+
+ private final Rect tempRect = new Rect();
+ private final TextView view;
+
+ PreOLinkAccessibilityHelper(TextView view) {
+ super(view);
+ this.view = view;
}
@Override
- public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
- mDelegate.sendAccessibilityEventUnchecked(host, event);
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- return mDelegate.dispatchPopulateAccessibilityEvent(host, event);
- }
-
- @Override
- public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- mDelegate.onPopulateAccessibilityEvent(host, event);
+ protected int getVirtualViewAt(float x, float y) {
+ final CharSequence text = view.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ final int offset = getOffsetForPosition(view, 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;
}
@Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- mDelegate.onInitializeAccessibilityEvent(host, event);
+ protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ final CharSequence text = view.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));
+ }
+ }
}
@Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
- mDelegate.onInitializeAccessibilityNodeInfo(host, info);
+ 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(view.getText());
+ }
}
@Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- return mDelegate.onRequestSendAccessibilityEvent(host, child, event);
+ 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(view.getText());
+ }
+ info.setFocusable(true);
+ info.setClickable(true);
+ getBoundsForSpan(span, tempRect);
+ if (tempRect.isEmpty()) {
+ Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
+ tempRect.set(0, 0, 1, 1);
+ }
+ info.setBoundsInParent(tempRect);
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
}
@Override
- public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
- return mDelegate.getAccessibilityNodeProvider(host);
+ protected boolean onPerformActionForVirtualView(
+ int virtualViewId, int action, Bundle arguments) {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+ ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ span.onClick(view);
+ return true;
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ }
+ }
+ return false;
}
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- return mDelegate.performAccessibilityAction(host, action, args);
+ private ClickableSpan getSpanForOffset(int offset) {
+ CharSequence text = view.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;
}
- /**
- * 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 mDelegate instanceof ExploreByTouchHelper
- && ((ExploreByTouchHelper) mDelegate).dispatchHoverEvent(event);
+ private CharSequence getTextForSpan(ClickableSpan span) {
+ CharSequence text = view.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ return spannedText.subSequence(
+ spannedText.getSpanStart(span), spannedText.getSpanEnd(span));
+ }
+ return text;
}
- @VisibleForTesting
- static class PreOLinkAccessibilityHelper extends ExploreByTouchHelper {
-
- private final Rect mTempRect = new Rect();
- private final TextView mView;
-
- PreOLinkAccessibilityHelper(TextView view) {
- super(view);
- mView = view;
- }
-
- @Override
- 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;
- }
-
- @Override
- protected void getVisibleVirtualViews(List<Integer> 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));
- }
- }
- }
-
- @Override
- protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
- final ClickableSpan span = getSpanForOffset(virtualViewId);
- if (span != null) {
- event.setContentDescription(getTextForSpan(span));
+ // 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 = view.getText();
+ outRect.setEmpty();
+ if (text instanceof Spanned) {
+ final Layout layout = view.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 {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- event.setContentDescription(mView.getText());
+ outRect.left = (int) xStart;
}
- }
-
- @Override
- 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);
- }
+ }
- @Override
- 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 {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- }
- }
- 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];
- }
- }
- 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);
- } 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;
- }
- }
-
- // Offset for padding
- outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop());
- }
- }
- return outRect;
+ // Offset for padding
+ outRect.offset(view.getTotalPaddingLeft(), view.getTotalPaddingTop());
}
+ }
+ return outRect;
+ }
- // Compat implementation of TextView#getOffsetForPosition().
+ // 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 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 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 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);
- }
+ private static int getOffsetAtCoordinate(TextView view, int line, float x) {
+ x = convertToLocalHorizontalCoordinate(view, x);
+ return view.getLayout().getOffsetForHorizontal(line, x);
}
+ }
}