BottomSheetBehaviorTest.java revision b1eb1357ec33343b7271a6d3876ac4af84e15510
148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki/*
248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * Copyright (C) 2016 The Android Open Source Project
348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki *
448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * you may not use this file except in compliance with the License.
648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * You may obtain a copy of the License at
748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki *
848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki *
1048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * Unless required by applicable law or agreed to in writing, software
1148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
1248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * See the License for the specific language governing permissions and
1448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki * limitations under the License.
1548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki */
1648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
1748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakipackage android.support.design.widget;
1848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
19dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull;
2048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.design.test.R;
21ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikovimport android.support.test.InstrumentationRegistry;
2248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.Espresso;
2348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.IdlingResource;
24e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Arakiimport android.support.test.espresso.action.CoordinatesProvider;
2548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.action.GeneralLocation;
2648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.action.GeneralSwipeAction;
2748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.action.Press;
2848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.action.Swipe;
2948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.action.ViewActions;
3048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.assertion.ViewAssertions;
3148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.support.test.espresso.matcher.ViewMatchers;
32b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Arakiimport android.support.v4.widget.NestedScrollView;
3348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.test.suitebuilder.annotation.MediumTest;
3448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.test.suitebuilder.annotation.SmallTest;
3548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.view.View;
3648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport android.view.ViewGroup;
37b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Arakiimport android.widget.TextView;
38b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki
39ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikovimport org.hamcrest.Matcher;
40ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikovimport org.junit.Test;
4148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
4248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport static org.hamcrest.CoreMatchers.is;
4348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport static org.hamcrest.CoreMatchers.not;
4448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakiimport static org.hamcrest.MatcherAssert.assertThat;
4548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
4648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Arakipublic class BottomSheetBehaviorTest extends
4748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        BaseInstrumentationTestCase<BottomSheetBehaviorActivity> {
4848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
4948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public static class Callback extends BottomSheetBehavior.BottomSheetCallback
5048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            implements IdlingResource {
5148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
5248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        private boolean mIsIdle;
5348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
5448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        private IdlingResource.ResourceCallback mResourceCallback;
5548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
5648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        public Callback(BottomSheetBehavior behavior) {
5748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            behavior.setBottomSheetCallback(this);
5848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            int state = behavior.getState();
5948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            mIsIdle = isIdleState(state);
6048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
6148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
6248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        @Override
63dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public void onStateChanged(@NonNull View bottomSheet,
64dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                @BottomSheetBehavior.State int newState) {
6548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            boolean wasIdle = mIsIdle;
6648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            mIsIdle = isIdleState(newState);
6748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            if (!wasIdle && mIsIdle && mResourceCallback != null) {
6848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                mResourceCallback.onTransitionToIdle();
6948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            }
7048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
7148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
7248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        @Override
73dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
7448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
7548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
7648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        @Override
7748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        public String getName() {
7848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            return Callback.class.getSimpleName();
7948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
8048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
8148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        @Override
8248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        public boolean isIdleNow() {
8348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            return mIsIdle;
8448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
8548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
8648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        @Override
8748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        public void registerIdleTransitionCallback(IdlingResource.ResourceCallback callback) {
8848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            mResourceCallback = callback;
8948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
9048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
9148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        private boolean isIdleState(int state) {
9248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            return state != BottomSheetBehavior.STATE_DRAGGING &&
9348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                    state != BottomSheetBehavior.STATE_SETTLING;
9448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
9548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
9648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
9748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
9848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private Callback mCallback;
9948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
10048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public BottomSheetBehaviorTest() {
10148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        super(BottomSheetBehaviorActivity.class);
10248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
10348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
10448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
10548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @SmallTest
10648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testInitialSetup() {
10748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        BottomSheetBehavior behavior = getBehavior();
10848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
10948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        CoordinatorLayout coordinatorLayout = getCoordinatorLayout();
11048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        ViewGroup bottomSheet = getBottomSheet();
11148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        assertThat(bottomSheet.getTop(),
11248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                is(coordinatorLayout.getHeight() - behavior.getPeekHeight()));
11348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
11448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
11548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
11648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @MediumTest
11748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testSetStateExpandedToCollapsed() {
11848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
11948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
12048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
12148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
12248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
12348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @MediumTest
12448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testSetStateHiddenToCollapsed() {
12548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        checkSetState(BottomSheetBehavior.STATE_HIDDEN, not(ViewMatchers.isDisplayed()));
12648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
12748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
12848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
12948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
13048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @MediumTest
13148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testSwipeDownToCollapse() {
13248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
13348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
134e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                .perform(DesignViewActions.withCustomConstraints(new GeneralSwipeAction(
1358609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                        Swipe.FAST,
1368609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                        // Manually calculate the starting coordinates to make sure that the touch
1378609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                        // actually falls onto the view on Gingerbread
1388609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                        new CoordinatesProvider() {
1398609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                            @Override
1408609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                            public float[] calculateCoordinates(View view) {
1418609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                int[] location = new int[2];
1428609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                view.getLocationInWindow(location);
1438609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                return new float[]{
1448609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                        view.getWidth() / 2,
1458609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                        location[1] + 1
1468609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                                };
1478609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                            }
1488609a20bfe8d61704facb9c18836db5b3a754105Yuichi Araki                        },
149e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                        // Manually calculate the ending coordinates to make sure that the bottom
150e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                        // sheet is collapsed, not hidden
151e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                        new CoordinatesProvider() {
152e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            @Override
153e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            public float[] calculateCoordinates(View view) {
154e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                BottomSheetBehavior behavior = getBehavior();
155e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                return new float[]{
156e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                        // x: center of the bottom sheet
157e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                        view.getWidth() / 2,
158e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                        // y: just above the peek height
159e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                        view.getHeight() - behavior.getPeekHeight()};
160e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            }
161e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                        }, Press.FINGER), ViewMatchers.isDisplayingAtLeast(5)));
16248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        // Avoid a deadlock (b/26160710)
16348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        registerIdlingResourceCallback();
16448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        try {
16548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
16648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
16748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
16848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        } finally {
16948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            unregisterIdlingResourceCallback();
17048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
17148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
17248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
17348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
17448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @MediumTest
17548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testSwipeDownToHide() {
17648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
17748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                .perform(DesignViewActions.withCustomConstraints(ViewActions.swipeDown(),
17848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                        ViewMatchers.isDisplayingAtLeast(5)));
17948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        // Avoid a deadlock (b/26160710)
18048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        try {
18148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
18248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                    .check(ViewAssertions.matches(not(ViewMatchers.isDisplayed())));
18348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_HIDDEN));
18448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        } finally {
18548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            unregisterIdlingResourceCallback();
18648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
18748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
18848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
18948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @Test
19048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    @MediumTest
19148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    public void testSwipeUpToExpand() {
19248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
19348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                .perform(DesignViewActions.withCustomConstraints(
19448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                        new GeneralSwipeAction(Swipe.FAST,
195e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                GeneralLocation.VISIBLE_CENTER, new CoordinatesProvider() {
196e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            @Override
197e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            public float[] calculateCoordinates(View view) {
198e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                                return new float[]{view.getWidth() / 2, 0};
199e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                            }
200e1b07825c14a3dee006a0489fd8e2c3060d9884fYuichi Araki                        }, Press.FINGER),
20148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                        ViewMatchers.isDisplayingAtLeast(5)));
20248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        // Avoid a deadlock (b/26160710)
20348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        registerIdlingResourceCallback();
20448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        try {
20548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
20648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
20748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_EXPANDED));
20848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        } finally {
20948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            unregisterIdlingResourceCallback();
21048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
21148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
21248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
21317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki    @Test
21417fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki    @MediumTest
215ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov    public void testInvisible() {
21617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        // Make the bottomsheet invisible
217ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
21817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            @Override
21917fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            public void run() {
22017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                getBottomSheet().setVisibility(View.INVISIBLE);
22117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
22217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            }
22317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        });
22417fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        // Swipe up as if to expand it
22517fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
22617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                .perform(DesignViewActions.withCustomConstraints(
22717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                        new GeneralSwipeAction(Swipe.FAST,
22817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                                GeneralLocation.VISIBLE_CENTER, new CoordinatesProvider() {
22917fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                            @Override
23017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                            public float[] calculateCoordinates(View view) {
23117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                                return new float[]{view.getWidth() / 2, 0};
23217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                            }
23317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                        }, Press.FINGER),
23417fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                        not(ViewMatchers.isDisplayed())));
23517fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        // Check that the bottom sheet stays the same collapsed state
236ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
23717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            @Override
23817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            public void run() {
23917fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
24017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            }
24117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        });
24217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki    }
24317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki
244b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki    @Test
245b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki    @MediumTest
246b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki    public void testNestedScroll() {
247b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        final ViewGroup bottomSheet = getBottomSheet();
248b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        final BottomSheetBehavior behavior = getBehavior();
249b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        final NestedScrollView scroll = new NestedScrollView(mActivityTestRule.getActivity());
250b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        // Set up nested scrolling area
251b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
252b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            @Override
253b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            public void run() {
254b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                bottomSheet.addView(scroll, new ViewGroup.LayoutParams(
255b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
256b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                TextView view = new TextView(mActivityTestRule.getActivity());
257b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                StringBuilder sb = new StringBuilder();
258b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                for (int i = 0; i < 500; ++i) {
259b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    sb.append("It is fine today. ");
260b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                }
261b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                view.setText(sb);
262b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                view.setOnClickListener(new View.OnClickListener() {
263b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    @Override
264b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    public void onClick(View v) {
265b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        // Do nothing
266b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    }
267b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                });
268b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                scroll.addView(view);
269b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
270b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                // The scroll offset is 0 at first
271b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                assertThat(scroll.getScrollY(), is(0));
272b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            }
273b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        });
274b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        // Swipe from the very bottom of the bottom sheet to the top edge of the screen so that the
275b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        // scrolling content is also scrolled
276b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        Espresso.onView(ViewMatchers.withId(R.id.coordinator))
277b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                .perform(new GeneralSwipeAction(Swipe.FAST,
278b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        new CoordinatesProvider() {
279b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            @Override
280b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            public float[] calculateCoordinates(View view) {
281b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                                return new float[]{view.getWidth() / 2, view.getHeight() - 1};
282b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            }
283b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        },
284b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        new CoordinatesProvider() {
285b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            @Override
286b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            public float[] calculateCoordinates(View view) {
287b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                                return new float[]{view.getWidth() / 2, 1};
288b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                            }
289b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                        }, Press.FINGER));
290b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        registerIdlingResourceCallback();
291b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        try {
292b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
293b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
294b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
295b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                @Override
296b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                public void run() {
297b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_EXPANDED));
298b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    // This confirms that the nested scrolling area was scrolled continuously after
299b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    // the bottom sheet is expanded.
300b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    assertThat(scroll.getScrollY(), is(not(0)));
301b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                }
302b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            });
303b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        } finally {
304b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            unregisterIdlingResourceCallback();
305b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        }
306b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki    }
307b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki
308ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov    private void checkSetState(final int state, Matcher<View> matcher) {
30948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        registerIdlingResourceCallback();
31048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        try {
311ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
312ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov                @Override
313ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov                public void run() {
314ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov                    getBehavior().setState(state);
315ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov                }
316ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov            });
31748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
31848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki                    .check(ViewAssertions.matches(matcher));
31948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            assertThat(getBehavior().getState(), is(state));
32048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        } finally {
32148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            unregisterIdlingResourceCallback();
32248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
32348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
32448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
32548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private void registerIdlingResourceCallback() {
32648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        // TODO(yaraki): Move this to setUp() when b/26160710 is fixed
32748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        mCallback = new Callback(getBehavior());
32848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        Espresso.registerIdlingResources(mCallback);
32948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
33048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
33148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private void unregisterIdlingResourceCallback() {
33248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        if (mCallback != null) {
33348cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            Espresso.unregisterIdlingResources(mCallback);
33448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki            mCallback = null;
33548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki        }
33648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
33748cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
33848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private ViewGroup getBottomSheet() {
339ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov        return mActivityTestRule.getActivity().mBottomSheet;
34048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
34148cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
34248cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private BottomSheetBehavior getBehavior() {
343ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov        return mActivityTestRule.getActivity().mBehavior;
34448cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
34548cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
34648cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    private CoordinatorLayout getCoordinatorLayout() {
347ee3e8053ef6b55e31fa0be004061318ec394eb64Kirill Grouchnikov        return mActivityTestRule.getActivity().mCoordinatorLayout;
34848cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki    }
34948cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki
35048cd60a8daad661611618f52a0dce00d5b2c64b9Yuichi Araki}
351