OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.appmenu; | 5 package org.chromium.chrome.browser.appmenu; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.content.pm.ActivityInfo; | 8 import android.content.pm.ActivityInfo; |
9 import android.support.test.InstrumentationRegistry; | |
10 import android.support.test.filters.SmallTest; | 9 import android.support.test.filters.SmallTest; |
11 import android.view.KeyEvent; | 10 import android.view.KeyEvent; |
12 import android.view.MenuItem; | 11 import android.view.MenuItem; |
13 import android.view.View; | 12 import android.view.View; |
14 import android.widget.ListPopupWindow; | 13 import android.widget.ListPopupWindow; |
15 import android.widget.ListView; | 14 import android.widget.ListView; |
16 | 15 |
17 import org.junit.Assert; | |
18 import org.junit.Before; | |
19 import org.junit.Rule; | |
20 import org.junit.Test; | |
21 import org.junit.runner.RunWith; | |
22 | |
23 import org.chromium.base.ThreadUtils; | 16 import org.chromium.base.ThreadUtils; |
24 import org.chromium.base.annotations.SuppressFBWarnings; | 17 import org.chromium.base.annotations.SuppressFBWarnings; |
25 import org.chromium.base.test.util.CommandLineFlags; | |
26 import org.chromium.base.test.util.DisabledTest; | 18 import org.chromium.base.test.util.DisabledTest; |
27 import org.chromium.base.test.util.Feature; | 19 import org.chromium.base.test.util.Feature; |
28 import org.chromium.base.test.util.RetryOnFailure; | 20 import org.chromium.base.test.util.RetryOnFailure; |
29 import org.chromium.base.test.util.UrlUtils; | 21 import org.chromium.base.test.util.UrlUtils; |
30 import org.chromium.chrome.browser.ChromeActivity; | 22 import org.chromium.chrome.browser.ChromeActivity; |
31 import org.chromium.chrome.browser.ChromeSwitches; | |
32 import org.chromium.chrome.browser.ChromeTabbedActivity; | 23 import org.chromium.chrome.browser.ChromeTabbedActivity; |
33 import org.chromium.chrome.test.ChromeActivityTestRule; | 24 import org.chromium.chrome.test.ChromeActivityTestCaseBase; |
34 import org.chromium.chrome.test.ChromeJUnit4ClassRunner; | |
35 import org.chromium.chrome.test.util.ChromeTabUtils; | 25 import org.chromium.chrome.test.util.ChromeTabUtils; |
36 import org.chromium.content.browser.test.util.Criteria; | 26 import org.chromium.content.browser.test.util.Criteria; |
37 import org.chromium.content.browser.test.util.CriteriaHelper; | 27 import org.chromium.content.browser.test.util.CriteriaHelper; |
38 | 28 |
39 import java.util.concurrent.Callable; | 29 import java.util.concurrent.Callable; |
40 | 30 |
41 /** | 31 /** |
42 * Tests AppMenu popup | 32 * Tests AppMenu popup |
43 */ | 33 */ |
44 @RunWith(ChromeJUnit4ClassRunner.class) | |
45 @RetryOnFailure | 34 @RetryOnFailure |
46 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, | 35 public class AppMenuTest extends ChromeActivityTestCaseBase<ChromeActivity> { |
47 ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG}) | |
48 public class AppMenuTest { | |
49 @Rule | |
50 public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = | |
51 new ChromeActivityTestRule<>(ChromeActivity.class); | |
52 | |
53 private static final String TEST_URL = UrlUtils.encodeHtmlDataUri("<html>foo
</html>"); | 36 private static final String TEST_URL = UrlUtils.encodeHtmlDataUri("<html>foo
</html>"); |
54 | 37 |
55 private AppMenu mAppMenu; | 38 private AppMenu mAppMenu; |
56 private AppMenuHandler mAppMenuHandler; | 39 private AppMenuHandler mAppMenuHandler; |
57 | 40 |
58 /** | 41 /** |
59 * AppMenuHandler that will be used to intercept item selections for testing
. | 42 * AppMenuHandler that will be used to intercept item selections for testing
. |
60 */ | 43 */ |
61 @SuppressFBWarnings("URF_UNREAD_FIELD") | 44 @SuppressFBWarnings("URF_UNREAD_FIELD") |
62 public static class AppMenuHandlerForTest extends AppMenuHandler { | 45 public static class AppMenuHandlerForTest extends AppMenuHandler { |
63 int mLastSelectedItemId = -1; | 46 int mLastSelectedItemId = -1; |
64 | 47 |
65 /** | 48 /** |
66 * AppMenuHandler for intercepting options item selections. | 49 * AppMenuHandler for intercepting options item selections. |
67 */ | 50 */ |
68 public AppMenuHandlerForTest(Activity activity, AppMenuPropertiesDelegat
e delegate, | 51 public AppMenuHandlerForTest(Activity activity, AppMenuPropertiesDelegat
e delegate, |
69 int menuResourceId) { | 52 int menuResourceId) { |
70 super(activity, delegate, menuResourceId); | 53 super(activity, delegate, menuResourceId); |
71 } | 54 } |
72 | 55 |
73 @Override | 56 @Override |
74 void onOptionsItemSelected(MenuItem item) { | 57 void onOptionsItemSelected(MenuItem item) { |
75 mLastSelectedItemId = item.getItemId(); | 58 mLastSelectedItemId = item.getItemId(); |
76 } | 59 } |
77 } | 60 } |
78 | 61 |
79 @Before | 62 public AppMenuTest() { |
80 public void setUp() throws Exception { | 63 super(ChromeActivity.class); |
| 64 } |
| 65 |
| 66 @Override |
| 67 public void startMainActivity() throws InterruptedException { |
| 68 startMainActivityWithURL(TEST_URL); |
| 69 } |
| 70 |
| 71 @Override |
| 72 protected void setUp() throws Exception { |
81 // We need list selection; ensure we are not in touch mode. | 73 // We need list selection; ensure we are not in touch mode. |
82 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); | 74 getInstrumentation().setInTouchMode(false); |
83 | 75 |
84 ChromeActivity.setAppMenuHandlerFactoryForTesting( | 76 ChromeActivity.setAppMenuHandlerFactoryForTesting( |
85 new ChromeActivity.AppMenuHandlerFactory() { | 77 new ChromeActivity.AppMenuHandlerFactory() { |
86 @Override | 78 @Override |
87 public AppMenuHandler get(Activity activity, AppMenuProperti
esDelegate delegate, | 79 public AppMenuHandler get(Activity activity, AppMenuProperti
esDelegate delegate, |
88 int menuResourceId) { | 80 int menuResourceId) { |
89 mAppMenuHandler = | 81 mAppMenuHandler = |
90 new AppMenuHandlerForTest(activity, delegate, me
nuResourceId); | 82 new AppMenuHandlerForTest(activity, delegate, me
nuResourceId); |
91 return mAppMenuHandler; | 83 return mAppMenuHandler; |
92 } | 84 } |
93 }); | 85 }); |
94 | 86 |
95 mActivityTestRule.startMainActivityWithURL(TEST_URL); | 87 super.setUp(); |
96 | 88 |
97 showAppMenuAndAssertMenuShown(); | 89 showAppMenuAndAssertMenuShown(); |
98 mAppMenu = mActivityTestRule.getActivity().getAppMenuHandler().getAppMen
u(); | 90 mAppMenu = getActivity().getAppMenuHandler().getAppMenu(); |
99 ThreadUtils.runOnUiThread(new Runnable() { | 91 ThreadUtils.runOnUiThread(new Runnable() { |
100 @Override | 92 @Override |
101 public void run() { | 93 public void run() { |
102 mAppMenu.getPopup().getListView().setSelection(0); | 94 mAppMenu.getPopup().getListView().setSelection(0); |
103 } | 95 } |
104 }); | 96 }); |
105 CriteriaHelper.pollInstrumentationThread(Criteria.equals(0, new Callable
<Integer>() { | 97 CriteriaHelper.pollInstrumentationThread(Criteria.equals(0, new Callable
<Integer>() { |
106 @Override | 98 @Override |
107 public Integer call() { | 99 public Integer call() { |
108 return getCurrentFocusedRow(); | 100 return getCurrentFocusedRow(); |
109 } | 101 } |
110 })); | 102 })); |
111 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); | 103 getInstrumentation().waitForIdleSync(); |
112 } | 104 } |
113 | 105 |
114 /** | 106 /** |
115 * Verify opening a new tab from the menu. | 107 * Verify opening a new tab from the menu. |
116 */ | 108 */ |
117 @Test | |
118 @SmallTest | 109 @SmallTest |
119 @Feature({"Browser", "Main"}) | 110 @Feature({"Browser", "Main"}) |
120 public void testMenuNewTab() throws InterruptedException { | 111 public void testMenuNewTab() throws InterruptedException { |
121 final int tabCountBefore = mActivityTestRule.getActivity().getCurrentTab
Model().getCount(); | 112 final int tabCountBefore = getActivity().getCurrentTabModel().getCount()
; |
122 ChromeTabUtils.newTabFromMenu(InstrumentationRegistry.getInstrumentation
(), | 113 ChromeTabUtils.newTabFromMenu(getInstrumentation(), (ChromeTabbedActivit
y) getActivity()); |
123 (ChromeTabbedActivity) mActivityTestRule.getActivity()); | 114 final int tabCountAfter = getActivity().getCurrentTabModel().getCount(); |
124 final int tabCountAfter = mActivityTestRule.getActivity().getCurrentTabM
odel().getCount(); | 115 assertTrue("Expected: " + (tabCountBefore + 1) + " Got: " + tabCountAfte
r, |
125 Assert.assertTrue("Expected: " + (tabCountBefore + 1) + " Got: " + tabCo
untAfter, | |
126 tabCountBefore + 1 == tabCountAfter); | 116 tabCountBefore + 1 == tabCountAfter); |
127 } | 117 } |
128 | 118 |
129 /** | 119 /** |
130 * Test bounds when accessing the menu through the keyboard. | 120 * Test bounds when accessing the menu through the keyboard. |
131 * Make sure that the menu stays open when trying to move past the first and
last items. | 121 * Make sure that the menu stays open when trying to move past the first and
last items. |
132 */ | 122 */ |
133 @Test | |
134 @SmallTest | 123 @SmallTest |
135 @Feature({"Browser", "Main"}) | 124 @Feature({"Browser", "Main"}) |
136 public void testKeyboardMenuBoundaries() { | 125 public void testKeyboardMenuBoundaries() { |
137 moveToBoundary(false, true); | 126 moveToBoundary(false, true); |
138 Assert.assertEquals(getCount() - 1, getCurrentFocusedRow()); | 127 assertEquals(getCount() - 1, getCurrentFocusedRow()); |
139 moveToBoundary(true, true); | 128 moveToBoundary(true, true); |
140 Assert.assertEquals(0, getCurrentFocusedRow()); | 129 assertEquals(0, getCurrentFocusedRow()); |
141 moveToBoundary(false, true); | 130 moveToBoundary(false, true); |
142 Assert.assertEquals(getCount() - 1, getCurrentFocusedRow()); | 131 assertEquals(getCount() - 1, getCurrentFocusedRow()); |
143 } | 132 } |
144 | 133 |
145 /** | 134 /** |
146 * Test that typing ENTER immediately opening the menu works. | 135 * Test that typing ENTER immediately opening the menu works. |
147 */ | 136 */ |
148 @Test | |
149 @SmallTest | 137 @SmallTest |
150 @Feature({"Browser", "Main"}) | 138 @Feature({"Browser", "Main"}) |
151 public void testKeyboardMenuEnterOnOpen() { | 139 public void testKeyboardMenuEnterOnOpen() { |
152 hitEnterAndAssertAppMenuDismissed(); | 140 hitEnterAndAssertAppMenuDismissed(); |
153 } | 141 } |
154 | 142 |
155 /** | 143 /** |
156 * Test that hitting ENTER past the top item doesn't crash Chrome. | 144 * Test that hitting ENTER past the top item doesn't crash Chrome. |
157 */ | 145 */ |
158 @Test | |
159 @SmallTest | 146 @SmallTest |
160 @Feature({"Browser", "Main"}) | 147 @Feature({"Browser", "Main"}) |
161 public void testKeyboardEnterAfterMovePastTopItem() { | 148 public void testKeyboardEnterAfterMovePastTopItem() { |
162 moveToBoundary(true, true); | 149 moveToBoundary(true, true); |
163 Assert.assertEquals(0, getCurrentFocusedRow()); | 150 assertEquals(0, getCurrentFocusedRow()); |
164 hitEnterAndAssertAppMenuDismissed(); | 151 hitEnterAndAssertAppMenuDismissed(); |
165 } | 152 } |
166 | 153 |
167 /** | 154 /** |
168 * Test that hitting ENTER past the bottom item doesn't crash Chrome. | 155 * Test that hitting ENTER past the bottom item doesn't crash Chrome. |
169 * Catches regressions for http://crbug.com/181067 | 156 * Catches regressions for http://crbug.com/181067 |
170 */ | 157 */ |
171 @Test | |
172 @SmallTest | 158 @SmallTest |
173 @Feature({"Browser", "Main"}) | 159 @Feature({"Browser", "Main"}) |
174 public void testKeyboardEnterAfterMovePastBottomItem() { | 160 public void testKeyboardEnterAfterMovePastBottomItem() { |
175 moveToBoundary(false, true); | 161 moveToBoundary(false, true); |
176 Assert.assertEquals(getCount() - 1, getCurrentFocusedRow()); | 162 assertEquals(getCount() - 1, getCurrentFocusedRow()); |
177 hitEnterAndAssertAppMenuDismissed(); | 163 hitEnterAndAssertAppMenuDismissed(); |
178 } | 164 } |
179 | 165 |
180 /** | 166 /** |
181 * Test that hitting ENTER on the top item actually triggers the top item. | 167 * Test that hitting ENTER on the top item actually triggers the top item. |
182 * Catches regressions for https://crbug.com/191239 for shrunken menus. | 168 * Catches regressions for https://crbug.com/191239 for shrunken menus. |
183 */ | 169 */ |
184 @Test | |
185 @SmallTest | 170 @SmallTest |
186 @Feature({"Browser", "Main"}) | 171 @Feature({"Browser", "Main"}) |
187 public void testKeyboardMenuEnterOnTopItemLandscape() { | 172 public void testKeyboardMenuEnterOnTopItemLandscape() { |
188 mActivityTestRule.getActivity().setRequestedOrientation( | 173 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA
NDSCAPE); |
189 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | |
190 showAppMenuAndAssertMenuShown(); | 174 showAppMenuAndAssertMenuShown(); |
191 moveToBoundary(true, false); | 175 moveToBoundary(true, false); |
192 Assert.assertEquals(0, getCurrentFocusedRow()); | 176 assertEquals(0, getCurrentFocusedRow()); |
193 hitEnterAndAssertAppMenuDismissed(); | 177 hitEnterAndAssertAppMenuDismissed(); |
194 } | 178 } |
195 | 179 |
196 /** | 180 /** |
197 * Test that hitting ENTER on the top item doesn't crash Chrome. | 181 * Test that hitting ENTER on the top item doesn't crash Chrome. |
198 */ | 182 */ |
199 @Test | |
200 @SmallTest | 183 @SmallTest |
201 @Feature({"Browser", "Main"}) | 184 @Feature({"Browser", "Main"}) |
202 public void testKeyboardMenuEnterOnTopItemPortrait() { | 185 public void testKeyboardMenuEnterOnTopItemPortrait() { |
203 mActivityTestRule.getActivity().setRequestedOrientation( | 186 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO
RTRAIT); |
204 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); | |
205 showAppMenuAndAssertMenuShown(); | 187 showAppMenuAndAssertMenuShown(); |
206 moveToBoundary(true, false); | 188 moveToBoundary(true, false); |
207 Assert.assertEquals(0, getCurrentFocusedRow()); | 189 assertEquals(0, getCurrentFocusedRow()); |
208 hitEnterAndAssertAppMenuDismissed(); | 190 hitEnterAndAssertAppMenuDismissed(); |
209 } | 191 } |
210 | 192 |
211 /** | 193 /** |
212 * Test that changing orientation hides the menu. | 194 * Test that changing orientation hides the menu. |
213 */ | 195 */ |
214 /* | 196 /* |
215 @SmallTest | 197 @SmallTest |
216 @Feature({"Browser", "Main"}) | 198 @Feature({"Browser", "Main"}) |
217 */ | 199 */ |
218 @Test | |
219 @DisabledTest(message = "crbug.com/458193") | 200 @DisabledTest(message = "crbug.com/458193") |
220 public void testChangingOrientationHidesMenu() { | 201 public void testChangingOrientationHidesMenu() { |
221 mActivityTestRule.getActivity().setRequestedOrientation( | 202 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA
NDSCAPE); |
222 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | |
223 showAppMenuAndAssertMenuShown(); | 203 showAppMenuAndAssertMenuShown(); |
224 mActivityTestRule.getActivity().setRequestedOrientation( | 204 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO
RTRAIT); |
225 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); | |
226 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not d
ismiss") { | 205 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not d
ismiss") { |
227 @Override | 206 @Override |
228 public boolean isSatisfied() { | 207 public boolean isSatisfied() { |
229 return !mAppMenuHandler.isAppMenuShowing(); | 208 return !mAppMenuHandler.isAppMenuShowing(); |
230 } | 209 } |
231 }); | 210 }); |
232 } | 211 } |
233 | 212 |
234 private void showAppMenuAndAssertMenuShown() { | 213 private void showAppMenuAndAssertMenuShown() { |
235 ThreadUtils.runOnUiThread(new Runnable() { | 214 ThreadUtils.runOnUiThread(new Runnable() { |
236 @Override | 215 @Override |
237 public void run() { | 216 public void run() { |
238 mAppMenuHandler.showAppMenu(null, false); | 217 mAppMenuHandler.showAppMenu(null, false); |
239 } | 218 } |
240 }); | 219 }); |
241 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not s
how") { | 220 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not s
how") { |
242 @Override | 221 @Override |
243 public boolean isSatisfied() { | 222 public boolean isSatisfied() { |
244 return mAppMenuHandler.isAppMenuShowing(); | 223 return mAppMenuHandler.isAppMenuShowing(); |
245 } | 224 } |
246 }); | 225 }); |
247 } | 226 } |
248 | 227 |
249 private void hitEnterAndAssertAppMenuDismissed() { | 228 private void hitEnterAndAssertAppMenuDismissed() { |
250 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); | 229 getInstrumentation().waitForIdleSync(); |
251 pressKey(KeyEvent.KEYCODE_ENTER); | 230 pressKey(KeyEvent.KEYCODE_ENTER); |
252 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not d
ismiss") { | 231 CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not d
ismiss") { |
253 @Override | 232 @Override |
254 public boolean isSatisfied() { | 233 public boolean isSatisfied() { |
255 return !mAppMenuHandler.isAppMenuShowing(); | 234 return !mAppMenuHandler.isAppMenuShowing(); |
256 } | 235 } |
257 }); | 236 }); |
258 } | 237 } |
259 | 238 |
260 private void moveToBoundary(boolean towardsTop, boolean movePast) { | 239 private void moveToBoundary(boolean towardsTop, boolean movePast) { |
(...skipping 17 matching lines...) Expand all Loading... |
278 pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DP
AD_DOWN); | 257 pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DP
AD_DOWN); |
279 CriteriaHelper.pollInstrumentationThread(Criteria.equals(end, new Ca
llable<Integer>() { | 258 CriteriaHelper.pollInstrumentationThread(Criteria.equals(end, new Ca
llable<Integer>() { |
280 @Override | 259 @Override |
281 public Integer call() { | 260 public Integer call() { |
282 return getCurrentFocusedRow(); | 261 return getCurrentFocusedRow(); |
283 } | 262 } |
284 })); | 263 })); |
285 } | 264 } |
286 | 265 |
287 // The menu should stay open. | 266 // The menu should stay open. |
288 Assert.assertTrue(mAppMenu.isShowing()); | 267 assertTrue(mAppMenu.isShowing()); |
289 } | 268 } |
290 | 269 |
291 private void pressKey(final int keycode) { | 270 private void pressKey(final int keycode) { |
292 final View view = mAppMenu.getPopup().getListView(); | 271 final View view = mAppMenu.getPopup().getListView(); |
293 ThreadUtils.runOnUiThread(new Runnable() { | 272 ThreadUtils.runOnUiThread(new Runnable() { |
294 @Override | 273 @Override |
295 public void run() { | 274 public void run() { |
296 view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode
)); | 275 view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode
)); |
297 view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keycode))
; | 276 view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keycode))
; |
298 } | 277 } |
299 }); | 278 }); |
300 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); | 279 getInstrumentation().waitForIdleSync(); |
301 } | 280 } |
302 | 281 |
303 private int getCurrentFocusedRow() { | 282 private int getCurrentFocusedRow() { |
304 ListPopupWindow popup = mAppMenu.getPopup(); | 283 ListPopupWindow popup = mAppMenu.getPopup(); |
305 if (popup == null || popup.getListView() == null) return ListView.INVALI
D_POSITION; | 284 if (popup == null || popup.getListView() == null) return ListView.INVALI
D_POSITION; |
306 ListView listView = popup.getListView(); | 285 ListView listView = popup.getListView(); |
307 return listView.getSelectedItemPosition(); | 286 return listView.getSelectedItemPosition(); |
308 } | 287 } |
309 | 288 |
310 private int getCount() { | 289 private int getCount() { |
311 ListPopupWindow popup = mAppMenu.getPopup(); | 290 ListPopupWindow popup = mAppMenu.getPopup(); |
312 if (popup == null || popup.getListView() == null) return 0; | 291 if (popup == null || popup.getListView() == null) return 0; |
313 return popup.getListView().getCount(); | 292 return popup.getListView().getCount(); |
314 } | 293 } |
315 } | 294 } |
OLD | NEW |