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 17b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lampackage com.android.setupwizardlib.util; 18d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 192614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport static org.junit.Assert.assertEquals; 202614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport static org.junit.Assert.assertTrue; 21b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport static org.mockito.Matchers.eq; 22b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport static org.mockito.Matchers.same; 23b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport static org.mockito.Mockito.mock; 24b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport static org.mockito.Mockito.verify; 252614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam 26d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.graphics.Rect; 27d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.os.Bundle; 282614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.InstrumentationRegistry; 292614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.filters.SmallTest; 302614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport android.support.test.runner.AndroidJUnit4; 317c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lamimport android.support.v4.text.BidiFormatter; 32d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 33b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; 34d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.support.v4.widget.ExploreByTouchHelper; 35d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.text.SpannableStringBuilder; 36059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lamimport android.util.DisplayMetrics; 37059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lamimport android.util.TypedValue; 38b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport android.view.MotionEvent; 397c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lamimport android.view.View; 40d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.view.accessibility.AccessibilityEvent; 41b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport android.widget.FrameLayout; 42d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport android.widget.TextView; 43d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 44d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport com.android.setupwizardlib.span.LinkSpan; 45b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lamimport com.android.setupwizardlib.util.LinkAccessibilityHelper.PreOLinkAccessibilityHelper; 46d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 472614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport org.junit.Test; 482614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lamimport org.junit.runner.RunWith; 492614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam 50d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.ArrayList; 51d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.Collections; 52d832154e333a3a45b5faecd518b664ddd297183cMaurice Lamimport java.util.List; 53d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 542614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam@RunWith(AndroidJUnit4.class) 552614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam@SmallTest 562614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lampublic class LinkAccessibilityHelperTest { 57d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 587c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam private static final LinkSpan LINK_SPAN = new LinkSpan("foobar"); 597c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 60d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam private TextView mTextView; 61b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam private TestPreOLinkAccessibilityHelper mHelper; 62d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 63059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam private DisplayMetrics mDisplayMetrics; 64059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam 652614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 66d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void testGetVirtualViewAt() { 677c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 68059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10)); 69d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertEquals("Virtual view ID should be 1", 1, virtualViewId); 70d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 71d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 722614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 73d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void testGetVirtualViewAtHost() { 747c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 75059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100)); 76d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertEquals("Virtual view ID should be INVALID_ID", 77d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam ExploreByTouchHelper.INVALID_ID, virtualViewId); 78d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 79d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 802614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 81d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void testGetVisibleVirtualViews() { 827c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 83d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam List<Integer> virtualViewIds = new ArrayList<>(); 84d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam mHelper.getVisibleVirtualViews(virtualViewIds); 85d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 86d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertEquals("VisibleVirtualViews should be [1]", 87d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam Collections.singletonList(1), virtualViewIds); 88d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 89d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 902614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 91d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void testOnPopulateEventForVirtualView() { 927c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 93d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam AccessibilityEvent event = AccessibilityEvent.obtain(); 94d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam mHelper.onPopulateEventForVirtualView(1, event); 95d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 96d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam // LinkSpan is set on substring(1, 2) of "Hello world" --> "e" 97d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertEquals("LinkSpan description should be \"e\"", 98d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam "e", event.getContentDescription().toString()); 99d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 100d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam event.recycle(); 101d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 102d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 1032614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 104d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void testOnPopulateEventForVirtualViewHost() { 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() { 1177c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 118d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 119d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam mHelper.onPopulateNodeForVirtualView(1, info); 120d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 121d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertEquals("LinkSpan description should be \"e\"", 122d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam "e", info.getContentDescription().toString()); 123d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertTrue("LinkSpan should be focusable", info.isFocusable()); 124d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam assertTrue("LinkSpan should be clickable", info.isClickable()); 125d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam Rect bounds = new Rect(); 126d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam info.getBoundsInParent(bounds); 127059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam assertEquals("LinkSpan bounds should be (10.5dp, 0dp, 18.5dp, 20.5dp)", 128059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam new Rect(dp2Px(10.5f), dp2Px(0f), dp2Px(18.5f), dp2Px(20.5f)), bounds); 129d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 130d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam info.recycle(); 131d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 132d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 1332614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 134cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam public void testNullLayout() { 1357c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(); 136cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam // Setting the padding will cause the layout to be null-ed out. 137cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam mTextView.setPadding(1, 1, 1, 1); 138cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam 139cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 140cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam mHelper.onPopulateNodeForVirtualView(0, info); 141cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam 142cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam Rect bounds = new Rect(); 143cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam info.getBoundsInParent(bounds); 144cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam assertEquals("LinkSpan bounds should be (0, 0, 1, 1)", 145cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam new Rect(0, 0, 1, 1), bounds); 146cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam 147cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam info.recycle(); 148cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam } 149cf90658b5c16018c9f3db7fd1d872025cff5d1dcMaurice Lam 1502614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 15104eecdd42f0bc9751825f9f21131a59852256278Maurice Lam public void testRtlLayout() { 15204eecdd42f0bc9751825f9f21131a59852256278Maurice Lam SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום"); 1537c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); 1547c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(ssb); 15504eecdd42f0bc9751825f9f21131a59852256278Maurice Lam 15604eecdd42f0bc9751825f9f21131a59852256278Maurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 15704eecdd42f0bc9751825f9f21131a59852256278Maurice Lam mHelper.onPopulateNodeForVirtualView(1, info); 15804eecdd42f0bc9751825f9f21131a59852256278Maurice Lam 15904eecdd42f0bc9751825f9f21131a59852256278Maurice Lam assertEquals("LinkSpan description should be \"כ\"", 16004eecdd42f0bc9751825f9f21131a59852256278Maurice Lam "כ", info.getContentDescription().toString()); 16104eecdd42f0bc9751825f9f21131a59852256278Maurice Lam Rect bounds = new Rect(); 16204eecdd42f0bc9751825f9f21131a59852256278Maurice Lam info.getBoundsInParent(bounds); 1637c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan bounds should be (481.5dp, 0dp, 489.5dp, 20.5dp)", 1647c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam new Rect(dp2Px(481.5f), dp2Px(0f), dp2Px(489.5f), dp2Px(20.5f)), bounds); 1657c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1667c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.recycle(); 1677c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam } 1687c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1692614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 1707c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam public void testMultilineLink() { 1717c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam SpannableStringBuilder ssb = new SpannableStringBuilder( 1727c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " 1737c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam + "Praesent accumsan efficitur eros eu porttitor."); 1747c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.setSpan(LINK_SPAN, 51, 74, 0 /* flags */); 1757c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(ssb); 1767c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1777c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 1787c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mHelper.onPopulateNodeForVirtualView(51, info); 1797c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1807c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan description should match the span", 1817c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam "elit. Praesent accumsan", info.getContentDescription().toString()); 1827c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam Rect bounds = new Rect(); 1837c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.getBoundsInParent(bounds); 1847c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan bounds should match first line of the span", 1857c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam new Rect(dp2Px(343f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds); 1867c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1877c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.recycle(); 1887c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam } 1897c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1902614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 1917c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam public void testRtlMultilineLink() { 1927c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " 1937c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " 1947c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam + "דפים המחשב מיזמים ב."; 1957c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam SpannableStringBuilder ssb = new SpannableStringBuilder(iwLoremIpsum); 1967c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.setSpan(LINK_SPAN, 50, 100, 0 /* flags */); 1977c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(ssb); 1987c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 1997c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 2007c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mHelper.onPopulateNodeForVirtualView(50, info); 2017c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 2027c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan description should match the span", 2037c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam iwLoremIpsum.substring(50, 100), 2047c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.getContentDescription().toString()); 2057c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam Rect bounds = new Rect(); 2067c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.getBoundsInParent(bounds); 2077c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan bounds should match the first line of the span", 2087c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam new Rect(dp2Px(0f), dp2Px(0f), dp2Px(150f), dp2Px(19.5f)), bounds); 20904eecdd42f0bc9751825f9f21131a59852256278Maurice Lam 21004eecdd42f0bc9751825f9f21131a59852256278Maurice Lam info.recycle(); 21104eecdd42f0bc9751825f9f21131a59852256278Maurice Lam } 21204eecdd42f0bc9751825f9f21131a59852256278Maurice Lam 2132614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam @Test 2147c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam public void testBidiMultilineLink() { 2157c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " 2167c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " 2177c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam + "דפים המחשב מיזמים ב."; 2187c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam BidiFormatter formatter = BidiFormatter.getInstance(false /* rtlContext */); 2197c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam SpannableStringBuilder ssb = new SpannableStringBuilder(); 2207c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.append("hello ").append(formatter.unicodeWrap(iwLoremIpsum)).append(" world"); 2217c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.setSpan(LINK_SPAN, 2227c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam "hello ".length() + 2, // Add two for the characters added by BidiFormatter 2237c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam "hello ".length() + 2 + iwLoremIpsum.length(), 2247c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 0 /* flags */); 2257c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(ssb); 2267c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 2277c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 2287c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mHelper.onPopulateNodeForVirtualView("hello ".length() + 2, info); 2297c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 2307c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan description should match the span", 2317c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam iwLoremIpsum, 2327c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.getContentDescription().toString()); 2337c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam Rect bounds = new Rect(); 2347c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.getBoundsInParent(bounds); 2357c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam assertEquals("LinkSpan bounds should match the first line of the span", 2367c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam new Rect(dp2Px(491.5f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds); 2377c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 2387c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam info.recycle(); 2397c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam } 2407c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 241b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam @Test 242b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam public void testMethodDelegation() { 243b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam initTextView(); 244b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam ExploreByTouchHelper delegate = mock(TestPreOLinkAccessibilityHelper.class); 245b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam LinkAccessibilityHelper helper = new LinkAccessibilityHelper(delegate); 246b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 247b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam AccessibilityEvent accessibilityEvent = 248b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_CLICKED); 249b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 250b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.sendAccessibilityEvent(mTextView, AccessibilityEvent.TYPE_VIEW_CLICKED); 251b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).sendAccessibilityEvent( 252b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 253b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam eq(AccessibilityEvent.TYPE_VIEW_CLICKED)); 254b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 255b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.sendAccessibilityEventUnchecked(mTextView, accessibilityEvent); 256b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).sendAccessibilityEventUnchecked(same(mTextView), same(accessibilityEvent)); 257b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 258b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.performAccessibilityAction( 259b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam mTextView, 260b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam AccessibilityActionCompat.ACTION_CLICK.getId(), 261b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam Bundle.EMPTY); 262b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).performAccessibilityAction( 263b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 264b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam eq(AccessibilityActionCompat.ACTION_CLICK.getId()), 265b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam eq(Bundle.EMPTY)); 266b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 267b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.dispatchPopulateAccessibilityEvent( 268b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam mTextView, 269b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam accessibilityEvent); 270b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).dispatchPopulateAccessibilityEvent( 271b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 272b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(accessibilityEvent)); 273b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 274b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam MotionEvent motionEvent = MotionEvent.obtain(0, 0, 0, 0, 0, 0); 275b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.dispatchHoverEvent(motionEvent); 276b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).dispatchHoverEvent(eq(motionEvent)); 277b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 278b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.getAccessibilityNodeProvider(mTextView); 279b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).getAccessibilityNodeProvider(same(mTextView)); 280b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 281b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.onInitializeAccessibilityEvent(mTextView, accessibilityEvent); 282b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).onInitializeAccessibilityEvent( 283b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 284b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam eq(accessibilityEvent)); 285b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 286b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam AccessibilityNodeInfoCompat accessibilityNodeInfo = AccessibilityNodeInfoCompat.obtain(); 287b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.onInitializeAccessibilityNodeInfo(mTextView, accessibilityNodeInfo); 288b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).onInitializeAccessibilityNodeInfo( 289b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 290b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(accessibilityNodeInfo)); 291b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 292b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.onPopulateAccessibilityEvent(mTextView, accessibilityEvent); 293b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).onPopulateAccessibilityEvent( 294b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 295b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(accessibilityEvent)); 296b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 297b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam FrameLayout parent = new FrameLayout(InstrumentationRegistry.getTargetContext()); 298b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam helper.onRequestSendAccessibilityEvent(parent, mTextView, accessibilityEvent); 299b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam verify(delegate).onRequestSendAccessibilityEvent( 300b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(parent), 301b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(mTextView), 302b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam same(accessibilityEvent)); 303b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam } 304b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam 3057c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam private void initTextView() { 3067c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); 3077c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); 3087c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam initTextView(ssb); 3097c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam } 3107c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 3117c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam private void initTextView(CharSequence text) { 3122614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam mTextView = new TextView(InstrumentationRegistry.getContext()); 3137c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mTextView.setSingleLine(false); 3147c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mTextView.setText(text); 3157c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); 316b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam mHelper = new TestPreOLinkAccessibilityHelper(mTextView); 3177c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 3187c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam int measureExactly500dp = View.MeasureSpec.makeMeasureSpec(dp2Px(500), 3197c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam View.MeasureSpec.EXACTLY); 3207c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mTextView.measure(measureExactly500dp, measureExactly500dp); 3217c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500)); 3227c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam } 3237c7aa7d0d3cd465b1f4c0aa812fc4006cd7a14adMaurice Lam 324059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam private int dp2Px(float dp) { 325059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam if (mDisplayMetrics == null) { 3262614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam mDisplayMetrics = 3272614260933341bd4ea7bb37a3435f46f82cacef7Maurice Lam InstrumentationRegistry.getContext().getResources().getDisplayMetrics(); 328059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam } 329059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics); 330059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam } 331059321ff28f79a2cbe630b4d814a96ff9254643aMaurice Lam 332b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam public static class TestPreOLinkAccessibilityHelper extends PreOLinkAccessibilityHelper { 333d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 334b72f3fb4598d2bd2560cdf5043defc80a0199e2eMaurice Lam TestPreOLinkAccessibilityHelper(TextView view) { 335d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam super(view); 336d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 337d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 338d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam @Override 339d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public int getVirtualViewAt(float x, float y) { 340d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam return super.getVirtualViewAt(x, y); 341d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 342d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 343d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam @Override 344d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void getVisibleVirtualViews(List<Integer> virtualViewIds) { 345d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam super.getVisibleVirtualViews(virtualViewIds); 346d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 347d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 348d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam @Override 349d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 350d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam super.onPopulateEventForVirtualView(virtualViewId, event); 351d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 352d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 353d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam @Override 354d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public void onPopulateNodeForVirtualView(int virtualViewId, 355d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam AccessibilityNodeInfoCompat info) { 356d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam super.onPopulateNodeForVirtualView(virtualViewId, info); 357d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 358d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam 359d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam @Override 360d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam public boolean onPerformActionForVirtualView(int virtualViewId, int action, 361d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam Bundle arguments) { 362d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam return super.onPerformActionForVirtualView(virtualViewId, action, arguments); 363d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 364d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam } 365d832154e333a3a45b5faecd518b664ddd297183cMaurice Lam} 366