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