15427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov/* 25427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Copyright (C) 2015 The Android Open Source Project 35427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * 45427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Licensed under the Apache License, Version 2.0 (the "License"); 55427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * you may not use this file except in compliance with the License. 65427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * You may obtain a copy of the License at 75427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * 85427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * http://www.apache.org/licenses/LICENSE-2.0 95427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * 105427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Unless required by applicable law or agreed to in writing, software 115427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * distributed under the License is distributed on an "AS IS" BASIS, 125427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * See the License for the specific language governing permissions and 145427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * limitations under the License. 155427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 165427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 175427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovpackage android.support.v4.view; 185427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikovimport android.support.annotation.Nullable; 2029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikovimport android.support.test.espresso.Espresso; 2129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikovimport android.support.test.espresso.IdlingResource; 225427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovimport android.support.test.espresso.UiController; 235427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovimport android.support.test.espresso.ViewAction; 2459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport android.support.test.espresso.action.CoordinatesProvider; 2559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport android.support.test.espresso.action.GeneralClickAction; 2659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport android.support.test.espresso.action.Press; 2759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport android.support.test.espresso.action.Tap; 285427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovimport android.view.View; 2959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport android.widget.TextView; 305427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovimport org.hamcrest.Matcher; 315427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 3259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; 3359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikovimport static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; 3459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov 355427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikovpublic class ViewPagerActions { 365427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov /** 3729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov * View pager listener that serves as Espresso's {@link IdlingResource} and notifies the 3829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov * registered callback when the view pager gets to STATE_IDLE state. 3929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov */ 4029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov private static class CustomViewPagerListener 4129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov implements ViewPager.OnPageChangeListener, IdlingResource { 4229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov private int mCurrState = ViewPager.SCROLL_STATE_IDLE; 4329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 4429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Nullable 4529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov private IdlingResource.ResourceCallback mCallback; 4629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 4729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov private boolean mNeedsIdle = false; 4829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 4929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 5029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { 5129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov mCallback = resourceCallback; 5229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 5329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 5429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 5529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public String getName() { 5629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "View pager listener"; 5729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 5829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 5929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 6029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public boolean isIdleNow() { 6129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (!mNeedsIdle) { 6229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return true; 6329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } else { 6429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return mCurrState == ViewPager.SCROLL_STATE_IDLE; 6529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 6629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 6729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 6829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 6929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public void onPageSelected(int position) { 7029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (mCurrState == ViewPager.SCROLL_STATE_IDLE) { 7129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (mCallback != null) { 7229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov mCallback.onTransitionToIdle(); 7329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 7429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 7529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 7629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 7729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 7829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public void onPageScrollStateChanged(int state) { 7929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov mCurrState = state; 8029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (mCurrState == ViewPager.SCROLL_STATE_IDLE) { 8129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (mCallback != null) { 8229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov mCallback.onTransitionToIdle(); 8329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 8429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 8529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 8629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 8729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 8829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 8929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 9029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 9129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 9229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov private abstract static class WrappedViewAction implements ViewAction { 9329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 9429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 9529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction wrap(final ViewAction baseAction) { 9629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov if (baseAction instanceof WrappedViewAction) { 9729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov throw new IllegalArgumentException("Don't wrap an already wrapped action"); 9829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 9929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 10029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return new WrappedViewAction() { 10129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 10229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public Matcher<View> getConstraints() { 10329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return baseAction.getConstraints(); 10429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 10529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 10629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 10729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public String getDescription() { 10829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return baseAction.getDescription(); 10929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 11029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 11129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov @Override 11229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public final void perform(UiController uiController, View view) { 11329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov final ViewPager viewPager = (ViewPager) view; 11429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // Add a custom tracker listener 11529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov final CustomViewPagerListener customListener = new CustomViewPagerListener(); 11629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.addOnPageChangeListener(customListener); 11729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 11829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // Note that we're running the following block in a try-finally construct. This 11929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // is needed since some of the wrapped actions are going to throw (expected) 12029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // exceptions. If that happens, we still need to clean up after ourselves to 12129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // leave the system (Espesso) in a good state. 12229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov try { 12329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // Register our listener as idling resource so that Espresso waits until the 12429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // wrapped action results in the view pager getting to the STATE_IDLE state 12529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov Espresso.registerIdlingResources(customListener); 12629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov baseAction.perform(uiController, view); 12729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov customListener.mNeedsIdle = true; 12829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov uiController.loopMainThreadUntilIdle(); 12929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov customListener.mNeedsIdle = false; 13029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } finally { 13129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // Unregister our idling resource 13229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov Espresso.unregisterIdlingResources(customListener); 13329212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov // And remove our tracker listener from ViewPager 13429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.removeOnPageChangeListener(customListener); 13529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 13629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 13729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }; 13829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov } 13929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov 14029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov /** 1418a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas * Scrolls <code>ViewPager</code> using arrowScroll method in a specified direction. 1428a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas */ 1438a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas public static ViewAction arrowScroll(final int direction) { 1448a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas return wrap(new ViewAction() { 1458a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas @Override 1468a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas public Matcher<View> getConstraints() { 1478a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas return isDisplayingAtLeast(90); 1488a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas } 1498a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas 1508a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas @Override 1518a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas public String getDescription() { 1528a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas return "ViewPager arrow scroll in direction: " + direction; 1538a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas } 1548a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas 1558a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas @Override 1568a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas public void perform(UiController uiController, View view) { 1578a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas uiController.loopMainThreadUntilIdle(); 1588a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas 1598a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas ViewPager viewPager = (ViewPager) view; 1608a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas viewPager.arrowScroll(direction); 1618a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas uiController.loopMainThreadUntilIdle(); 1628a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas } 1638a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas }); 1648a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas } 1658a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas 1668a99b874fa855f70e7ebd23254cdd3069603eb7fAurimas Liutikas /** 1675427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Moves <code>ViewPager</code> to the right by one page. 1685427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 16929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction scrollRight(final boolean smoothScroll) { 17029212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return wrap(new ViewAction() { 1715427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 1725427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public Matcher<View> getConstraints() { 1735427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov return isDisplayingAtLeast(90); 1745427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 1755427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1765427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 1775427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public String getDescription() { 17829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "ViewPager move one page to the right"; 1795427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 1805427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1815427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 1825427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public void perform(UiController uiController, View view) { 1835427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 1845427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1855427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov ViewPager viewPager = (ViewPager) view; 1865427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov int current = viewPager.getCurrentItem(); 18729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.setCurrentItem(current + 1, smoothScroll); 1885427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1895427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 1905427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 19129212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }); 1925427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 1935427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 1945427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov /** 1955427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Moves <code>ViewPager</code> to the left by one page. 1965427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 19729212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction scrollLeft(final boolean smoothScroll) { 19829212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return wrap(new ViewAction() { 1995427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2005427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public Matcher<View> getConstraints() { 2015427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov return isDisplayingAtLeast(90); 2025427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2035427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2045427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2055427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public String getDescription() { 20629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "ViewPager move one page to the left"; 2075427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2085427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2095427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2105427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public void perform(UiController uiController, View view) { 2115427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2125427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2135427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov ViewPager viewPager = (ViewPager) view; 2145427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov int current = viewPager.getCurrentItem(); 21529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.setCurrentItem(current - 1, smoothScroll); 2165427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2175427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2185427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 21929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }); 2205427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2215427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2225427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov /** 2235427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Moves <code>ViewPager</code> to the last page. 2245427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 22529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction scrollToLast(final boolean smoothScroll) { 22629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return wrap(new ViewAction() { 2275427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2285427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public Matcher<View> getConstraints() { 2295427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov return isDisplayingAtLeast(90); 2305427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2315427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2325427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2335427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public String getDescription() { 23429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "ViewPager move to last page"; 2355427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2365427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2375427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2385427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public void perform(UiController uiController, View view) { 2395427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2405427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2415427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov ViewPager viewPager = (ViewPager) view; 2425427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov int size = viewPager.getAdapter().getCount(); 2435427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov if (size > 0) { 24429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.setCurrentItem(size - 1, smoothScroll); 2455427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2465427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2475427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2485427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 24929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }); 2505427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2515427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2525427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov /** 2535427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Moves <code>ViewPager</code> to the first page. 2545427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 25529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction scrollToFirst(final boolean smoothScroll) { 25629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return wrap(new ViewAction() { 2575427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2585427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public Matcher<View> getConstraints() { 2595427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov return isDisplayingAtLeast(90); 2605427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2615427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2625427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2635427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public String getDescription() { 26429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "ViewPager move to first page"; 2655427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2665427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2675427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2685427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public void perform(UiController uiController, View view) { 2695427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2705427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2715427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov ViewPager viewPager = (ViewPager) view; 2725427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov int size = viewPager.getAdapter().getCount(); 2735427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov if (size > 0) { 27429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.setCurrentItem(0, smoothScroll); 2755427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2765427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2775427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 2785427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 27929212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }); 2805427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2815427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2825427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov /** 2835427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov * Moves <code>ViewPager</code> to specific page. 2845427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov */ 28529212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov public static ViewAction scrollToPage(final int page, final boolean smoothScroll) { 28629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return wrap(new ViewAction() { 2875427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2885427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public Matcher<View> getConstraints() { 2895427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov return isDisplayingAtLeast(90); 2905427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2915427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2925427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2935427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public String getDescription() { 29429212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov return "ViewPager move to page"; 2955427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 2965427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 2975427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov @Override 2985427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov public void perform(UiController uiController, View view) { 2995427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 3005427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 3015427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov ViewPager viewPager = (ViewPager) view; 30229212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov viewPager.setCurrentItem(page, smoothScroll); 3035427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov 3045427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov uiController.loopMainThreadUntilIdle(); 3055427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 30629212b535486a2f7c6dc7e35ede84f9fa4816e70Kirill Grouchnikov }); 3075427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov } 308a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov 309a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov /** 310a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov * Moves <code>ViewPager</code> to specific page. 311a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov */ 312a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov public static ViewAction setAdapter(final PagerAdapter adapter) { 313a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov return new ViewAction() { 314a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov @Override 315a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov public Matcher<View> getConstraints() { 316a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov return isAssignableFrom(ViewPager.class); 317a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov } 318a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov 319a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov @Override 320a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov public String getDescription() { 321a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov return "ViewPager set adapter"; 322a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov } 323a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov 324a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov @Override 325a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov public void perform(UiController uiController, View view) { 326a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov uiController.loopMainThreadUntilIdle(); 327a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov 328a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov ViewPager viewPager = (ViewPager) view; 329a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov viewPager.setAdapter(adapter); 330a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov 331a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov uiController.loopMainThreadUntilIdle(); 332a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov } 333a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov }; 334a5647c78730032f1de294e8e035f7d4e9ac94731Kirill Grouchnikov } 33559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov 33659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov /** 33759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov * Clicks between two titles in a <code>ViewPager</code> title strip 33859606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov */ 33959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov public static ViewAction clickBetweenTwoTitles(final String title1, final String title2) { 34059606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov return new GeneralClickAction( 34159606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov Tap.SINGLE, 34259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov new CoordinatesProvider() { 34359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov @Override 34459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov public float[] calculateCoordinates(View view) { 34559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov PagerTitleStrip pagerStrip = (PagerTitleStrip) view; 34659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov 34759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // Get the screen position of the pager strip 34859606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov final int[] viewScreenPosition = new int[2]; 34959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov pagerStrip.getLocationOnScreen(viewScreenPosition); 35059606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov 35159606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // Get the left / right of the first title 35259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov int title1Left = 0, title1Right = 0, title2Left = 0, title2Right = 0; 35359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov final int childCount = pagerStrip.getChildCount(); 35459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov for (int i = 0; i < childCount; i++) { 35559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov final View child = pagerStrip.getChildAt(i); 35659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov if (child instanceof TextView) { 35759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov final TextView textViewChild = (TextView) child; 35859606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov final CharSequence childText = textViewChild.getText(); 35959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov if (title1.equals(childText)) { 36059606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov title1Left = textViewChild.getLeft(); 36159606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov title1Right = textViewChild.getRight(); 36259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } else if (title2.equals(childText)) { 36359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov title2Left = textViewChild.getLeft(); 36459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov title2Right = textViewChild.getRight(); 36559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 36659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 36759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 36859606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov 36959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov if (title1Right < title2Left) { 37059606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // Title 1 is to the left of title 2 37159606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov return new float[] { 37259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov viewScreenPosition[0] + (title1Right + title2Left) / 2, 37359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov viewScreenPosition[1] + pagerStrip.getHeight() / 2 }; 37459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } else { 37559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // The assumption here is that PagerTitleStrip prevents titles 37659606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // from overlapping, so if we get here it means that title 1 37759606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov // is to the right of title 2 37859606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov return new float[] { 37959606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov viewScreenPosition[0] + (title2Right + title1Left) / 2, 38059606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov viewScreenPosition[1] + pagerStrip.getHeight() / 2 }; 38159606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 38259606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 38359606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov }, 38459606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov Press.FINGER); 38559606ec8e4d812326448f0bf6acde5a0a167a958Kirill Grouchnikov } 3865427189579423bcb9f341534f030ce26a2a79d6dKirill Grouchnikov} 387