Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e914695 authored by Andrew Sapperstein's avatar Andrew Sapperstein
Browse files

Use LinkTextView for support disclaimer text.

LinkTextView uses LinkAccessibilityHelper to properly handle
making links accessible.

Deleted Settings' outdated fork for the version in setupwizardlib.

Test: manual

Change-Id: I38c031f96b5be0d45e4cc1aa358f95b229f17480
Fixes: 31077012
parent 716313a5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@
    android:orientation="vertical"
    android:padding="24dp">

    <TextView
    <com.android.settings.widget.LinkTextView
        android:id="@+id/support_disclaimer_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
+0 −169
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.widget;

import android.graphics.Rect;
import android.os.Bundle;
import android.text.Layout;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;

import java.util.List;

/**
 * Copied from setup wizard.
 */
public class LinkAccessibilityHelper extends ExploreByTouchHelper {

    private static final String TAG = "LinkAccessibilityHelper";

    private final TextView mView;
    private final Rect mTempRect = new Rect();

    public LinkAccessibilityHelper(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 = mView.getOffsetForPosition(x, y);
            ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class);
            if (linkSpans.length == 1) {
                ClickableSpan linkSpan = linkSpans[0];
                return spannedText.getSpanStart(linkSpan);
            }
        }
        return 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));
        } else {
            Log.e(TAG, "ClickableSpan is null for offset: " + virtualViewId);
            event.setContentDescription(mView.getText());
        }
    }

    @Override
    protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo info) {
        final ClickableSpan span = getSpanForOffset(virtualViewId);
        if (span != null) {
            info.setContentDescription(getTextForSpan(span));
        } else {
            Log.e(TAG, "ClickableSpan is null for offset: " + virtualViewId);
            info.setContentDescription(mView.getText());
        }
        info.setFocusable(true);
        info.setClickable(true);
        getBoundsForSpan(span, mTempRect);
        if (!mTempRect.isEmpty()) {
            info.setBoundsInParent(getBoundsForSpan(span, mTempRect));
        } else {
            Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
            mTempRect.set(0, 0, 1, 1);
            info.setBoundsInParent(mTempRect);
        }
        info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
    }

    @Override
    protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
            Bundle arguments) {
        if (action == AccessibilityNodeInfo.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) {
            Spanned spannedText = (Spanned) text;
            final int spanStart = spannedText.getSpanStart(span);
            final int spanEnd = spannedText.getSpanEnd(span);
            final Layout layout = mView.getLayout();
            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);
            outRect.left = (int) xStart;
            if (lineEnd == lineStart) {
                outRect.right = (int) xEnd;
            } // otherwise just leave it at the end of the start line

            // Offset for padding
            outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop());
        }
        return outRect;
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -18,12 +18,14 @@ package com.android.settings.widget;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v13.view.ViewCompat;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;
import com.android.setupwizardlib.util.LinkAccessibilityHelper;

/**
 * Copied from setup wizard.
@@ -39,7 +41,7 @@ public class LinkTextView extends TextView {
    public LinkTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mAccessibilityHelper = new LinkAccessibilityHelper(this);
        setAccessibilityDelegate(mAccessibilityHelper);
        ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
    }

    @Override