Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / apps / app_window_intercept_all_keys_uitest.cc
blob6d61972d31f8e9467fe6dfd54089dd980b422d17
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
3 // found in the LICENSE file.
5 #include "base/callback.h"
6 #include "base/logging.h"
7 #include "base/macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/apps/app_browsertest_util.h"
10 #include "chrome/test/base/interactive_test_utils.h"
11 #include "extensions/browser/app_window/native_app_window.h"
12 #include "extensions/test/extension_test_message_listener.h"
13 #include "testing/gtest/include/gtest/gtest-spi.h"
15 using extensions::NativeAppWindow;
17 class AppWindowInterceptAllKeysTest
18 : public extensions::PlatformAppBrowserTest {
19 public:
20 // Send key to window but does not wait till the key is actually in the input
21 // queue (like ui_test_utils::SendKeyPressToWindowSync()) as key will not be
22 // sent to hook when keyboard is intercepted.
23 bool SimulateKeyPress(ui::KeyboardCode key,
24 bool control,
25 bool shift,
26 bool alt,
27 bool command) {
28 DVLOG(1) << "Sending: " << key << " control = " << control
29 << " shift = " << shift << " alt = " << alt
30 << " command = " << command;
31 if (!ui_controls::SendKeyPressNotifyWhenDone(
32 GetFirstAppWindow()->GetNativeWindow(), key, control, shift, alt,
33 command, null_callback_)) {
34 LOG(WARNING) << "Failed to send key to app";
35 failure_message_ = "Failed to send key to app.";
36 return false;
39 base::RunLoop().RunUntilIdle();
40 return !testing::Test::HasFatalFailure();
43 bool SimulateKeyPress(ui::KeyboardCode key) {
44 return SimulateKeyPress(key, false, false, false, false);
47 bool WaitForKeyEvent(ui::KeyboardCode code) {
48 std::string key_event = base::StringPrintf("KeyReceived: %d", code);
49 ExtensionTestMessageListener key_listener(key_event, false);
51 if (!SimulateKeyPress(code)) {
52 failure_message_ = "Failed to send key to app";
53 return false;
56 key_listener.WaitUntilSatisfied();
58 DVLOG(1) << "Application ACK-ed keypress";
59 return true;
62 bool LoadApplication(const char* app_path) {
63 DVLOG(1) << "Launching app = " << app_path;
64 LoadAndLaunchPlatformApp(app_path, "Launched");
66 DVLOG(1) << "Validating that application is in focus";
67 // We start by making sure the window is actually focused.
68 if (!ui_test_utils::ShowAndFocusNativeWindow(
69 GetFirstAppWindow()->GetNativeWindow())) {
70 failure_message_ = "App did not get focus.";
71 return false;
74 DVLOG(1) << "Launched application";
75 return true;
78 void SendTaskSwitchKeys() {
79 // Send switch sequence (currently just for windows - will have to update as
80 // more platform support is added).
81 SimulateKeyPress(ui::VKEY_TAB, false, false, true, false);
84 void ValidateCannotInterceptKeys(const char* app_path,
85 bool change_intercept,
86 bool enable_intercept) {
87 ExtensionTestMessageListener command_listener("readyForCommand", true);
88 ASSERT_TRUE(LoadApplication(app_path)) << failure_message_;
90 const char* message = "";
91 if (change_intercept) {
92 message = enable_intercept ? "enable" : "disable";
94 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
95 command_listener.Reply(message);
96 command_listener.Reset();
98 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
100 SendTaskSwitchKeys();
102 // Send key and check if it is received.
103 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
106 void ValidateInterceptKeys(bool disable_after_enabling) {
107 ExtensionTestMessageListener command_listener("readyForCommand", true);
108 ASSERT_TRUE(LoadApplication(app_with_permission_)) << failure_message_;
110 // setInterceptAllKeys() is asynchronous so wait for response and receiving
111 // a key back.
112 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
113 command_listener.Reply("enable");
114 command_listener.Reset();
116 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
118 SendTaskSwitchKeys();
120 // Send key and check if it is received.
121 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
123 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
125 if (disable_after_enabling) {
126 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
127 command_listener.Reply("disable");
128 command_listener.Reset();
129 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
133 protected:
134 std::string failure_message_;
135 base::Callback<void(void)> null_callback_;
136 const char* app_with_permission_ =
137 "window_api_intercept_all_keys/has_permission";
138 const char* app_without_permission_ =
139 "window_api_intercept_all_keys/no_permission";
142 // Currently this is implemented only for Windows.
143 // Disabled test http://crbug.com/438209
144 #if defined(OS_WIN)
145 #define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence
146 #else
147 #define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence
148 #endif
150 // Tests a window continues to keep focus even after application switch key
151 // sequence is sent when setInterceptAllKeys() is enabled.
152 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
153 MAYBE_GetKeysAfterSwitchSequence) {
154 ValidateInterceptKeys(false);
157 // Test to make sure that keys not received after disable.
158 // Disabled test http://crbug.com/438209
159 #if defined(OS_WIN)
160 #define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled
161 #else
162 #define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled
163 #endif
165 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
166 MAYBE_NoKeysAfterDisableIsCalled) {
167 ValidateInterceptKeys(true);
169 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
171 SendTaskSwitchKeys();
173 // Send key and check if it is received.
174 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
177 // Test that calling just disable has no effect in retaining keyboard intercept.
178 // Currently this is implemented only for Windows.
179 // Disabled test http://crbug.com/438209
180 #if defined(OS_WIN)
181 #define MAYBE_NoopCallingDisableInterceptAllKeys \
182 DISABLED_NoopCallingDisableInterceptAllKeys
183 #else
184 #define MAYBE_NoopCallingDisableInterceptAllKeys \
185 DISABLED_NoopCallingDisableInterceptAllKeys
186 #endif
188 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
189 MAYBE_NoopCallingDisableInterceptAllKeys) {
190 ValidateCannotInterceptKeys(app_with_permission_, true, false);
193 // Test no effect when called without permissions
194 // Currently this is implemented only for Windows.
195 #if defined(OS_WIN)
196 #define MAYBE_NoopCallingEnableWithoutPermission \
197 DISABLED_NoopCallingEnableWithoutPermission
198 #else
199 #define MAYBE_NoopCallingEnableWithoutPermission \
200 DISABLED_NoopCallingEnableWithoutPermission
201 #endif
203 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
204 MAYBE_NoopCallingEnableWithoutPermission) {
205 ValidateCannotInterceptKeys(app_without_permission_, true, true);
208 // Test that intercept is disabled by default
209 #if defined(OS_WIN)
210 // Disabled test http://crbug.com/438209
211 #define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault
212 #else
213 #define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault
214 #endif
216 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
217 MAYBE_InterceptDisabledByDefault) {
218 ValidateCannotInterceptKeys(app_with_permission_, false, false);
221 // Tests that the application cannot be loaded in stable.
222 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, CannotLoadOtherThanDev) {
223 chrome::VersionInfo::Channel version_info[] = {
224 chrome::VersionInfo::CHANNEL_BETA, chrome::VersionInfo::CHANNEL_STABLE};
225 for (unsigned int index = 0; index < arraysize(version_info); index++) {
226 extensions::ScopedCurrentChannel channel(version_info[index]);
227 const extensions::Extension* extension = nullptr;
228 EXPECT_NONFATAL_FAILURE(
229 extension = LoadExtension(test_data_dir_.AppendASCII("platform_apps")
230 .AppendASCII(app_with_permission_)),
231 "");
233 DVLOG(1) << "Finished loading extension";
235 ASSERT_TRUE(extension == nullptr) << "Application loaded in"
236 << version_info[index]
237 << " while permission does not exist";
241 // Inject different keyboard combos and make sure that the app get them all.
242 // Disabled test http://crbug.com/438209
243 #if defined(OS_WIN)
244 #define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent
245 #else
246 #define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent
247 #endif
249 namespace {
250 // Maximum lenght of the result array in KeyEventTestData structure.
251 const size_t kMaxResultLength = 10;
253 // A structure holding test data of a keyboard event.
254 // Each keyboard event may generate multiple result strings representing
255 // the result of keydown, keypress, keyup and textInput events.
256 // For keydown, keypress and keyup events, the format of the result string is:
257 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
258 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
259 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
260 // the state of corresponding modifier key.
261 struct KeyEventTestData {
262 ui::KeyboardCode key;
263 bool control;
264 bool shift;
265 bool alt;
266 bool command;
268 int result_length;
269 const char* const result[kMaxResultLength];
271 } // namespace
273 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, MAYBE_ValidateKeyEvent) {
274 // Launch the app
275 ValidateInterceptKeys(false);
277 static const KeyEventTestData kValidateKeyEvents[] = {
278 // a
279 {ui::VKEY_A,
280 false,
281 false,
282 false,
283 false,
285 {"D 65 0 false false false false",
286 "P 97 97 false false false false",
287 "U 65 0 false false false false"}},
288 // shift+a
289 {ui::VKEY_A,
290 false,
291 true,
292 false,
293 false,
295 {"D 16 0 false true false false",
296 "D 65 0 false true false false",
297 "P 65 65 false true false false",
298 "U 65 0 false true false false",
299 "U 16 0 false true false false"}},
300 // ctrl+f which has accelerator binding should also result in all keys
301 // being
302 // sent.
303 {ui::VKEY_F,
304 true,
305 false,
306 false,
307 false,
309 {"D 17 0 true false false false",
310 "D 70 0 true false false false",
311 "P 6 6 true false false false",
312 "U 70 0 true false false false",
313 "U 17 0 true false false false"}},
314 // ctrl+z
315 {ui::VKEY_Z,
316 true,
317 false,
318 false,
319 false,
321 {"D 17 0 true false false false",
322 "D 90 0 true false false false",
323 "P 26 26 true false false false",
324 "U 90 0 true false false false",
325 "U 17 0 true false false false"}},
326 // alt+f
327 {ui::VKEY_F,
328 false,
329 false,
330 true,
331 false,
333 {"D 18 0 false false true false",
334 "D 70 0 false false true false",
335 "U 70 0 false false true false",
336 "U 18 0 false false true false"}},
337 // make sure both left and right shift makes it across
338 {ui::VKEY_RSHIFT,
339 false,
340 false,
341 false,
342 false,
344 {"D 16 0 false true false false", "U 16 0 false true false false"}},
347 DVLOG(1) << "Starting keyboard input test";
349 for (unsigned int index = 0; index < arraysize(kValidateKeyEvents); index++) {
350 // create all the event listeners needed
351 const KeyEventTestData* current_event = &kValidateKeyEvents[index];
352 scoped_ptr<ExtensionTestMessageListener> listeners[kMaxResultLength];
353 for (int i = 0; i < current_event->result_length; i++) {
354 listeners[i].reset(
355 new ExtensionTestMessageListener(current_event->result[i], false));
357 ASSERT_TRUE(SimulateKeyPress(current_event->key, current_event->control,
358 current_event->shift, current_event->alt,
359 current_event->command));
360 for (int i = 0; i < current_event->result_length; i++) {
361 EXPECT_TRUE(listeners[i]->WaitUntilSatisfied());