BaseKeyEventsTestCase.java revision 522ead667d2efbd7675b89b11aec769ec37baa20
1/* 2 * Copyright (C) 2015 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.v7.app; 18 19import static android.support.test.espresso.Espresso.onView; 20import static android.support.test.espresso.action.ViewActions.click; 21import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; 22import static android.support.test.espresso.assertion.ViewAssertions.matches; 23import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 24import static android.support.test.espresso.matcher.ViewMatchers.withClassName; 25import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription; 26import static android.support.test.espresso.matcher.ViewMatchers.withId; 27 28import static org.junit.Assert.assertEquals; 29import static org.junit.Assert.assertFalse; 30import static org.junit.Assert.assertNotNull; 31import static org.junit.Assert.assertTrue; 32 33import android.support.test.filters.FlakyTest; 34import android.support.test.filters.LargeTest; 35import android.support.test.filters.SmallTest; 36import android.support.test.filters.Suppress; 37import android.support.v4.view.MenuItemCompat; 38import android.support.v7.appcompat.test.R; 39import android.support.v7.testutils.BaseTestActivity; 40import android.support.v7.view.ActionMode; 41import android.view.KeyEvent; 42import android.view.Menu; 43import android.view.MenuItem; 44 45import org.hamcrest.Matchers; 46import org.junit.Test; 47 48import java.util.concurrent.atomic.AtomicBoolean; 49 50public abstract class BaseKeyEventsTestCase<A extends BaseTestActivity> 51 extends BaseInstrumentationTestCase<A> { 52 53 protected BaseKeyEventsTestCase(Class<A> activityClass) { 54 super(activityClass); 55 } 56 57 @Test 58 @SmallTest 59 public void testBackDismissesActionMode() { 60 final AtomicBoolean destroyed = new AtomicBoolean(); 61 62 getActivity().runOnUiThread(new Runnable() { 63 @Override 64 public void run() { 65 getActivity().startSupportActionMode(new ActionMode.Callback() { 66 @Override 67 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 68 mode.getMenuInflater().inflate(R.menu.sample_actions, menu); 69 return true; 70 } 71 72 @Override 73 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 74 return false; 75 } 76 77 @Override 78 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 79 return false; 80 } 81 82 @Override 83 public void onDestroyActionMode(ActionMode mode) { 84 destroyed.set(true); 85 } 86 }); 87 } 88 }); 89 90 getInstrumentation().waitForIdleSync(); 91 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); 92 getInstrumentation().waitForIdleSync(); 93 94 assertFalse("Activity was not finished", getActivity().isFinishing()); 95 assertTrue("ActionMode was destroyed", destroyed.get()); 96 } 97 98 @Suppress 99 @FlakyTest(bugId = 34956766) 100 @Test 101 @LargeTest 102 public void testBackCollapsesActionView() throws InterruptedException { 103 // Click on the Search menu item 104 onView(withId(R.id.action_search)).perform(click()); 105 // Check that the action view is displayed (expanded) 106 onView(withClassName(Matchers.is(CustomCollapsibleView.class.getName()))) 107 .check(matches(isDisplayed())); 108 109 // Let things settle 110 getInstrumentation().waitForIdleSync(); 111 // Now send a back event to collapse the custom action view 112 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); 113 getInstrumentation().waitForIdleSync(); 114 115 // Check that the Activity is still running 116 assertFalse(getActivity().isFinishing()); 117 assertFalse(getActivity().isDestroyed()); 118 // ... and that our action view is not attached 119 onView(withClassName(Matchers.is(CustomCollapsibleView.class.getName()))) 120 .check(doesNotExist()); 121 } 122 123 @Test 124 @SmallTest 125 public void testMenuPressInvokesPanelCallbacks() throws InterruptedException { 126 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU); 127 getInstrumentation().waitForIdleSync(); 128 assertTrue("onMenuOpened called", getActivity().wasOnMenuOpenedCalled()); 129 130 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU); 131 getInstrumentation().waitForIdleSync(); 132 assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled()); 133 } 134 135 @Test 136 @SmallTest 137 public void testBackPressWithMenuInvokesOnPanelClosed() throws InterruptedException { 138 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU); 139 getInstrumentation().waitForIdleSync(); 140 141 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); 142 getInstrumentation().waitForIdleSync(); 143 assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled()); 144 } 145 146 @Test 147 @SmallTest 148 public void testBackPressWithEmptyMenuFinishesActivity() throws InterruptedException { 149 repopulateWithEmptyMenu(); 150 151 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU); 152 getInstrumentation().waitForIdleSync(); 153 154 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); 155 assertTrue(getActivity().isFinishing()); 156 } 157 158 @Test 159 @SmallTest 160 public void testDelKeyEventReachesActivity() { 161 // First send the event 162 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DEL); 163 getInstrumentation().waitForIdleSync(); 164 165 KeyEvent downEvent = getActivity().getInvokedKeyDownEvent(); 166 assertNotNull("onKeyDown called", downEvent); 167 assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_DEL, downEvent.getKeyCode()); 168 169 KeyEvent upEvent = getActivity().getInvokedKeyUpEvent(); 170 assertNotNull("onKeyUp called", upEvent); 171 assertEquals("onKeyUp event matches", KeyEvent.KEYCODE_DEL, upEvent.getKeyCode()); 172 } 173 174 @Test 175 @SmallTest 176 public void testMenuKeyEventReachesActivity() throws InterruptedException { 177 getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU); 178 getInstrumentation().waitForIdleSync(); 179 180 KeyEvent downEvent = getActivity().getInvokedKeyDownEvent(); 181 assertNotNull("onKeyDown called", downEvent); 182 assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, downEvent.getKeyCode()); 183 184 KeyEvent upEvent = getActivity().getInvokedKeyUpEvent(); 185 assertNotNull("onKeyUp called", upEvent); 186 assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, upEvent.getKeyCode()); 187 } 188 189 @Test 190 @SmallTest 191 public void testActionMenuContent() throws Throwable { 192 onView(withId(R.id.action_search)) 193 .check(matches(isDisplayed())) 194 .check(matches(withContentDescription(R.string.search_menu_description))); 195 196 onView(withId(R.id.action_alpha_shortcut)) 197 .check(matches(isDisplayed())) 198 .check(matches(withContentDescription(R.string.alpha_menu_title))); 199 200 Menu menu = getActivity().getMenu(); 201 final MenuItem alphaItem = menu.findItem(R.id.action_alpha_shortcut); 202 assertNotNull(alphaItem); 203 204 mActivityTestRule.runOnUiThread(new Runnable() { 205 @Override 206 public void run() { 207 MenuItemCompat.setContentDescription(alphaItem, 208 getActivity().getString(R.string.alpha_menu_description)); 209 MenuItemCompat.setTooltipText(alphaItem, 210 getActivity().getString(R.string.alpha_menu_tooltip)); 211 } 212 }); 213 214 onView(withId(R.id.action_alpha_shortcut)) 215 .check(matches(isDisplayed())) 216 .check(matches(withContentDescription(R.string.alpha_menu_description))); 217 } 218 219 private void repopulateWithEmptyMenu() throws InterruptedException { 220 int count = 0; 221 getActivity().setShouldPopulateOptionsMenu(false); 222 while (count++ < 10) { 223 Menu menu = getActivity().getMenu(); 224 if (menu == null || menu.size() != 0) { 225 Thread.sleep(100); 226 } else { 227 return; 228 } 229 } 230 } 231} 232