1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.design.widget; 18 19import android.os.Build; 20import android.support.design.custom.TestFloatingBehavior; 21import android.support.design.test.R; 22import android.support.design.testutils.SnackbarUtils; 23import android.support.test.espresso.UiController; 24import android.support.test.espresso.ViewAction; 25import android.support.v7.widget.AppCompatTextView; 26import android.test.suitebuilder.annotation.MediumTest; 27import android.view.View; 28import android.view.ViewGroup; 29import org.hamcrest.Matcher; 30import org.junit.After; 31import org.junit.Test; 32 33import static android.support.design.widget.DesignViewActions.setVisibility; 34import static android.support.test.espresso.Espresso.onView; 35import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; 36import static android.support.test.espresso.matcher.ViewMatchers.isEnabled; 37import static android.support.test.espresso.matcher.ViewMatchers.withId; 38import static org.junit.Assert.assertTrue; 39import static org.mockito.Mockito.mock; 40 41@MediumTest 42public class CoordinatorSnackbarWithFabTest extends BaseDynamicCoordinatorLayoutTest { 43 private static final String MESSAGE_TEXT = "Test Message"; 44 private static final String ACTION_TEXT = "Action"; 45 46 private Snackbar mSnackbar; 47 48 @After 49 public void teardown() { 50 // Dismiss the snackbar to get back to clean state for the next test 51 if (mSnackbar != null) { 52 SnackbarUtils.dismissSnackbarAndWaitUntilFullyDismissed(mSnackbar); 53 } 54 } 55 56 /** 57 * Returns the location of our snackbar on the screen. 58 */ 59 private static int[] getSnackbarLocationOnScreen() { 60 final int[] location = new int[2]; 61 onView(isAssignableFrom(Snackbar.SnackbarLayout.class)).perform(new ViewAction() { 62 @Override 63 public Matcher<View> getConstraints() { 64 return isEnabled(); 65 } 66 67 @Override 68 public String getDescription() { 69 return "Snackbar matcher"; 70 } 71 72 @Override 73 public void perform(UiController uiController, View view) { 74 view.getLocationOnScreen(location); 75 } 76 }); 77 return location; 78 } 79 80 /** 81 * Helper method that verifies that the passed view is above the snackbar in the activity 82 * window. 83 */ 84 private static void verifySnackbarViewStacking(View view, int extraBottomMargin) { 85 if (Build.VERSION.SDK_INT >= 11) { 86 // Get location of snackbar in window 87 final int[] snackbarOnScreenXY = getSnackbarLocationOnScreen(); 88 // Get location of passed view in window 89 final int[] viewOnScreenXY = new int[2]; 90 view.getLocationOnScreen(viewOnScreenXY); 91 92 // Compute the bottom visible edge of the view 93 int viewBottom = viewOnScreenXY[1] + view.getHeight() - extraBottomMargin; 94 int snackbarTop = snackbarOnScreenXY[1]; 95 // and verify that our view is above the snackbar 96 assertTrue(viewBottom <= snackbarTop); 97 } 98 } 99 100 @Test 101 public void testBuiltInSliding() { 102 onView(withId(R.id.coordinator_stub)).perform( 103 inflateViewStub(R.layout.design_snackbar_with_fab)); 104 105 // Create and show a snackbar 106 mSnackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE) 107 .setAction(ACTION_TEXT, mock(View.OnClickListener.class)); 108 SnackbarUtils.showSnackbarAndWaitUntilFullyShown(mSnackbar); 109 110 // Take into account bottom padding and bottom margin to account for how drop shadow is 111 // emulated on pre-Lollipop devices 112 final FloatingActionButton fab = 113 (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab); 114 verifySnackbarViewStacking(fab, fab.getPaddingBottom() 115 - ((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin); 116 } 117 118 @Test 119 public void testBuiltInSlidingFromHiddenFab() { 120 onView(withId(R.id.coordinator_stub)).perform( 121 inflateViewStub(R.layout.design_snackbar_with_fab)); 122 onView(withId(R.id.fab)).perform(setVisibility(View.GONE)); 123 124 // Create and show a snackbar 125 mSnackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE) 126 .setAction(ACTION_TEXT, mock(View.OnClickListener.class)); 127 SnackbarUtils.showSnackbarAndWaitUntilFullyShown(mSnackbar); 128 129 // Take into account bottom padding and bottom margin to account for how drop shadow is 130 // emulated on pre-Lollipop devices 131 onView(withId(R.id.fab)).perform(setVisibility(View.VISIBLE)); 132 final FloatingActionButton fab = 133 (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab); 134 verifySnackbarViewStacking(fab, fab.getPaddingBottom() 135 - ((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin); 136 } 137 138 @Test 139 public void testBehaviorBasedSlidingFromLayoutAttribute() { 140 // Use a layout in which an AppCompatTextView child has Behavior object configured via 141 // layout_behavior XML attribute 142 onView(withId(R.id.coordinator_stub)).perform( 143 inflateViewStub(R.layout.design_snackbar_behavior_layout_attr)); 144 145 // Create and show a snackbar 146 mSnackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE) 147 .setAction(ACTION_TEXT, mock(View.OnClickListener.class)); 148 SnackbarUtils.showSnackbarAndWaitUntilFullyShown(mSnackbar); 149 150 final AppCompatTextView textView = 151 (AppCompatTextView) mCoordinatorLayout.findViewById(R.id.text); 152 verifySnackbarViewStacking(textView, 0); 153 } 154 155 @Test 156 public void testBehaviorBasedSlidingFromClassAnnotation() { 157 // Use a layout in which a custom child view has Behavior object configured via 158 // annotation on the class that extends AppCompatTextView 159 onView(withId(R.id.coordinator_stub)).perform( 160 inflateViewStub(R.layout.design_snackbar_behavior_annotation)); 161 162 // Create and show a snackbar 163 mSnackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE) 164 .setAction(ACTION_TEXT, mock(View.OnClickListener.class)); 165 SnackbarUtils.showSnackbarAndWaitUntilFullyShown(mSnackbar); 166 167 final AppCompatTextView textView = 168 (AppCompatTextView) mCoordinatorLayout.findViewById(R.id.text); 169 verifySnackbarViewStacking(textView, 0); 170 } 171 172 @Test 173 public void testBehaviorBasedSlidingFromRuntimeApiCall() { 174 // Use a layout in which an AppCompatTextView child doesn't have any configured Behavior 175 onView(withId(R.id.coordinator_stub)).perform( 176 inflateViewStub(R.layout.design_snackbar_behavior_runtime)); 177 178 // and configure that Behavior at runtime by setting it on its LayoutParams 179 final AppCompatTextView textView = 180 (AppCompatTextView) mCoordinatorLayout.findViewById(R.id.text); 181 final CoordinatorLayout.LayoutParams textViewLp = 182 (CoordinatorLayout.LayoutParams) textView.getLayoutParams(); 183 textViewLp.setBehavior(new TestFloatingBehavior()); 184 185 // Create and show a snackbar 186 mSnackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE) 187 .setAction(ACTION_TEXT, mock(View.OnClickListener.class)); 188 SnackbarUtils.showSnackbarAndWaitUntilFullyShown(mSnackbar); 189 190 verifySnackbarViewStacking(textView, 0); 191 } 192} 193