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