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