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