1d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam/*
2d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * Copyright (C) 2016 The Android Open Source Project
3d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam *
4d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License");
5d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * you may not use this file except in compliance with the License.
6d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * You may obtain a copy of the License at
7d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam *
8d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam *      http://www.apache.org/licenses/LICENSE-2.0
9d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam *
10d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * Unless required by applicable law or agreed to in writing, software
11d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS,
12d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * See the License for the specific language governing permissions and
14d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam * limitations under the License.
15d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam */
16d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
17d832154e333a3a45b5faecd518b664ddd297183cMaurice Lampackage com.android.setupwizardlib.test;
18d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
191dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaverimport static android.support.v4.os.BuildCompat.isAtLeastO;
201dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver
212614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport static org.junit.Assert.assertEquals;
222614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport static org.junit.Assert.assertTrue;
232614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam
24d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.graphics.Rect;
25d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.os.Bundle;
262614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.InstrumentationRegistry;
272614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.filters.SmallTest;
282614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.runner.AndroidJUnit4;
297c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lamimport android.support.v4.text.BidiFormatter;
30d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
31d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.support.v4.widget.ExploreByTouchHelper;
32d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.text.SpannableStringBuilder;
33059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lamimport android.util.DisplayMetrics;
34059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lamimport android.util.TypedValue;
357c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lamimport android.view.View;
36d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.view.accessibility.AccessibilityEvent;
37d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.widget.TextView;
38d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
39d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport com.android.setupwizardlib.span.LinkSpan;
40d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport com.android.setupwizardlib.util.LinkAccessibilityHelper;
41d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
422614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport org.junit.Test;
432614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport org.junit.runner.RunWith;
442614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam
45d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.ArrayList;
46d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.Collections;
47d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.List;
48d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
492614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam@RunWith(AndroidJUnit4.class)
502614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam@SmallTest
512614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lampublic class LinkAccessibilityHelperTest {
52d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
537c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    private static final LinkSpan LINK_SPAN = new LinkSpan("foobar");
547c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
55d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    private TextView mTextView;
56d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    private TestLinkAccessibilityHelper mHelper;
57d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
58059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam    private DisplayMetrics mDisplayMetrics;
59059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam
602614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
61d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testGetVirtualViewAt() {
621dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
637c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
64059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10));
65d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("Virtual view ID should be 1", 1, virtualViewId);
66d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
67d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
682614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
69d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testGetVirtualViewAtHost() {
701dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
717c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
72059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100));
73d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("Virtual view ID should be INVALID_ID",
74d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                ExploreByTouchHelper.INVALID_ID, virtualViewId);
75d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
76d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
772614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
78d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testGetVisibleVirtualViews() {
791dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
807c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
81d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        List<Integer> virtualViewIds = new ArrayList<>();
82d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        mHelper.getVisibleVirtualViews(virtualViewIds);
83d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
84d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("VisibleVirtualViews should be [1]",
85d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                Collections.singletonList(1), virtualViewIds);
86d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
87d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
882614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
89d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testOnPopulateEventForVirtualView() {
901dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
917c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
92d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        AccessibilityEvent event = AccessibilityEvent.obtain();
93d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        mHelper.onPopulateEventForVirtualView(1, event);
94d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
95d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        // LinkSpan is set on substring(1, 2) of "Hello world" --> "e"
96d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("LinkSpan description should be \"e\"",
97d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                "e", event.getContentDescription().toString());
98d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
99d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        event.recycle();
100d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
101d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
1022614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
103d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testOnPopulateEventForVirtualViewHost() {
1041dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
1057c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
106d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        AccessibilityEvent event = AccessibilityEvent.obtain();
107d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event);
108d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
109d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("Host view description should be \"Hello world\"", "Hello world",
110d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                event.getContentDescription().toString());
111d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
112d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        event.recycle();
113d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
114d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
1152614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
116d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    public void testOnPopulateNodeForVirtualView() {
1171dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
1187c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
119d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
120d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        mHelper.onPopulateNodeForVirtualView(1, info);
121d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
122d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertEquals("LinkSpan description should be \"e\"",
123d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                "e", info.getContentDescription().toString());
124d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertTrue("LinkSpan should be focusable", info.isFocusable());
125d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        assertTrue("LinkSpan should be clickable", info.isClickable());
126d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        Rect bounds = new Rect();
127d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        info.getBoundsInParent(bounds);
128059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        assertEquals("LinkSpan bounds should be (10.5dp, 0dp, 18.5dp, 20.5dp)",
129059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam                new Rect(dp2Px(10.5f), dp2Px(0f), dp2Px(18.5f), dp2Px(20.5f)), bounds);
130d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
131d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        info.recycle();
132d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
133d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
1342614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
135cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam    public void testNullLayout() {
1361dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
1377c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView();
138cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        // Setting the padding will cause the layout to be null-ed out.
139cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        mTextView.setPadding(1, 1, 1, 1);
140cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam
141cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
142cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        mHelper.onPopulateNodeForVirtualView(0, info);
143cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam
144cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        Rect bounds = new Rect();
145cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        info.getBoundsInParent(bounds);
146cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        assertEquals("LinkSpan bounds should be (0, 0, 1, 1)",
147cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam                new Rect(0, 0, 1, 1), bounds);
148cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam
149cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam        info.recycle();
150cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam    }
151cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam
1522614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
15304eecdd42f0bc9751825f9f21131a59852256278Maurice Lam    public void testRtlLayout() {
1541dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
15504eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום");
1567c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
1577c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView(ssb);
15804eecdd42f0bc9751825f9f21131a59852256278Maurice Lam
15904eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
16004eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        mHelper.onPopulateNodeForVirtualView(1, info);
16104eecdd42f0bc9751825f9f21131a59852256278Maurice Lam
16204eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        assertEquals("LinkSpan description should be \"כ\"",
16304eecdd42f0bc9751825f9f21131a59852256278Maurice Lam                "כ", info.getContentDescription().toString());
16404eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        Rect bounds = new Rect();
16504eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        info.getBoundsInParent(bounds);
1667c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan bounds should be (481.5dp, 0dp, 489.5dp, 20.5dp)",
1677c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                new Rect(dp2Px(481.5f), dp2Px(0f), dp2Px(489.5f), dp2Px(20.5f)), bounds);
1687c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1697c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.recycle();
1707c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    }
1717c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1722614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
1737c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    public void testMultilineLink() {
1741dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
1757c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        SpannableStringBuilder ssb = new SpannableStringBuilder(
1767c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
1777c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                + "Praesent accumsan efficitur eros eu porttitor.");
1787c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.setSpan(LINK_SPAN, 51, 74, 0 /* flags */);
1797c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView(ssb);
1807c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1817c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
1827c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mHelper.onPopulateNodeForVirtualView(51, info);
1837c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1847c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan description should match the span",
1857c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                "elit. Praesent accumsan", info.getContentDescription().toString());
1867c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        Rect bounds = new Rect();
1877c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.getBoundsInParent(bounds);
1887c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan bounds should match first line of the span",
1897c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                new Rect(dp2Px(343f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds);
1907c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1917c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.recycle();
1927c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    }
1937c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
1942614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
1957c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    public void testRtlMultilineLink() {
1961dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
1977c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
1987c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
1997c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                + "דפים המחשב מיזמים ב.";
2007c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        SpannableStringBuilder ssb = new SpannableStringBuilder(iwLoremIpsum);
2017c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.setSpan(LINK_SPAN, 50, 100, 0 /* flags */);
2027c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView(ssb);
2037c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2047c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
2057c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mHelper.onPopulateNodeForVirtualView(50, info);
2067c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2077c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan description should match the span",
2087c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                iwLoremIpsum.substring(50, 100),
2097c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                info.getContentDescription().toString());
2107c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        Rect bounds = new Rect();
2117c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.getBoundsInParent(bounds);
2127c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan bounds should match the first line of the span",
2137c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                new Rect(dp2Px(0f), dp2Px(0f), dp2Px(150f), dp2Px(19.5f)), bounds);
21404eecdd42f0bc9751825f9f21131a59852256278Maurice Lam
21504eecdd42f0bc9751825f9f21131a59852256278Maurice Lam        info.recycle();
21604eecdd42f0bc9751825f9f21131a59852256278Maurice Lam    }
21704eecdd42f0bc9751825f9f21131a59852256278Maurice Lam
2182614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam    @Test
2197c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    public void testBidiMultilineLink() {
2201dcf260b5556208115dc649534dd66d59ec7a5c6Phil Weaver        if (isAtLeastO()) return;
2217c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
2227c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
2237c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                + "דפים המחשב מיזמים ב.";
2247c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        BidiFormatter formatter = BidiFormatter.getInstance(false /* rtlContext */);
2257c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        SpannableStringBuilder ssb = new SpannableStringBuilder();
2267c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.append("hello ").append(formatter.unicodeWrap(iwLoremIpsum)).append(" world");
2277c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.setSpan(LINK_SPAN,
2287c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                "hello ".length() + 2, // Add two for the characters added by BidiFormatter
2297c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                "hello ".length() + 2 + iwLoremIpsum.length(),
2307c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                0 /* flags */);
2317c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView(ssb);
2327c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2337c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
2347c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mHelper.onPopulateNodeForVirtualView("hello ".length() + 2, info);
2357c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2367c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan description should match the span",
2377c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                iwLoremIpsum,
2387c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                info.getContentDescription().toString());
2397c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        Rect bounds = new Rect();
2407c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.getBoundsInParent(bounds);
2417c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        assertEquals("LinkSpan bounds should match the first line of the span",
2427c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                new Rect(dp2Px(491.5f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds);
2437c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2447c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        info.recycle();
2457c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    }
2467c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2477c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    private void initTextView() {
2487c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
2497c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
2507c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        initTextView(ssb);
2517c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    }
2527c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2537c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    private void initTextView(CharSequence text) {
2542614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam        mTextView = new TextView(InstrumentationRegistry.getContext());
2557c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mTextView.setSingleLine(false);
2567c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mTextView.setText(text);
2577c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
2587c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mHelper = new TestLinkAccessibilityHelper(mTextView);
2597c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
2607c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        int measureExactly500dp = View.MeasureSpec.makeMeasureSpec(dp2Px(500),
2617c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam                View.MeasureSpec.EXACTLY);
2627c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mTextView.measure(measureExactly500dp, measureExactly500dp);
2637c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam        mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500));
2647c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam    }
2657c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam
266059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam    private int dp2Px(float dp) {
267059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        if (mDisplayMetrics == null) {
2682614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam            mDisplayMetrics =
2692614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam                    InstrumentationRegistry.getContext().getResources().getDisplayMetrics();
270059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        }
271059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics);
272059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam    }
273059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam
274d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    private static class TestLinkAccessibilityHelper extends LinkAccessibilityHelper {
275d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
276d60659421446329c7a7af2a009a51413d5388254Maurice Lam        TestLinkAccessibilityHelper(TextView view) {
277d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            super(view);
278d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
279d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
280d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        @Override
281d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        public int getVirtualViewAt(float x, float y) {
282d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            return super.getVirtualViewAt(x, y);
283d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
284d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
285d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        @Override
286d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        public void getVisibleVirtualViews(List<Integer> virtualViewIds) {
287d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            super.getVisibleVirtualViews(virtualViewIds);
288d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
289d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
290d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        @Override
291d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
292d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            super.onPopulateEventForVirtualView(virtualViewId, event);
293d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
294d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
295d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        @Override
296d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        public void onPopulateNodeForVirtualView(int virtualViewId,
297d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                AccessibilityNodeInfoCompat info) {
298d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            super.onPopulateNodeForVirtualView(virtualViewId, info);
299d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
300d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam
301d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        @Override
302d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        public boolean onPerformActionForVirtualView(int virtualViewId, int action,
303d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam                Bundle arguments) {
304d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam            return super.onPerformActionForVirtualView(virtualViewId, action, arguments);
305d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam        }
306d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam    }
307d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam}
308