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