10906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette/* 20906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * Copyright (C) 2016 The Android Open Source Project 30906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * 40906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 50906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * you may not use this file except in compliance with the License. 60906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * You may obtain a copy of the License at 70906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * 80906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 90906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * 100906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * Unless required by applicable law or agreed to in writing, software 110906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 120906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * See the License for the specific language governing permissions and 140906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * limitations under the License. 150906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette */ 160906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 170906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverettepackage android.support.v4.widget; 180906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 19754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static junit.framework.Assert.assertFalse; 20754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 21754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertEquals; 22754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertNotNull; 23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assume.assumeTrue; 24754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 250906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.graphics.Rect; 260906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.os.Build; 270906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.os.Bundle; 28ff22d81f6561f6cdd2a91eb63238c41079927a22Kirill Grouchnikovimport android.support.coreui.test.R; 290906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.support.test.annotation.UiThreadTest; 30754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.SmallTest; 310906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.support.v4.BaseInstrumentationTestCase; 320906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.support.v4.view.ViewCompat; 330906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 340906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport android.view.View; 35754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 36ff22d81f6561f6cdd2a91eb63238c41079927a22Kirill Grouchnikovimport org.junit.Before; 37ff22d81f6561f6cdd2a91eb63238c41079927a22Kirill Grouchnikovimport org.junit.Test; 380906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 390906dafe25770e872a72f8abd2c044b0faef86d7Alan Viveretteimport java.util.List; 400906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 410906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette@SmallTest 420906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverettepublic class ExploreByTouchHelperTest extends BaseInstrumentationTestCase<ExploreByTouchHelperTestActivity> { 430906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette private View mHost; 440906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 450906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette public ExploreByTouchHelperTest() { 460906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette super(ExploreByTouchHelperTestActivity.class); 470906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 480906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 490906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Before 500906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette public void setUp() { 510906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette // Accessibility delegates are only supported on API 14+. 520906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assumeTrue(Build.VERSION.SDK_INT >= 14); 530906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette mHost = mActivityTestRule.getActivity().findViewById(R.id.host_view); 540906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 550906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 560906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Test 570906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @UiThreadTest 580906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette public void testBoundsInScreen() { 590906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final ExploreByTouchHelper helper = new ParentBoundsHelper(mHost); 600906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette ViewCompat.setAccessibilityDelegate(mHost, helper); 610906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 620906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final AccessibilityNodeInfoCompat node = 630906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1); 640906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertNotNull(node); 650906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 660906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect hostBounds = new Rect(); 670906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette mHost.getLocalVisibleRect(hostBounds); 680906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertFalse("Host has not been laid out", hostBounds.isEmpty()); 690906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 700906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect nodeBoundsInParent = new Rect(); 710906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette node.getBoundsInParent(nodeBoundsInParent); 720906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertEquals("Wrong bounds in parent", hostBounds, nodeBoundsInParent); 730906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 740906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect hostBoundsOnScreen = getBoundsOnScreen(mHost); 750906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect nodeBoundsInScreen = new Rect(); 760906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette node.getBoundsInScreen(nodeBoundsInScreen); 770906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertEquals("Wrong bounds in screen", hostBoundsOnScreen, nodeBoundsInScreen); 780906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 790906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final int scrollX = 100; 800906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final int scrollY = 50; 810906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette mHost.scrollTo(scrollX, scrollY); 820906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 830906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette // Generate a node for the new position. 840906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final AccessibilityNodeInfoCompat scrolledNode = 850906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1); 860906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertNotNull(scrolledNode); 870906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 883b591130c68223aa613660aaff79e65e26b5fc06Zach Kuznia // Bounds in parent should not be affected by visibility. 890906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect scrolledNodeBoundsInParent = new Rect(); 900906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette scrolledNode.getBoundsInParent(scrolledNodeBoundsInParent); 910906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertEquals("Wrong bounds in parent after scrolling", 920906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette hostBounds, scrolledNodeBoundsInParent); 930906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 940906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect expectedBoundsInScreen = new Rect(hostBoundsOnScreen); 950906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette expectedBoundsInScreen.offset(-scrollX, -scrollY); 960906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette expectedBoundsInScreen.intersect(hostBoundsOnScreen); 970906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette scrolledNode.getBoundsInScreen(nodeBoundsInScreen); 980906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette assertEquals("Wrong bounds in screen after scrolling", 990906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette expectedBoundsInScreen, nodeBoundsInScreen); 1000906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1010906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette ViewCompat.setAccessibilityDelegate(mHost, null); 1020906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1030906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1040906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette private static Rect getBoundsOnScreen(View v) { 1050906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final int[] tempLocation = new int[2]; 1060906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect hostBoundsOnScreen = new Rect(0, 0, v.getWidth(), v.getHeight()); 1070906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette v.getLocationOnScreen(tempLocation); 1080906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette hostBoundsOnScreen.offset(tempLocation[0], tempLocation[1]); 1090906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette return hostBoundsOnScreen; 1100906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1110906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1120906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette /** 1130906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * An extension of ExploreByTouchHelper that contains a single virtual view 1140906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette * whose bounds match the host view. 1150906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette */ 1160906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette private static class ParentBoundsHelper extends ExploreByTouchHelper { 1170906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette private final View mHost; 1180906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1190906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette public ParentBoundsHelper(View host) { 1200906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette super(host); 1210906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1220906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette mHost = host; 1230906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1240906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1250906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Override 1260906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette protected int getVirtualViewAt(float x, float y) { 1270906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette return 1; 1280906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1290906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1300906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Override 1310906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette protected void getVisibleVirtualViews(List<Integer> virtualViewIds) { 1320906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette virtualViewIds.add(1); 1330906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1340906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1350906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Override 1360906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) { 1370906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette if (virtualViewId == 1) { 1380906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette node.setContentDescription("test"); 1390906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1400906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette final Rect hostBounds = new Rect(0, 0, mHost.getWidth(), mHost.getHeight()); 1410906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette node.setBoundsInParent(hostBounds); 1420906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1430906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1440906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette 1450906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette @Override 1460906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) { 1470906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette return false; 1480906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1490906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette } 1500906dafe25770e872a72f8abd2c044b0faef86d7Alan Viverette} 151