blob: 23ef7c5124a8879f989577df51702f449c472f67 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.design.widget;
import static android.support.design.testutils.TestUtilsActions.addTabs;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
import android.os.SystemClock;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import android.support.design.test.R;
import android.support.design.testutils.Cheeses;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.LargeTest;
import android.support.test.filters.Suppress;
import org.junit.Test;
@LargeTest
public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
private TabLayout mTabLayout;
@Override
protected void configureContent(@LayoutRes int layoutResId, @StringRes int titleResId)
throws Throwable {
super.configureContent(layoutResId, titleResId);
mTabLayout = (TabLayout) mAppBar.findViewById(R.id.tabs);
String[] tabTitles = new String[5];
System.arraycopy(Cheeses.sCheeseStrings, 0, tabTitles, 0, 5);
onView(withId(R.id.tabs)).perform(addTabs(tabTitles));
}
@Test
public void testScrollingToolbarAndScrollingTabs() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_scroll_tabs_scroll,
R.string.design_appbar_toolbar_scroll_tabs_scroll);
final int[] appbarOnScreenXY = new int[2];
final int[] coordinatorLayoutOnScreenXY = new int[2];
mAppBar.getLocationOnScreen(appbarOnScreenXY);
mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
final int originalAppbarTop = appbarOnScreenXY[1];
final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
final int toolbarHeight = mToolbar.getHeight();
final int tabsHeight = mTabLayout.getHeight();
final int appbarHeight = mAppBar.getHeight();
final int longSwipeAmount = 3 * appbarHeight / 2;
final int shortSwipeAmount = toolbarHeight;
// Perform a swipe-up gesture across the horizontal center of the screen, starting from
// just below the AppBarLayout
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + 20,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should not be visually "present" on the screen, with its bottom
// edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-up gesture
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
shortSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should still be off the screen. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a long swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to fully bring down
// the scrolled-away toolbar and tab layout
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
longSwipeAmount * 3 / 2);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be visually snapped below the system status bar as it
// in scrolling mode and we've swiped down. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be in its original position.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should still be in its original position.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
@Test
public void testScrollingToolbarAndPinnedTabs() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_scroll_tabs_pinned,
R.string.design_appbar_toolbar_scroll_tabs_pin);
final int[] appbarOnScreenXY = new int[2];
final int[] coordinatorLayoutOnScreenXY = new int[2];
mAppBar.getLocationOnScreen(appbarOnScreenXY);
mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
final int originalAppbarTop = appbarOnScreenXY[1];
final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
final int toolbarHeight = mToolbar.getHeight();
final int tabsHeight = mTabLayout.getHeight();
final int appbarHeight = mAppBar.getHeight();
final int longSwipeAmount = 3 * appbarHeight / 2;
final int shortSwipeAmount = toolbarHeight;
// Perform a swipe-up gesture across the horizontal center of the screen, starting from
// just below the AppBarLayout
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + 20,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the tab bar should be visually snapped below the system status bar.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-up gesture
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
shortSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the tab bar should still be visually snapped below the system status bar
// as it is in the pinned mode. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to fully bring down
// the scrolled-away toolbar and tab layout
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom - shortSwipeAmount,
3 * shortSwipeAmount / 2);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be in its original position as it
// in scrolling mode and we've swiped down. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be in its original position.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom,
longSwipeAmount);
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should still be in its original position.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
@Suppress
@FlakyTest(bugId = 30701044)
@LargeTest
@Test
public void testSnappingToolbarAndSnappingTabs() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_scroll_tabs_scroll_snap,
R.string.design_appbar_toolbar_scroll_tabs_scroll_snap);
final int[] appbarOnScreenXY = new int[2];
final int[] coordinatorLayoutOnScreenXY = new int[2];
mAppBar.getLocationOnScreen(appbarOnScreenXY);
mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
final int originalAppbarTop = appbarOnScreenXY[1];
final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
final int toolbarHeight = mToolbar.getHeight();
final int tabsHeight = mTabLayout.getHeight();
final int appbarHeight = mAppBar.getHeight();
// Since AppBarLayout doesn't expose a way to track snap animations, the three possible
// options are
// a) track how vertical offsets and invalidation is propagated through the
// view hierarchy and wait until there are no more events of that kind
// b) run a dummy Espresso action that waits until the main thread is idle
// c) sleep for a hardcoded period of time to "wait" until the snap animation is done
// In this test method we go with option b)
// Perform a swipe-up gesture across the horizontal center of the screen. The amount
// of swipe is 25% of the toolbar height and we expect the snap behavior to "move"
// the app bar back to its original position.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
toolbarHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be in its original position as it
// in snapping mode and we haven't swiped "enough". Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a slightly longer swipe-up gesture, this time by 75% of the toolbar height.
// We expect the snap behavior to move the app bar to snap the tab layout below the
// system status bar.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
3 * toolbarHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should "snap" the toolbar away and align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-up gesture, this time by 25% of the tab layout height. We expect
// snap behavior to move the app bar back to snap the tab layout below the system status
// bar.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
tabsHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should "snap" back to align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
// snap behavior to move the app bar fully away from the screen.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
3 * tabsHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should not be visually "present" on the screen, with its bottom
// edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture by 25% of the tab layout height. We expect
// snap behavior to move the app bar back fully away from the screen.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
tabsHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should still not be visually "present" on the screen, with
// its bottom edge aligned with the system status bar. Allow for off-by-a-pixel margin
// of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
// snap behavior to move the app bar to snap the tab layout below the system status
// bar.
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
3 * tabsHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should "snap" the toolbar away and align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture by 25% of the toolbar height. We expect
// snap behavior to align the tab layout below the system status bar
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
toolbarHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should still align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the toolbar height. We expect
// snap behavior to move the app bar back to its original place (fully visible).
performVerticalSwipeDownGesture(
R.id.coordinator_layout,
centerX,
originalAppbarBottom + toolbarHeight,
3 * tabsHeight / 4);
// Wait for the snap animation to be done
waitForSnapAnimationToFinish();
mAppBar.getLocationOnScreen(appbarOnScreenXY);
// At this point the app bar should be in its original position.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
private void waitForSnapAnimationToFinish() {
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior)
((CoordinatorLayout.LayoutParams) mAppBar.getLayoutParams()).getBehavior();
while (behavior.isOffsetAnimatorRunning()) {
SystemClock.sleep(16);
}
}
}