Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / automation / testing_automation_provider.cc
blobb0293f44a1bec939dba877928d5afac4ac55b852
1 // Copyright 2013 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 "chrome/browser/automation/testing_automation_provider.h"
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/files/file_path.h"
16 #include "base/json/json_reader.h"
17 #include "base/json/json_writer.h"
18 #include "base/json/string_escape.h"
19 #include "base/path_service.h"
20 #include "base/prefs/pref_service.h"
21 #include "base/process/process.h"
22 #include "base/process/process_iterator.h"
23 #include "base/sequenced_task_runner.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/time/time.h"
28 #include "chrome/app/chrome_command_ids.h"
29 #include "chrome/browser/autocomplete/autocomplete_controller.h"
30 #include "chrome/browser/autocomplete/autocomplete_match.h"
31 #include "chrome/browser/autocomplete/autocomplete_result.h"
32 #include "chrome/browser/automation/automation_browser_tracker.h"
33 #include "chrome/browser/automation/automation_provider_json.h"
34 #include "chrome/browser/automation/automation_provider_list.h"
35 #include "chrome/browser/automation/automation_provider_observers.h"
36 #include "chrome/browser/automation/automation_tab_tracker.h"
37 #include "chrome/browser/automation/automation_util.h"
38 #include "chrome/browser/automation/automation_window_tracker.h"
39 #include "chrome/browser/bookmarks/bookmark_model.h"
40 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
41 #include "chrome/browser/bookmarks/bookmark_storage.h"
42 #include "chrome/browser/browser_process.h"
43 #include "chrome/browser/browser_shutdown.h"
44 #include "chrome/browser/chrome_notification_types.h"
45 #include "chrome/browser/content_settings/host_content_settings_map.h"
46 #include "chrome/browser/devtools/devtools_window.h"
47 #include "chrome/browser/download/download_prefs.h"
48 #include "chrome/browser/download/download_service.h"
49 #include "chrome/browser/download/download_service_factory.h"
50 #include "chrome/browser/download/download_shelf.h"
51 #include "chrome/browser/download/save_package_file_picker.h"
52 #include "chrome/browser/extensions/browser_action_test_util.h"
53 #include "chrome/browser/extensions/crx_installer.h"
54 #include "chrome/browser/extensions/extension_action.h"
55 #include "chrome/browser/extensions/extension_action_manager.h"
56 #include "chrome/browser/extensions/extension_host.h"
57 #include "chrome/browser/extensions/extension_service.h"
58 #include "chrome/browser/extensions/extension_system.h"
59 #include "chrome/browser/extensions/extension_tab_util.h"
60 #include "chrome/browser/extensions/extension_util.h"
61 #include "chrome/browser/extensions/launch_util.h"
62 #include "chrome/browser/extensions/unpacked_installer.h"
63 #include "chrome/browser/extensions/updater/extension_updater.h"
64 #include "chrome/browser/history/history_service_factory.h"
65 #include "chrome/browser/history/top_sites.h"
66 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
67 #include "chrome/browser/infobars/infobar.h"
68 #include "chrome/browser/infobars/infobar_service.h"
69 #include "chrome/browser/lifetime/application_lifetime.h"
70 #include "chrome/browser/notifications/balloon.h"
71 #include "chrome/browser/notifications/balloon_collection.h"
72 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
73 #include "chrome/browser/notifications/notification.h"
74 #include "chrome/browser/password_manager/password_store.h"
75 #include "chrome/browser/password_manager/password_store_change.h"
76 #include "chrome/browser/password_manager/password_store_factory.h"
77 #include "chrome/browser/platform_util.h"
78 #include "chrome/browser/plugins/plugin_prefs.h"
79 #include "chrome/browser/profiles/profile.h"
80 #include "chrome/browser/profiles/profile_info_cache.h"
81 #include "chrome/browser/profiles/profile_manager.h"
82 #include "chrome/browser/profiles/profile_window.h"
83 #include "chrome/browser/profiles/profiles_state.h"
84 #include "chrome/browser/search_engines/template_url.h"
85 #include "chrome/browser/search_engines/template_url_service.h"
86 #include "chrome/browser/search_engines/template_url_service_factory.h"
87 #include "chrome/browser/sessions/session_service_factory.h"
88 #include "chrome/browser/sessions/session_tab_helper.h"
89 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
90 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
91 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
92 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
93 #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
94 #include "chrome/browser/ui/browser_commands.h"
95 #include "chrome/browser/ui/browser_finder.h"
96 #include "chrome/browser/ui/browser_iterator.h"
97 #include "chrome/browser/ui/browser_list.h"
98 #include "chrome/browser/ui/browser_tabstrip.h"
99 #include "chrome/browser/ui/browser_window.h"
100 #include "chrome/browser/ui/extensions/application_launch.h"
101 #include "chrome/browser/ui/find_bar/find_bar.h"
102 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
103 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
104 #include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
105 #include "chrome/browser/ui/host_desktop.h"
106 #include "chrome/browser/ui/login/login_prompt.h"
107 #include "chrome/browser/ui/omnibox/location_bar.h"
108 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
109 #include "chrome/browser/ui/omnibox/omnibox_view.h"
110 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
111 #include "chrome/browser/ui/startup/startup_types.h"
112 #include "chrome/common/automation_constants.h"
113 #include "chrome/common/automation_messages.h"
114 #include "chrome/common/chrome_constants.h"
115 #include "chrome/common/chrome_paths.h"
116 #include "chrome/common/chrome_switches.h"
117 #include "chrome/common/extensions/extension_constants.h"
118 #include "chrome/common/extensions/manifest_url_handler.h"
119 #include "chrome/common/pref_names.h"
120 #include "chrome/common/render_messages.h"
121 #include "content/public/browser/browser_child_process_host_iterator.h"
122 #include "content/public/browser/child_process_data.h"
123 #include "content/public/browser/favicon_status.h"
124 #include "content/public/browser/geolocation_provider.h"
125 #include "content/public/browser/interstitial_page.h"
126 #include "content/public/browser/interstitial_page_delegate.h"
127 #include "content/public/browser/navigation_entry.h"
128 #include "content/public/browser/notification_service.h"
129 #include "content/public/browser/plugin_service.h"
130 #include "content/public/browser/render_process_host.h"
131 #include "content/public/browser/render_view_host.h"
132 #include "content/public/browser/render_widget_host_view.h"
133 #include "content/public/browser/web_contents.h"
134 #include "content/public/common/child_process_host.h"
135 #include "content/public/common/common_param_traits.h"
136 #include "content/public/common/drop_data.h"
137 #include "content/public/common/geoposition.h"
138 #include "content/public/common/ssl_status.h"
139 #include "content/public/common/webplugininfo.h"
140 #include "extensions/browser/process_manager.h"
141 #include "extensions/browser/view_type_utils.h"
142 #include "extensions/common/extension.h"
143 #include "extensions/common/extension_set.h"
144 #include "extensions/common/manifest_handlers/background_info.h"
145 #include "extensions/common/permissions/permission_set.h"
146 #include "extensions/common/permissions/permissions_data.h"
147 #include "extensions/common/url_pattern.h"
148 #include "extensions/common/url_pattern_set.h"
149 #include "net/cookies/cookie_store.h"
150 #include "third_party/WebKit/public/web/WebInputEvent.h"
151 #include "ui/base/ui_base_types.h"
152 #include "ui/events/event_constants.h"
153 #include "ui/events/keycodes/keyboard_codes.h"
155 #if defined(ENABLE_CONFIGURATION_POLICY)
156 #include "components/policy/core/common/policy_service.h"
157 #endif
159 #if defined(OS_CHROMEOS)
160 #include "chromeos/dbus/dbus_thread_manager.h"
161 #endif
163 #if defined(OS_MACOSX)
164 #include <mach/mach.h>
165 #include <mach/mach_vm.h>
166 #endif
168 using automation_util::SendErrorIfModalDialogActive;
169 using content::BrowserChildProcessHostIterator;
170 using content::BrowserContext;
171 using content::BrowserThread;
172 using content::ChildProcessHost;
173 using content::DownloadItem;
174 using content::DownloadManager;
175 using content::InterstitialPage;
176 using content::NativeWebKeyboardEvent;
177 using content::NavigationController;
178 using content::NavigationEntry;
179 using content::OpenURLParams;
180 using content::PluginService;
181 using content::Referrer;
182 using content::RenderViewHost;
183 using content::SSLStatus;
184 using content::WebContents;
185 using extensions::Extension;
186 using extensions::ExtensionActionManager;
187 using extensions::ExtensionList;
188 using extensions::Manifest;
190 namespace {
192 // Helper to reply asynchronously if |automation| is still valid.
193 void SendSuccessReply(base::WeakPtr<AutomationProvider> automation,
194 IPC::Message* reply_message) {
195 if (automation.get())
196 AutomationJSONReply(automation.get(), reply_message).SendSuccess(NULL);
199 // Helper to process the result of CanEnablePlugin.
200 void DidEnablePlugin(base::WeakPtr<AutomationProvider> automation,
201 IPC::Message* reply_message,
202 const base::FilePath::StringType& path,
203 const std::string& error_msg,
204 bool did_enable) {
205 if (did_enable) {
206 SendSuccessReply(automation, reply_message);
207 } else {
208 if (automation.get()) {
209 AutomationJSONReply(automation.get(), reply_message)
210 .SendError(base::StringPrintf(error_msg.c_str(), path.c_str()));
215 // Helper to resolve the overloading of PostTask.
216 void PostTask(BrowserThread::ID id, const base::Closure& callback) {
217 BrowserThread::PostTask(id, FROM_HERE, callback);
220 class AutomationInterstitialPage : public content::InterstitialPageDelegate {
221 public:
222 AutomationInterstitialPage(WebContents* tab,
223 const GURL& url,
224 const std::string& contents)
225 : contents_(contents) {
226 interstitial_page_ = InterstitialPage::Create(tab, true, url, this);
227 interstitial_page_->Show();
230 virtual std::string GetHTMLContents() OVERRIDE { return contents_; }
232 private:
233 const std::string contents_;
234 InterstitialPage* interstitial_page_; // Owns us.
236 DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
239 } // namespace
241 const int TestingAutomationProvider::kSynchronousCommands[] = {
242 IDC_HOME,
243 IDC_SELECT_NEXT_TAB,
244 IDC_SELECT_PREVIOUS_TAB,
245 IDC_SHOW_BOOKMARK_MANAGER,
248 TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
249 : AutomationProvider(profile) {
250 BrowserList::AddObserver(this);
251 registrar_.Add(this, chrome::NOTIFICATION_SESSION_END,
252 content::NotificationService::AllSources());
253 #if defined(OS_CHROMEOS)
254 AddChromeosObservers();
255 #endif
258 TestingAutomationProvider::~TestingAutomationProvider() {
259 #if defined(OS_CHROMEOS)
260 RemoveChromeosObservers();
261 #endif
262 BrowserList::RemoveObserver(this);
265 IPC::Channel::Mode TestingAutomationProvider::GetChannelMode(
266 bool use_named_interface) {
267 if (use_named_interface)
268 #if defined(OS_POSIX)
269 return IPC::Channel::MODE_OPEN_NAMED_SERVER;
270 #else
271 return IPC::Channel::MODE_NAMED_SERVER;
272 #endif
273 else
274 return IPC::Channel::MODE_CLIENT;
277 void TestingAutomationProvider::OnBrowserAdded(Browser* browser) {
280 void TestingAutomationProvider::OnBrowserRemoved(Browser* browser) {
281 #if !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
282 // For backwards compatibility with the testing automation interface, we
283 // want the automation provider (and hence the process) to go away when the
284 // last browser goes away.
285 // The automation layer doesn't support non-native desktops.
286 if (BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty() &&
287 !CommandLine::ForCurrentProcess()->HasSwitch(
288 switches::kKeepAliveForTest)) {
289 // If you change this, update Observer for chrome::SESSION_END
290 // below.
291 base::MessageLoop::current()->PostTask(
292 FROM_HERE,
293 base::Bind(&TestingAutomationProvider::OnRemoveProvider, this));
295 #endif // !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
298 void TestingAutomationProvider::Observe(
299 int type,
300 const content::NotificationSource& source,
301 const content::NotificationDetails& details) {
302 DCHECK(type == chrome::NOTIFICATION_SESSION_END);
303 // OnBrowserRemoved does a ReleaseLater. When session end is received we exit
304 // before the task runs resulting in this object not being deleted. This
305 // Release balance out the Release scheduled by OnBrowserRemoved.
306 Release();
309 bool TestingAutomationProvider::OnMessageReceived(
310 const IPC::Message& message) {
311 base::ThreadRestrictions::ScopedAllowWait allow_wait;
312 bool handled = true;
313 bool deserialize_success = true;
314 IPC_BEGIN_MESSAGE_MAP_EX(TestingAutomationProvider,
315 message,
316 deserialize_success)
317 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
318 IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
319 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
320 IPC_MESSAGE_HANDLER(AutomationMsg_GetMachPortCount, GetMachPortCount)
321 IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
322 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
323 IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
324 IPC_MESSAGE_HANDLER_DELAY_REPLY(
325 AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
326 NavigateToURLBlockUntilNavigationsComplete)
327 IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
328 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
329 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
330 IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
331 GetNormalBrowserWindowCount)
332 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
333 IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
334 ExecuteBrowserCommandAsync)
335 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
336 ExecuteBrowserCommand)
337 IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession)
338 IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
339 IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
340 IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
341 IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType)
342 IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
343 IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
344 IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
345 IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
346 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
347 ExecuteJavascript)
348 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
349 OpenNewBrowserWindowOfType)
350 IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
351 IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration,
352 GetMetricEventDuration)
353 IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
354 IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
355 GetFindWindowVisibility)
356 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad,
357 WaitForBookmarkModelToLoad)
358 IPC_MESSAGE_HANDLER_DELAY_REPLY(
359 AutomationMsg_WaitForBrowserWindowCountToBecome,
360 WaitForBrowserWindowCountToBecome)
361 IPC_MESSAGE_HANDLER_DELAY_REPLY(
362 AutomationMsg_GoBackBlockUntilNavigationsComplete,
363 GoBackBlockUntilNavigationsComplete)
364 IPC_MESSAGE_HANDLER_DELAY_REPLY(
365 AutomationMsg_GoForwardBlockUntilNavigationsComplete,
366 GoForwardBlockUntilNavigationsComplete)
367 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest,
368 SendJSONRequestWithBrowserIndex)
369 IPC_MESSAGE_HANDLER_DELAY_REPLY(
370 AutomationMsg_SendJSONRequestWithBrowserHandle,
371 SendJSONRequestWithBrowserHandle)
372 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabCountToBecome,
373 WaitForTabCountToBecome)
374 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForInfoBarCount,
375 WaitForInfoBarCount)
376 IPC_MESSAGE_HANDLER_DELAY_REPLY(
377 AutomationMsg_WaitForProcessLauncherThreadToGoIdle,
378 WaitForProcessLauncherThreadToGoIdle)
380 IPC_MESSAGE_UNHANDLED(
381 handled = AutomationProvider::OnMessageReceived(message))
382 IPC_END_MESSAGE_MAP_EX()
383 if (!deserialize_success)
384 OnMessageDeserializationFailure();
385 return handled;
388 void TestingAutomationProvider::OnChannelError() {
389 if (!reinitialize_on_channel_error_ &&
390 browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) {
391 chrome::AttemptExit();
393 AutomationProvider::OnChannelError();
396 void TestingAutomationProvider::CloseBrowser(int browser_handle,
397 IPC::Message* reply_message) {
398 if (!browser_tracker_->ContainsHandle(browser_handle))
399 return;
401 Browser* browser = browser_tracker_->GetResource(browser_handle);
402 new BrowserClosedNotificationObserver(browser, this, reply_message, false);
403 browser->window()->Close();
406 void TestingAutomationProvider::ActivateTab(int handle,
407 int at_index,
408 int* status) {
409 *status = -1;
410 if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
411 Browser* browser = browser_tracker_->GetResource(handle);
412 if (at_index >= 0 && at_index < browser->tab_strip_model()->count()) {
413 browser->tab_strip_model()->ActivateTabAt(at_index, true);
414 *status = 0;
419 void TestingAutomationProvider::AppendTab(int handle,
420 const GURL& url,
421 IPC::Message* reply_message) {
422 int append_tab_response = -1; // -1 is the error code
423 TabAppendedNotificationObserver* observer = NULL;
425 if (browser_tracker_->ContainsHandle(handle)) {
426 Browser* browser = browser_tracker_->GetResource(handle);
427 observer = new TabAppendedNotificationObserver(browser, this,
428 reply_message, false);
429 WebContents* contents =
430 chrome::AddSelectedTabWithURL(browser, url,
431 content::PAGE_TRANSITION_TYPED);
432 if (contents) {
433 append_tab_response = GetIndexForNavigationController(
434 &contents->GetController(), browser);
438 if (append_tab_response < 0) {
439 // Appending tab failed. Clean up and send failure response.
441 if (observer)
442 delete observer;
444 AutomationMsg_AppendTab::WriteReplyParams(reply_message,
445 append_tab_response);
446 Send(reply_message);
450 void TestingAutomationProvider::GetMachPortCount(int* port_count) {
451 #if defined(OS_MACOSX)
452 mach_port_name_array_t names;
453 mach_msg_type_number_t names_count;
454 mach_port_type_array_t types;
455 mach_msg_type_number_t types_count;
457 mach_port_t port = mach_task_self();
459 // A friendlier interface would allow NULL buffers to only get the counts.
460 kern_return_t kr = mach_port_names(port, &names, &names_count,
461 &types, &types_count);
462 if (kr != KERN_SUCCESS) {
463 *port_count = 0;
464 return;
467 // The documentation states this is an invariant.
468 DCHECK_EQ(names_count, types_count);
469 *port_count = names_count;
471 mach_vm_deallocate(port, reinterpret_cast<mach_vm_address_t>(names),
472 names_count * sizeof(mach_port_name_array_t));
473 mach_vm_deallocate(port, reinterpret_cast<mach_vm_address_t>(types),
474 types_count * sizeof(mach_port_type_array_t));
475 #else
476 *port_count = 0;
477 #endif
480 void TestingAutomationProvider::GetActiveTabIndex(int handle,
481 int* active_tab_index) {
482 *active_tab_index = -1; // -1 is the error code
483 if (browser_tracker_->ContainsHandle(handle)) {
484 Browser* browser = browser_tracker_->GetResource(handle);
485 *active_tab_index = browser->tab_strip_model()->active_index();
489 void TestingAutomationProvider::CloseTab(int tab_handle,
490 bool wait_until_closed,
491 IPC::Message* reply_message) {
492 if (tab_tracker_->ContainsHandle(tab_handle)) {
493 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
494 Browser* browser = chrome::FindBrowserWithWebContents(
495 controller->GetWebContents());
496 DCHECK(browser);
497 new TabClosedNotificationObserver(this, wait_until_closed, reply_message,
498 false);
499 chrome::CloseWebContents(browser, controller->GetWebContents(), false);
500 return;
503 AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
504 Send(reply_message);
507 void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
508 int* value_size,
509 std::string* value) {
510 WebContents* contents = tab_tracker_->ContainsHandle(handle) ?
511 tab_tracker_->GetResource(handle)->GetWebContents() : NULL;
512 automation_util::GetCookies(url, contents, value_size, value);
515 void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
516 int handle, const GURL& url, int number_of_navigations,
517 IPC::Message* reply_message) {
518 if (tab_tracker_->ContainsHandle(handle)) {
519 NavigationController* tab = tab_tracker_->GetResource(handle);
521 // Simulate what a user would do. Activate the tab and then navigate.
522 // We could allow navigating in a background tab in future.
523 Browser* browser = FindAndActivateTab(tab);
525 if (browser) {
526 new NavigationNotificationObserver(tab, this, reply_message,
527 number_of_navigations, false, false);
529 // TODO(darin): avoid conversion to GURL.
530 OpenURLParams params(
531 url, Referrer(), CURRENT_TAB,
532 content::PageTransitionFromInt(
533 content::PAGE_TRANSITION_TYPED |
534 content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
535 false);
536 browser->OpenURL(params);
537 return;
541 AutomationMsg_NavigateToURLBlockUntilNavigationsComplete::WriteReplyParams(
542 reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
543 Send(reply_message);
546 void TestingAutomationProvider::NavigationAsync(int handle,
547 const GURL& url,
548 bool* status) {
549 *status = false;
551 if (tab_tracker_->ContainsHandle(handle)) {
552 NavigationController* tab = tab_tracker_->GetResource(handle);
554 // Simulate what a user would do. Activate the tab and then navigate.
555 // We could allow navigating in a background tab in future.
556 Browser* browser = FindAndActivateTab(tab);
558 if (browser) {
559 // Don't add any listener unless a callback mechanism is desired.
560 // TODO(vibhor): Do this if such a requirement arises in future.
561 OpenURLParams params(
562 url, Referrer(), CURRENT_TAB,
563 content::PageTransitionFromInt(
564 content::PAGE_TRANSITION_TYPED |
565 content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
566 false);
567 browser->OpenURL(params);
568 *status = true;
573 void TestingAutomationProvider::Reload(int handle,
574 IPC::Message* reply_message) {
575 if (tab_tracker_->ContainsHandle(handle)) {
576 NavigationController* tab = tab_tracker_->GetResource(handle);
577 Browser* browser = FindAndActivateTab(tab);
578 if (chrome::IsCommandEnabled(browser, IDC_RELOAD)) {
579 new NavigationNotificationObserver(
580 tab, this, reply_message, 1, false, false);
581 chrome::ExecuteCommand(browser, IDC_RELOAD);
582 return;
586 AutomationMsg_Reload::WriteReplyParams(
587 reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
588 Send(reply_message);
591 void TestingAutomationProvider::GetBrowserWindowCount(int* window_count) {
592 // The automation layer doesn't support non-native desktops.
593 *window_count = static_cast<int>(BrowserList::GetInstance(
594 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
597 void TestingAutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
598 *window_count = static_cast<int>(chrome::GetTabbedBrowserCount(
599 profile_, chrome::HOST_DESKTOP_TYPE_NATIVE));
602 void TestingAutomationProvider::GetBrowserWindow(int index, int* handle) {
603 *handle = 0;
604 Browser* browser = automation_util::GetBrowserAt(index);
605 if (browser)
606 *handle = browser_tracker_->Add(browser);
609 void TestingAutomationProvider::ExecuteBrowserCommandAsync(int handle,
610 int command,
611 bool* success) {
612 *success = false;
613 if (!browser_tracker_->ContainsHandle(handle)) {
614 LOG(WARNING) << "Browser tracker does not contain handle: " << handle;
615 return;
617 Browser* browser = browser_tracker_->GetResource(handle);
618 if (!chrome::SupportsCommand(browser, command)) {
619 LOG(WARNING) << "Browser does not support command: " << command;
620 return;
622 if (!chrome::IsCommandEnabled(browser, command)) {
623 LOG(WARNING) << "Browser command not enabled: " << command;
624 return;
626 chrome::ExecuteCommand(browser, command);
627 *success = true;
630 void TestingAutomationProvider::ExecuteBrowserCommand(
631 int handle, int command, IPC::Message* reply_message) {
632 if (browser_tracker_->ContainsHandle(handle)) {
633 Browser* browser = browser_tracker_->GetResource(handle);
634 if (chrome::SupportsCommand(browser, command) &&
635 chrome::IsCommandEnabled(browser, command)) {
636 // First check if we can handle the command without using an observer.
637 for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
638 if (command == kSynchronousCommands[i]) {
639 chrome::ExecuteCommand(browser, command);
640 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
641 true);
642 Send(reply_message);
643 return;
647 // Use an observer if we have one, otherwise fail.
648 if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
649 this, browser, command, reply_message, false)) {
650 chrome::ExecuteCommand(browser, command);
651 return;
655 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
656 Send(reply_message);
659 void TestingAutomationProvider::WebkitMouseClick(base::DictionaryValue* args,
660 IPC::Message* reply_message) {
661 if (SendErrorIfModalDialogActive(this, reply_message))
662 return;
664 RenderViewHost* view;
665 std::string error;
666 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
667 AutomationJSONReply(this, reply_message).SendError(error);
668 return;
671 blink::WebMouseEvent mouse_event;
672 if (!args->GetInteger("x", &mouse_event.x) ||
673 !args->GetInteger("y", &mouse_event.y)) {
674 AutomationJSONReply(this, reply_message)
675 .SendError("(X,Y) coordinates missing or invalid");
676 return;
679 int button;
680 if (!args->GetInteger("button", &button)) {
681 AutomationJSONReply(this, reply_message)
682 .SendError("Mouse button missing or invalid");
683 return;
685 if (button == automation::kLeftButton) {
686 mouse_event.button = blink::WebMouseEvent::ButtonLeft;
687 } else if (button == automation::kRightButton) {
688 mouse_event.button = blink::WebMouseEvent::ButtonRight;
689 } else if (button == automation::kMiddleButton) {
690 mouse_event.button = blink::WebMouseEvent::ButtonMiddle;
691 } else {
692 AutomationJSONReply(this, reply_message)
693 .SendError("Invalid button press requested");
694 return;
697 mouse_event.type = blink::WebInputEvent::MouseDown;
698 mouse_event.clickCount = 1;
700 view->ForwardMouseEvent(mouse_event);
702 mouse_event.type = blink::WebInputEvent::MouseUp;
703 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
705 view->ForwardMouseEvent(mouse_event);
708 void TestingAutomationProvider::WebkitMouseMove(
709 base::DictionaryValue* args, IPC::Message* reply_message) {
710 if (SendErrorIfModalDialogActive(this, reply_message))
711 return;
713 RenderViewHost* view;
714 std::string error;
715 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
716 AutomationJSONReply(this, reply_message).SendError(error);
717 return;
720 blink::WebMouseEvent mouse_event;
721 if (!args->GetInteger("x", &mouse_event.x) ||
722 !args->GetInteger("y", &mouse_event.y)) {
723 AutomationJSONReply(this, reply_message)
724 .SendError("(X,Y) coordinates missing or invalid");
725 return;
728 mouse_event.type = blink::WebInputEvent::MouseMove;
729 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
731 view->ForwardMouseEvent(mouse_event);
734 void TestingAutomationProvider::WebkitMouseDrag(base::DictionaryValue* args,
735 IPC::Message* reply_message) {
736 if (SendErrorIfModalDialogActive(this, reply_message))
737 return;
739 RenderViewHost* view;
740 std::string error;
741 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
742 AutomationJSONReply(this, reply_message).SendError(error);
743 return;
746 blink::WebMouseEvent mouse_event;
747 int start_x, start_y, end_x, end_y;
748 if (!args->GetInteger("start_x", &start_x) ||
749 !args->GetInteger("start_y", &start_y) ||
750 !args->GetInteger("end_x", &end_x) ||
751 !args->GetInteger("end_y", &end_y)) {
752 AutomationJSONReply(this, reply_message)
753 .SendError("Invalid start/end positions");
754 return;
757 mouse_event.type = blink::WebInputEvent::MouseMove;
758 // Step 1- Move the mouse to the start position.
759 mouse_event.x = start_x;
760 mouse_event.y = start_y;
761 view->ForwardMouseEvent(mouse_event);
763 // Step 2- Left click mouse down, the mouse button is fixed.
764 mouse_event.type = blink::WebInputEvent::MouseDown;
765 mouse_event.button = blink::WebMouseEvent::ButtonLeft;
766 mouse_event.clickCount = 1;
767 view->ForwardMouseEvent(mouse_event);
769 // Step 3 - Move the mouse to the end position.
770 mouse_event.type = blink::WebInputEvent::MouseMove;
771 mouse_event.x = end_x;
772 mouse_event.y = end_y;
773 mouse_event.clickCount = 0;
774 view->ForwardMouseEvent(mouse_event);
776 // Step 4 - Release the left mouse button.
777 mouse_event.type = blink::WebInputEvent::MouseUp;
778 mouse_event.clickCount = 1;
779 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
781 view->ForwardMouseEvent(mouse_event);
784 void TestingAutomationProvider::WebkitMouseButtonDown(
785 base::DictionaryValue* args, IPC::Message* reply_message) {
786 if (SendErrorIfModalDialogActive(this, reply_message))
787 return;
789 RenderViewHost* view;
790 std::string error;
791 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
792 AutomationJSONReply(this, reply_message).SendError(error);
793 return;
796 blink::WebMouseEvent mouse_event;
797 if (!args->GetInteger("x", &mouse_event.x) ||
798 !args->GetInteger("y", &mouse_event.y)) {
799 AutomationJSONReply(this, reply_message)
800 .SendError("(X,Y) coordinates missing or invalid");
801 return;
804 mouse_event.type = blink::WebInputEvent::MouseDown;
805 mouse_event.button = blink::WebMouseEvent::ButtonLeft;
806 mouse_event.clickCount = 1;
807 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
809 view->ForwardMouseEvent(mouse_event);
812 void TestingAutomationProvider::WebkitMouseButtonUp(
813 base::DictionaryValue* args, IPC::Message* reply_message) {
814 if (SendErrorIfModalDialogActive(this, reply_message))
815 return;
817 RenderViewHost* view;
818 std::string error;
819 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
820 AutomationJSONReply(this, reply_message).SendError(error);
821 return;
824 blink::WebMouseEvent mouse_event;
825 if (!args->GetInteger("x", &mouse_event.x) ||
826 !args->GetInteger("y", &mouse_event.y)) {
827 AutomationJSONReply(this, reply_message)
828 .SendError("(X,Y) coordinates missing or invalid");
829 return;
832 mouse_event.type = blink::WebInputEvent::MouseUp;
833 mouse_event.button = blink::WebMouseEvent::ButtonLeft;
834 mouse_event.clickCount = 1;
835 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
837 view->ForwardMouseEvent(mouse_event);
840 void TestingAutomationProvider::WebkitMouseDoubleClick(
841 base::DictionaryValue* args, IPC::Message* reply_message) {
842 if (SendErrorIfModalDialogActive(this, reply_message))
843 return;
845 RenderViewHost* view;
846 std::string error;
847 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
848 AutomationJSONReply(this, reply_message).SendError(error);
849 return;
852 blink::WebMouseEvent mouse_event;
853 if (!args->GetInteger("x", &mouse_event.x) ||
854 !args->GetInteger("y", &mouse_event.y)) {
855 AutomationJSONReply(this, reply_message)
856 .SendError("(X,Y) coordinates missing or invalid");
857 return;
860 mouse_event.type = blink::WebInputEvent::MouseDown;
861 mouse_event.button = blink::WebMouseEvent::ButtonLeft;
862 mouse_event.clickCount = 1;
863 view->ForwardMouseEvent(mouse_event);
865 mouse_event.type = blink::WebInputEvent::MouseUp;
866 new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
868 view->ForwardMouseEvent(mouse_event);
870 mouse_event.type = blink::WebInputEvent::MouseDown;
871 mouse_event.clickCount = 2;
872 view->ForwardMouseEvent(mouse_event);
874 mouse_event.type = blink::WebInputEvent::MouseUp;
875 view->ForwardMouseEvent(mouse_event);
878 void TestingAutomationProvider::DragAndDropFilePaths(
879 base::DictionaryValue* args, IPC::Message* reply_message) {
880 if (SendErrorIfModalDialogActive(this, reply_message))
881 return;
883 RenderViewHost* view;
884 std::string error;
885 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
886 AutomationJSONReply(this, reply_message).SendError(error);
887 return;
890 int x, y;
891 if (!args->GetInteger("x", &x) || !args->GetInteger("y", &y)) {
892 AutomationJSONReply(this, reply_message)
893 .SendError("(X,Y) coordinates missing or invalid");
894 return;
897 base::ListValue* paths = NULL;
898 if (!args->GetList("paths", &paths)) {
899 AutomationJSONReply(this, reply_message)
900 .SendError("'paths' missing or invalid");
901 return;
904 // Emulate drag and drop to set the file paths to the file upload control.
905 content::DropData drop_data;
906 for (size_t path_index = 0; path_index < paths->GetSize(); ++path_index) {
907 base::string16 path;
908 if (!paths->GetString(path_index, &path)) {
909 AutomationJSONReply(this, reply_message)
910 .SendError("'paths' contains a non-string type");
911 return;
914 drop_data.filenames.push_back(
915 content::DropData::FileInfo(path, base::string16()));
918 const gfx::Point client(x, y);
919 // We don't set any values in screen variable because DragTarget*** ignore the
920 // screen argument.
921 const gfx::Point screen;
923 int operations = 0;
924 operations |= blink::WebDragOperationCopy;
925 operations |= blink::WebDragOperationLink;
926 operations |= blink::WebDragOperationMove;
928 view->DragTargetDragEnter(
929 drop_data, client, screen,
930 static_cast<blink::WebDragOperationsMask>(operations), 0);
931 new DragTargetDropAckNotificationObserver(this, reply_message);
932 view->DragTargetDrop(client, screen, 0);
935 void TestingAutomationProvider::GetTabCount(int handle, int* tab_count) {
936 *tab_count = -1; // -1 is the error code
938 if (browser_tracker_->ContainsHandle(handle)) {
939 Browser* browser = browser_tracker_->GetResource(handle);
940 *tab_count = browser->tab_strip_model()->count();
944 void TestingAutomationProvider::GetType(int handle, int* type_as_int) {
945 *type_as_int = -1; // -1 is the error code
947 if (browser_tracker_->ContainsHandle(handle)) {
948 Browser* browser = browser_tracker_->GetResource(handle);
949 *type_as_int = static_cast<int>(browser->type());
953 void TestingAutomationProvider::GetTab(int win_handle,
954 int tab_index,
955 int* tab_handle) {
956 *tab_handle = 0;
957 if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
958 Browser* browser = browser_tracker_->GetResource(win_handle);
959 if (tab_index < browser->tab_strip_model()->count()) {
960 WebContents* web_contents =
961 browser->tab_strip_model()->GetWebContentsAt(tab_index);
962 *tab_handle = tab_tracker_->Add(&web_contents->GetController());
967 void TestingAutomationProvider::GetTabTitle(int handle,
968 int* title_string_size,
969 std::wstring* title) {
970 *title_string_size = -1; // -1 is the error code
971 if (tab_tracker_->ContainsHandle(handle)) {
972 NavigationController* tab = tab_tracker_->GetResource(handle);
973 NavigationEntry* entry = tab->GetActiveEntry();
974 if (entry != NULL) {
975 *title = base::UTF16ToWideHack(entry->GetTitleForDisplay(std::string()));
976 } else {
977 *title = std::wstring();
979 *title_string_size = static_cast<int>(title->size());
983 void TestingAutomationProvider::GetTabIndex(int handle, int* tabstrip_index) {
984 *tabstrip_index = -1; // -1 is the error code
986 if (tab_tracker_->ContainsHandle(handle)) {
987 NavigationController* tab = tab_tracker_->GetResource(handle);
988 Browser* browser = chrome::FindBrowserWithWebContents(
989 tab->GetWebContents());
990 *tabstrip_index = browser->tab_strip_model()->GetIndexOfWebContents(
991 tab->GetWebContents());
995 void TestingAutomationProvider::GetTabURL(int handle,
996 bool* success,
997 GURL* url) {
998 *success = false;
999 if (tab_tracker_->ContainsHandle(handle)) {
1000 NavigationController* tab = tab_tracker_->GetResource(handle);
1001 // Return what the user would see in the location bar.
1002 *url = tab->GetActiveEntry()->GetVirtualURL();
1003 *success = true;
1007 void TestingAutomationProvider::ExecuteJavascriptInRenderViewFrame(
1008 const base::string16& frame_xpath,
1009 const base::string16& script,
1010 IPC::Message* reply_message,
1011 RenderViewHost* render_view_host) {
1012 // Set the routing id of this message with the controller.
1013 // This routing id needs to be remembered for the reverse
1014 // communication while sending back the response of
1015 // this javascript execution.
1016 render_view_host->ExecuteJavascriptInWebFrame(
1017 frame_xpath,
1018 base::ASCIIToUTF16("window.domAutomationController.setAutomationId(0);"));
1019 render_view_host->ExecuteJavascriptInWebFrame(
1020 frame_xpath, script);
1023 void TestingAutomationProvider::ExecuteJavascript(
1024 int handle,
1025 const std::wstring& frame_xpath,
1026 const std::wstring& script,
1027 IPC::Message* reply_message) {
1028 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1029 if (!web_contents) {
1030 AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
1031 Send(reply_message);
1032 return;
1035 new DomOperationMessageSender(this, reply_message, false);
1036 ExecuteJavascriptInRenderViewFrame(base::WideToUTF16Hack(frame_xpath),
1037 base::WideToUTF16Hack(script),
1038 reply_message,
1039 web_contents->GetRenderViewHost());
1042 // Sample json input: { "command": "OpenNewBrowserWindowWithNewProfile" }
1043 // Sample output: {}
1044 void TestingAutomationProvider::OpenNewBrowserWindowWithNewProfile(
1045 base::DictionaryValue* args, IPC::Message* reply_message) {
1046 ProfileManager* profile_manager = g_browser_process->profile_manager();
1047 new BrowserOpenedWithNewProfileNotificationObserver(this, reply_message);
1048 profile_manager->CreateMultiProfileAsync(
1049 base::string16(), base::string16(),
1050 ProfileManager::CreateCallback(), std::string());
1053 // Sample json input: { "command": "GetMultiProfileInfo" }
1054 // See GetMultiProfileInfo() in pyauto.py for sample output.
1055 void TestingAutomationProvider::GetMultiProfileInfo(
1056 base::DictionaryValue* args, IPC::Message* reply_message) {
1057 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1058 ProfileManager* profile_manager = g_browser_process->profile_manager();
1059 const ProfileInfoCache& profile_info_cache =
1060 profile_manager->GetProfileInfoCache();
1061 return_value->SetBoolean("enabled", profiles::IsMultipleProfilesEnabled());
1063 base::ListValue* profiles = new base::ListValue;
1064 for (size_t index = 0; index < profile_info_cache.GetNumberOfProfiles();
1065 ++index) {
1066 base::DictionaryValue* item = new base::DictionaryValue;
1067 item->SetString("name", profile_info_cache.GetNameOfProfileAtIndex(index));
1068 item->SetString("path",
1069 profile_info_cache.GetPathOfProfileAtIndex(index).value());
1070 profiles->Append(item);
1072 return_value->Set("profiles", profiles);
1073 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
1076 void TestingAutomationProvider::OpenNewBrowserWindowOfType(
1077 int type, bool show, IPC::Message* reply_message) {
1078 new BrowserOpenedNotificationObserver(this, reply_message, false);
1079 // We may have no current browser windows open so don't rely on
1080 // asking an existing browser to execute the IDC_NEWWINDOW command.
1081 Browser* browser = new Browser(
1082 Browser::CreateParams(static_cast<Browser::Type>(type), profile_,
1083 chrome::HOST_DESKTOP_TYPE_NATIVE));
1084 chrome::AddTabAt(browser, GURL(), -1, true);
1085 if (show)
1086 browser->window()->Show();
1089 void TestingAutomationProvider::OpenNewBrowserWindow(
1090 base::DictionaryValue* args,
1091 IPC::Message* reply_message) {
1092 bool show;
1093 if (!args->GetBoolean("show", &show)) {
1094 AutomationJSONReply(this, reply_message)
1095 .SendError("'show' missing or invalid.");
1096 return;
1098 new BrowserOpenedNotificationObserver(this, reply_message, true);
1099 Browser* browser = new Browser(
1100 Browser::CreateParams(Browser::TYPE_TABBED, profile_,
1101 chrome::HOST_DESKTOP_TYPE_NATIVE));
1102 chrome::AddTabAt(browser, GURL(), -1, true);
1103 if (show)
1104 browser->window()->Show();
1107 void TestingAutomationProvider::GetBrowserWindowCountJSON(
1108 base::DictionaryValue* args,
1109 IPC::Message* reply_message) {
1110 base::DictionaryValue dict;
1111 // The automation layer doesn't support non-native desktops.
1112 dict.SetInteger("count",
1113 static_cast<int>(BrowserList::GetInstance(
1114 chrome::HOST_DESKTOP_TYPE_NATIVE)->size()));
1115 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
1118 void TestingAutomationProvider::CloseBrowserWindow(
1119 base::DictionaryValue* args,
1120 IPC::Message* reply_message) {
1121 AutomationJSONReply reply(this, reply_message);
1122 Browser* browser;
1123 std::string error_msg;
1124 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1125 reply.SendError(error_msg);
1126 return;
1128 new BrowserClosedNotificationObserver(browser, this, reply_message, true);
1129 browser->window()->Close();
1132 void TestingAutomationProvider::OpenProfileWindow(
1133 base::DictionaryValue* args, IPC::Message* reply_message) {
1134 ProfileManager* profile_manager = g_browser_process->profile_manager();
1135 base::FilePath::StringType path;
1136 if (!args->GetString("path", &path)) {
1137 AutomationJSONReply(this, reply_message).SendError(
1138 "Invalid or missing arg: 'path'");
1139 return;
1141 Profile* profile = profile_manager->GetProfileByPath(base::FilePath(path));
1142 if (!profile) {
1143 AutomationJSONReply(this, reply_message).SendError(
1144 base::StringPrintf("Invalid profile path: %s", path.c_str()));
1145 return;
1147 int num_loads;
1148 if (!args->GetInteger("num_loads", &num_loads)) {
1149 AutomationJSONReply(this, reply_message).SendError(
1150 "Invalid or missing arg: 'num_loads'");
1151 return;
1153 new BrowserOpenedWithExistingProfileNotificationObserver(
1154 this, reply_message, num_loads);
1155 profiles::FindOrCreateNewWindowForProfile(
1156 profile,
1157 chrome::startup::IS_NOT_PROCESS_STARTUP,
1158 chrome::startup::IS_NOT_FIRST_RUN,
1159 chrome::HOST_DESKTOP_TYPE_NATIVE,
1160 false);
1163 void TestingAutomationProvider::GetWindowForBrowser(int browser_handle,
1164 bool* success,
1165 int* handle) {
1166 *success = false;
1167 *handle = 0;
1169 if (browser_tracker_->ContainsHandle(browser_handle)) {
1170 Browser* browser = browser_tracker_->GetResource(browser_handle);
1171 gfx::NativeWindow win = browser->window()->GetNativeWindow();
1172 // Add() returns the existing handle for the resource if any.
1173 *handle = window_tracker_->Add(win);
1174 *success = true;
1178 void TestingAutomationProvider::GetMetricEventDuration(
1179 const std::string& event_name,
1180 int* duration_ms) {
1181 *duration_ms = metric_event_duration_observer_->GetEventDurationMs(
1182 event_name);
1185 void TestingAutomationProvider::BringBrowserToFront(int browser_handle,
1186 bool* success) {
1187 *success = false;
1188 if (browser_tracker_->ContainsHandle(browser_handle)) {
1189 Browser* browser = browser_tracker_->GetResource(browser_handle);
1190 browser->window()->Activate();
1191 *success = true;
1195 void TestingAutomationProvider::GetFindWindowVisibility(int handle,
1196 bool* visible) {
1197 *visible = false;
1198 Browser* browser = browser_tracker_->GetResource(handle);
1199 if (browser) {
1200 FindBarTesting* find_bar =
1201 browser->GetFindBarController()->find_bar()->GetFindBarTesting();
1202 find_bar->GetFindBarWindowInfo(NULL, visible);
1206 // Bookmark bar visibility is based on the pref (e.g. is it in the toolbar).
1207 // Presence in the NTP is signalled in |detached|.
1208 void TestingAutomationProvider::GetBookmarkBarStatus(
1209 base::DictionaryValue* args,
1210 IPC::Message* reply_message) {
1211 AutomationJSONReply reply(this, reply_message);
1212 Browser* browser;
1213 std::string error_msg;
1214 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1215 reply.SendError(error_msg);
1216 return;
1218 // browser->window()->IsBookmarkBarVisible() is not consistent across
1219 // platforms. bookmark_bar_state() also follows prefs::kShowBookmarkBar
1220 // and has a shared implementation on all platforms.
1221 base::DictionaryValue dict;
1222 dict.SetBoolean("visible",
1223 browser->bookmark_bar_state() == BookmarkBar::SHOW);
1224 dict.SetBoolean("animating", browser->window()->IsBookmarkBarAnimating());
1225 dict.SetBoolean("detached",
1226 browser->bookmark_bar_state() == BookmarkBar::DETACHED);
1227 reply.SendSuccess(&dict);
1230 void TestingAutomationProvider::GetBookmarksAsJSON(
1231 base::DictionaryValue* args,
1232 IPC::Message* reply_message) {
1233 AutomationJSONReply reply(this, reply_message);
1234 Browser* browser;
1235 std::string error_msg, bookmarks_as_json;
1236 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1237 reply.SendError(error_msg);
1238 return;
1240 BookmarkModel* bookmark_model =
1241 BookmarkModelFactory::GetForProfile(browser->profile());
1242 if (!bookmark_model->loaded()) {
1243 reply.SendError("Bookmark model is not loaded");
1244 return;
1246 scoped_refptr<BookmarkStorage> storage(
1247 new BookmarkStorage(browser->profile(),
1248 bookmark_model,
1249 browser->profile()->GetIOTaskRunner().get()));
1250 if (!storage->SerializeData(&bookmarks_as_json)) {
1251 reply.SendError("Failed to serialize bookmarks");
1252 return;
1254 base::DictionaryValue dict;
1255 dict.SetString("bookmarks_as_json", bookmarks_as_json);
1256 reply.SendSuccess(&dict);
1259 void TestingAutomationProvider::WaitForBookmarkModelToLoad(
1260 int handle,
1261 IPC::Message* reply_message) {
1262 if (browser_tracker_->ContainsHandle(handle)) {
1263 Browser* browser = browser_tracker_->GetResource(handle);
1264 BookmarkModel* model =
1265 BookmarkModelFactory::GetForProfile(browser->profile());
1266 AutomationProviderBookmarkModelObserver* observer =
1267 new AutomationProviderBookmarkModelObserver(this, reply_message,
1268 model, false);
1269 if (model->loaded()) {
1270 observer->ReleaseReply();
1271 delete observer;
1272 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1273 reply_message, true);
1274 Send(reply_message);
1279 void TestingAutomationProvider::WaitForBookmarkModelToLoadJSON(
1280 base::DictionaryValue* args,
1281 IPC::Message* reply_message) {
1282 Browser* browser;
1283 std::string error_msg;
1284 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1285 AutomationJSONReply(this, reply_message).SendError(error_msg);
1286 return;
1288 BookmarkModel* model =
1289 BookmarkModelFactory::GetForProfile(browser->profile());
1290 AutomationProviderBookmarkModelObserver* observer =
1291 new AutomationProviderBookmarkModelObserver(this, reply_message, model,
1292 true);
1293 if (model->loaded()) {
1294 observer->ReleaseReply();
1295 delete observer;
1296 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
1297 return;
1301 void TestingAutomationProvider::AddBookmark(
1302 base::DictionaryValue* args,
1303 IPC::Message* reply_message) {
1304 AutomationJSONReply reply(this, reply_message);
1305 Browser* browser;
1306 std::string error_msg, url;
1307 base::string16 title;
1308 int parent_id, index;
1309 bool folder;
1310 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1311 reply.SendError(error_msg);
1312 return;
1314 if (!args->GetBoolean("is_folder", &folder)) {
1315 reply.SendError("'is_folder' missing or invalid");
1316 return;
1318 if (!folder && !args->GetString("url", &url)) {
1319 reply.SendError("'url' missing or invalid");
1320 return;
1322 if (!args->GetInteger("parent_id", &parent_id)) {
1323 reply.SendError("'parent_id' missing or invalid");
1324 return;
1326 if (!args->GetInteger("index", &index)) {
1327 reply.SendError("'index' missing or invalid");
1328 return;
1330 if (!args->GetString("title", &title)) {
1331 reply.SendError("'title' missing or invalid");
1332 return;
1334 BookmarkModel* model =
1335 BookmarkModelFactory::GetForProfile(browser->profile());
1336 if (!model->loaded()) {
1337 reply.SendError("Bookmark model is not loaded");
1338 return;
1340 const BookmarkNode* parent = model->GetNodeByID(parent_id);
1341 if (!parent) {
1342 reply.SendError("Failed to get parent bookmark node");
1343 return;
1345 const BookmarkNode* child;
1346 if (folder) {
1347 child = model->AddFolder(parent, index, title);
1348 } else {
1349 child = model->AddURL(parent, index, title, GURL(url));
1351 if (!child) {
1352 reply.SendError("Failed to add bookmark");
1353 return;
1355 reply.SendSuccess(NULL);
1358 void TestingAutomationProvider::ReparentBookmark(base::DictionaryValue* args,
1359 IPC::Message* reply_message) {
1360 AutomationJSONReply reply(this, reply_message);
1361 Browser* browser;
1362 std::string error_msg;
1363 int new_parent_id, id, index;
1364 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1365 reply.SendError(error_msg);
1366 return;
1368 if (!args->GetInteger("id", &id)) {
1369 reply.SendError("'id' missing or invalid");
1370 return;
1372 if (!args->GetInteger("new_parent_id", &new_parent_id)) {
1373 reply.SendError("'new_parent_id' missing or invalid");
1374 return;
1376 if (!args->GetInteger("index", &index)) {
1377 reply.SendError("'index' missing or invalid");
1378 return;
1380 BookmarkModel* model =
1381 BookmarkModelFactory::GetForProfile(browser->profile());
1382 if (!model->loaded()) {
1383 reply.SendError("Bookmark model is not loaded");
1384 return;
1386 const BookmarkNode* node = model->GetNodeByID(id);
1387 const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id);
1388 if (!node) {
1389 reply.SendError("Failed to get bookmark node");
1390 return;
1392 if (!new_parent) {
1393 reply.SendError("Failed to get new parent bookmark node");
1394 return;
1396 model->Move(node, new_parent, index);
1397 reply.SendSuccess(NULL);
1400 void TestingAutomationProvider::SetBookmarkTitle(base::DictionaryValue* args,
1401 IPC::Message* reply_message) {
1402 AutomationJSONReply reply(this, reply_message);
1403 Browser* browser;
1404 std::string error_msg;
1405 base::string16 title;
1406 int id;
1407 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1408 reply.SendError(error_msg);
1409 return;
1411 if (!args->GetInteger("id", &id)) {
1412 reply.SendError("'id' missing or invalid");
1413 return;
1415 if (!args->GetString("title", &title)) {
1416 reply.SendError("'title' missing or invalid");
1417 return;
1419 BookmarkModel* model =
1420 BookmarkModelFactory::GetForProfile(browser->profile());
1421 if (!model->loaded()) {
1422 reply.SendError("Bookmark model is not loaded");
1423 return;
1425 const BookmarkNode* node = model->GetNodeByID(id);
1426 if (!node) {
1427 reply.SendError("Failed to get bookmark node");
1428 return;
1430 model->SetTitle(node, title);
1431 reply.SendSuccess(NULL);
1434 void TestingAutomationProvider::SetBookmarkURL(base::DictionaryValue* args,
1435 IPC::Message* reply_message) {
1436 AutomationJSONReply reply(this, reply_message);
1437 Browser* browser;
1438 std::string error_msg, url;
1439 int id;
1440 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1441 reply.SendError(error_msg);
1442 return;
1444 if (!args->GetInteger("id", &id)) {
1445 reply.SendError("'id' missing or invalid");
1446 return;
1448 if (!args->GetString("url", &url)) {
1449 reply.SendError("'url' missing or invalid");
1450 return;
1452 BookmarkModel* model =
1453 BookmarkModelFactory::GetForProfile(browser->profile());
1454 if (!model->loaded()) {
1455 reply.SendError("Bookmark model is not loaded");
1456 return;
1458 const BookmarkNode* node = model->GetNodeByID(id);
1459 if (!node) {
1460 reply.SendError("Failed to get bookmark node");
1461 return;
1463 model->SetURL(node, GURL(url));
1464 reply.SendSuccess(NULL);
1467 void TestingAutomationProvider::RemoveBookmark(base::DictionaryValue* args,
1468 IPC::Message* reply_message) {
1469 AutomationJSONReply reply(this, reply_message);
1470 Browser* browser;
1471 std::string error_msg;
1472 int id;
1473 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1474 reply.SendError(error_msg);
1475 return;
1477 if (!args->GetInteger("id", &id)) {
1478 reply.SendError("'id' missing or invalid");
1479 return;
1481 BookmarkModel* model =
1482 BookmarkModelFactory::GetForProfile(browser->profile());
1483 if (!model->loaded()) {
1484 reply.SendError("Bookmark model is not loaded");
1485 return;
1487 const BookmarkNode* node = model->GetNodeByID(id);
1488 if (!node) {
1489 reply.SendError("Failed to get bookmark node");
1490 return;
1492 const BookmarkNode* parent = node->parent();
1493 if (!parent) {
1494 reply.SendError("Failed to get parent bookmark node");
1495 return;
1497 model->Remove(parent, parent->GetIndexOf(node));
1498 reply.SendSuccess(NULL);
1501 void TestingAutomationProvider::WaitForBrowserWindowCountToBecome(
1502 int target_count,
1503 IPC::Message* reply_message) {
1504 // The automation layer doesn't support non-native desktops.
1505 int current_count = static_cast<int>(BrowserList::GetInstance(
1506 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
1507 if (current_count == target_count) {
1508 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
1509 reply_message, true);
1510 Send(reply_message);
1511 return;
1514 // Set up an observer (it will delete itself).
1515 new BrowserCountChangeNotificationObserver(target_count, this, reply_message);
1518 void TestingAutomationProvider::GoBackBlockUntilNavigationsComplete(
1519 int handle, int number_of_navigations, IPC::Message* reply_message) {
1520 if (tab_tracker_->ContainsHandle(handle)) {
1521 NavigationController* tab = tab_tracker_->GetResource(handle);
1522 Browser* browser = FindAndActivateTab(tab);
1523 if (chrome::IsCommandEnabled(browser, IDC_BACK)) {
1524 new NavigationNotificationObserver(tab, this, reply_message,
1525 number_of_navigations, false, false);
1526 chrome::ExecuteCommand(browser, IDC_BACK);
1527 return;
1531 AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams(
1532 reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
1533 Send(reply_message);
1536 void TestingAutomationProvider::GoForwardBlockUntilNavigationsComplete(
1537 int handle, int number_of_navigations, IPC::Message* reply_message) {
1538 if (tab_tracker_->ContainsHandle(handle)) {
1539 NavigationController* tab = tab_tracker_->GetResource(handle);
1540 Browser* browser = FindAndActivateTab(tab);
1541 if (chrome::IsCommandEnabled(browser, IDC_FORWARD)) {
1542 new NavigationNotificationObserver(tab, this, reply_message,
1543 number_of_navigations, false, false);
1544 chrome::ExecuteCommand(browser, IDC_FORWARD);
1545 return;
1549 AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams(
1550 reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
1551 Send(reply_message);
1554 void TestingAutomationProvider::BuildJSONHandlerMaps() {
1555 // Map json commands to their handlers.
1556 handler_map_["ApplyAccelerator"] =
1557 &TestingAutomationProvider::ExecuteBrowserCommandAsyncJSON;
1558 handler_map_["RunCommand"] =
1559 &TestingAutomationProvider::ExecuteBrowserCommandJSON;
1560 handler_map_["IsMenuCommandEnabled"] =
1561 &TestingAutomationProvider::IsMenuCommandEnabledJSON;
1562 handler_map_["ActivateTab"] =
1563 &TestingAutomationProvider::ActivateTabJSON;
1564 handler_map_["BringBrowserToFront"] =
1565 &TestingAutomationProvider::BringBrowserToFrontJSON;
1566 handler_map_["GetIndicesFromTab"] =
1567 &TestingAutomationProvider::GetIndicesFromTab;
1568 handler_map_["NavigateToURL"] =
1569 &TestingAutomationProvider::NavigateToURL;
1570 handler_map_["GetActiveTabIndex"] =
1571 &TestingAutomationProvider::GetActiveTabIndexJSON;
1572 handler_map_["AppendTab"] =
1573 &TestingAutomationProvider::AppendTabJSON;
1574 handler_map_["OpenNewBrowserWindow"] =
1575 &TestingAutomationProvider::OpenNewBrowserWindow;
1576 handler_map_["CloseBrowserWindow"] =
1577 &TestingAutomationProvider::CloseBrowserWindow;
1578 handler_map_["WaitUntilNavigationCompletes"] =
1579 &TestingAutomationProvider::WaitUntilNavigationCompletes;
1580 handler_map_["GetLocalStatePrefsInfo"] =
1581 &TestingAutomationProvider::GetLocalStatePrefsInfo;
1582 handler_map_["SetLocalStatePrefs"] =
1583 &TestingAutomationProvider::SetLocalStatePrefs;
1584 handler_map_["GetPrefsInfo"] = &TestingAutomationProvider::GetPrefsInfo;
1585 handler_map_["SetPrefs"] = &TestingAutomationProvider::SetPrefs;
1586 handler_map_["ExecuteJavascript"] =
1587 &TestingAutomationProvider::ExecuteJavascriptJSON;
1588 handler_map_["AddDomEventObserver"] =
1589 &TestingAutomationProvider::AddDomEventObserver;
1590 handler_map_["RemoveEventObserver"] =
1591 &TestingAutomationProvider::RemoveEventObserver;
1592 handler_map_["GetNextEvent"] =
1593 &TestingAutomationProvider::GetNextEvent;
1594 handler_map_["ClearEventQueue"] =
1595 &TestingAutomationProvider::ClearEventQueue;
1596 handler_map_["ExecuteJavascriptInRenderView"] =
1597 &TestingAutomationProvider::ExecuteJavascriptInRenderView;
1598 handler_map_["GoForward"] =
1599 &TestingAutomationProvider::GoForward;
1600 handler_map_["GoBack"] =
1601 &TestingAutomationProvider::GoBack;
1602 handler_map_["Reload"] =
1603 &TestingAutomationProvider::ReloadJSON;
1604 handler_map_["OpenFindInPage"] =
1605 &TestingAutomationProvider::OpenFindInPage;
1606 handler_map_["IsFindInPageVisible"] =
1607 &TestingAutomationProvider::IsFindInPageVisible;
1608 handler_map_["SetDownloadShelfVisible"] =
1609 &TestingAutomationProvider::SetDownloadShelfVisibleJSON;
1610 handler_map_["IsDownloadShelfVisible"] =
1611 &TestingAutomationProvider::IsDownloadShelfVisibleJSON;
1612 handler_map_["GetDownloadDirectory"] =
1613 &TestingAutomationProvider::GetDownloadDirectoryJSON;
1614 handler_map_["GetCookies"] =
1615 &TestingAutomationProvider::GetCookiesJSON;
1616 handler_map_["DeleteCookie"] =
1617 &TestingAutomationProvider::DeleteCookieJSON;
1618 handler_map_["SetCookie"] =
1619 &TestingAutomationProvider::SetCookieJSON;
1620 handler_map_["GetCookiesInBrowserContext"] =
1621 &TestingAutomationProvider::GetCookiesInBrowserContext;
1622 handler_map_["DeleteCookieInBrowserContext"] =
1623 &TestingAutomationProvider::DeleteCookieInBrowserContext;
1624 handler_map_["SetCookieInBrowserContext"] =
1625 &TestingAutomationProvider::SetCookieInBrowserContext;
1627 handler_map_["WaitForBookmarkModelToLoad"] =
1628 &TestingAutomationProvider::WaitForBookmarkModelToLoadJSON;
1629 handler_map_["GetBookmarksAsJSON"] =
1630 &TestingAutomationProvider::GetBookmarksAsJSON;
1631 handler_map_["GetBookmarkBarStatus"] =
1632 &TestingAutomationProvider::GetBookmarkBarStatus;
1633 handler_map_["AddBookmark"] =
1634 &TestingAutomationProvider::AddBookmark;
1635 handler_map_["ReparentBookmark"] =
1636 &TestingAutomationProvider::ReparentBookmark;
1637 handler_map_["SetBookmarkTitle"] =
1638 &TestingAutomationProvider::SetBookmarkTitle;
1639 handler_map_["SetBookmarkURL"] =
1640 &TestingAutomationProvider::SetBookmarkURL;
1641 handler_map_["RemoveBookmark"] =
1642 &TestingAutomationProvider::RemoveBookmark;
1644 handler_map_["GetTabIds"] =
1645 &TestingAutomationProvider::GetTabIds;
1646 handler_map_["IsTabIdValid"] =
1647 &TestingAutomationProvider::IsTabIdValid;
1648 handler_map_["CloseTab"] =
1649 &TestingAutomationProvider::CloseTabJSON;
1650 handler_map_["SetViewBounds"] =
1651 &TestingAutomationProvider::SetViewBounds;
1652 handler_map_["MaximizeView"] =
1653 &TestingAutomationProvider::MaximizeView;
1654 handler_map_["WebkitMouseMove"] =
1655 &TestingAutomationProvider::WebkitMouseMove;
1656 handler_map_["WebkitMouseClick"] =
1657 &TestingAutomationProvider::WebkitMouseClick;
1658 handler_map_["WebkitMouseDrag"] =
1659 &TestingAutomationProvider::WebkitMouseDrag;
1660 handler_map_["WebkitMouseButtonUp"] =
1661 &TestingAutomationProvider::WebkitMouseButtonUp;
1662 handler_map_["WebkitMouseButtonDown"] =
1663 &TestingAutomationProvider::WebkitMouseButtonDown;
1664 handler_map_["WebkitMouseDoubleClick"] =
1665 &TestingAutomationProvider::WebkitMouseDoubleClick;
1666 handler_map_["DragAndDropFilePaths"] =
1667 &TestingAutomationProvider::DragAndDropFilePaths;
1668 handler_map_["SendWebkitKeyEvent"] =
1669 &TestingAutomationProvider::SendWebkitKeyEvent;
1670 handler_map_["ActivateTab"] =
1671 &TestingAutomationProvider::ActivateTabJSON;
1672 handler_map_["GetAppModalDialogMessage"] =
1673 &TestingAutomationProvider::GetAppModalDialogMessage;
1674 handler_map_["AcceptOrDismissAppModalDialog"] =
1675 &TestingAutomationProvider::AcceptOrDismissAppModalDialog;
1676 handler_map_["ActionOnSSLBlockingPage"] =
1677 &TestingAutomationProvider::ActionOnSSLBlockingPage;
1678 handler_map_["GetSecurityState"] =
1679 &TestingAutomationProvider::GetSecurityState;
1680 handler_map_["IsPageActionVisible"] =
1681 &TestingAutomationProvider::IsPageActionVisible;
1682 handler_map_["CreateNewAutomationProvider"] =
1683 &TestingAutomationProvider::CreateNewAutomationProvider;
1684 handler_map_["GetBrowserWindowCount"] =
1685 &TestingAutomationProvider::GetBrowserWindowCountJSON;
1686 handler_map_["GetBrowserInfo"] =
1687 &TestingAutomationProvider::GetBrowserInfo;
1688 handler_map_["GetTabInfo"] =
1689 &TestingAutomationProvider::GetTabInfo;
1690 handler_map_["GetTabCount"] =
1691 &TestingAutomationProvider::GetTabCountJSON;
1692 handler_map_["OpenNewBrowserWindowWithNewProfile"] =
1693 &TestingAutomationProvider::OpenNewBrowserWindowWithNewProfile;
1694 handler_map_["GetMultiProfileInfo"] =
1695 &TestingAutomationProvider::GetMultiProfileInfo;
1696 handler_map_["OpenProfileWindow"] =
1697 &TestingAutomationProvider::OpenProfileWindow;
1698 handler_map_["GetProcessInfo"] =
1699 &TestingAutomationProvider::GetProcessInfo;
1700 handler_map_["RefreshPolicies"] =
1701 &TestingAutomationProvider::RefreshPolicies;
1702 handler_map_["InstallExtension"] =
1703 &TestingAutomationProvider::InstallExtension;
1704 handler_map_["GetExtensionsInfo"] =
1705 &TestingAutomationProvider::GetExtensionsInfo;
1706 handler_map_["UninstallExtensionById"] =
1707 &TestingAutomationProvider::UninstallExtensionById;
1708 handler_map_["SetExtensionStateById"] =
1709 &TestingAutomationProvider::SetExtensionStateById;
1710 handler_map_["TriggerPageActionById"] =
1711 &TestingAutomationProvider::TriggerPageActionById;
1712 handler_map_["TriggerBrowserActionById"] =
1713 &TestingAutomationProvider::TriggerBrowserActionById;
1714 handler_map_["UpdateExtensionsNow"] =
1715 &TestingAutomationProvider::UpdateExtensionsNow;
1716 handler_map_["OverrideGeoposition"] =
1717 &TestingAutomationProvider::OverrideGeoposition;
1718 handler_map_["SimulateAsanMemoryBug"] =
1719 &TestingAutomationProvider::SimulateAsanMemoryBug;
1721 #if defined(OS_CHROMEOS)
1722 handler_map_["AcceptOOBENetworkScreen"] =
1723 &TestingAutomationProvider::AcceptOOBENetworkScreen;
1724 handler_map_["AcceptOOBEEula"] = &TestingAutomationProvider::AcceptOOBEEula;
1725 handler_map_["CancelOOBEUpdate"] =
1726 &TestingAutomationProvider::CancelOOBEUpdate;
1727 handler_map_["PickUserImage"] = &TestingAutomationProvider::PickUserImage;
1728 handler_map_["SkipToLogin"] = &TestingAutomationProvider::SkipToLogin;
1729 handler_map_["GetOOBEScreenInfo"] =
1730 &TestingAutomationProvider::GetOOBEScreenInfo;
1732 handler_map_["GetLoginInfo"] = &TestingAutomationProvider::GetLoginInfo;
1733 handler_map_["ShowCreateAccountUI"] =
1734 &TestingAutomationProvider::ShowCreateAccountUI;
1735 handler_map_["ExecuteJavascriptInOOBEWebUI"] =
1736 &TestingAutomationProvider::ExecuteJavascriptInOOBEWebUI;
1737 handler_map_["LoginAsGuest"] = &TestingAutomationProvider::LoginAsGuest;
1738 handler_map_["SubmitLoginForm"] =
1739 &TestingAutomationProvider::SubmitLoginForm;
1740 handler_map_["AddLoginEventObserver"] =
1741 &TestingAutomationProvider::AddLoginEventObserver;
1742 handler_map_["SignOut"] = &TestingAutomationProvider::SignOut;
1744 handler_map_["LockScreen"] = &TestingAutomationProvider::LockScreen;
1745 handler_map_["UnlockScreen"] = &TestingAutomationProvider::UnlockScreen;
1746 handler_map_["SignoutInScreenLocker"] =
1747 &TestingAutomationProvider::SignoutInScreenLocker;
1749 handler_map_["GetBatteryInfo"] = &TestingAutomationProvider::GetBatteryInfo;
1751 handler_map_["EnableSpokenFeedback"] =
1752 &TestingAutomationProvider::EnableSpokenFeedback;
1753 handler_map_["IsSpokenFeedbackEnabled"] =
1754 &TestingAutomationProvider::IsSpokenFeedbackEnabled;
1756 handler_map_["GetTimeInfo"] = &TestingAutomationProvider::GetTimeInfo;
1757 handler_map_["SetTimezone"] = &TestingAutomationProvider::SetTimezone;
1759 handler_map_["UpdateCheck"] = &TestingAutomationProvider::UpdateCheck;
1761 handler_map_["GetVolumeInfo"] = &TestingAutomationProvider::GetVolumeInfo;
1762 handler_map_["SetVolume"] = &TestingAutomationProvider::SetVolume;
1763 handler_map_["SetMute"] = &TestingAutomationProvider::SetMute;
1765 handler_map_["OpenCrosh"] = &TestingAutomationProvider::OpenCrosh;
1767 browser_handler_map_["GetTimeInfo"] =
1768 &TestingAutomationProvider::GetTimeInfo;
1769 #endif // defined(OS_CHROMEOS)
1771 browser_handler_map_["DisablePlugin"] =
1772 &TestingAutomationProvider::DisablePlugin;
1773 browser_handler_map_["EnablePlugin"] =
1774 &TestingAutomationProvider::EnablePlugin;
1775 browser_handler_map_["GetPluginsInfo"] =
1776 &TestingAutomationProvider::GetPluginsInfo;
1778 browser_handler_map_["GetNavigationInfo"] =
1779 &TestingAutomationProvider::GetNavigationInfo;
1781 browser_handler_map_["PerformActionOnInfobar"] =
1782 &TestingAutomationProvider::PerformActionOnInfobar;
1784 browser_handler_map_["GetHistoryInfo"] =
1785 &TestingAutomationProvider::GetHistoryInfo;
1787 browser_handler_map_["GetOmniboxInfo"] =
1788 &TestingAutomationProvider::GetOmniboxInfo;
1789 browser_handler_map_["SetOmniboxText"] =
1790 &TestingAutomationProvider::SetOmniboxText;
1791 browser_handler_map_["OmniboxAcceptInput"] =
1792 &TestingAutomationProvider::OmniboxAcceptInput;
1793 browser_handler_map_["OmniboxMovePopupSelection"] =
1794 &TestingAutomationProvider::OmniboxMovePopupSelection;
1796 browser_handler_map_["LoadSearchEngineInfo"] =
1797 &TestingAutomationProvider::LoadSearchEngineInfo;
1798 browser_handler_map_["GetSearchEngineInfo"] =
1799 &TestingAutomationProvider::GetSearchEngineInfo;
1800 browser_handler_map_["AddOrEditSearchEngine"] =
1801 &TestingAutomationProvider::AddOrEditSearchEngine;
1802 browser_handler_map_["PerformActionOnSearchEngine"] =
1803 &TestingAutomationProvider::PerformActionOnSearchEngine;
1805 browser_handler_map_["SetWindowDimensions"] =
1806 &TestingAutomationProvider::SetWindowDimensions;
1808 browser_handler_map_["GetDownloadsInfo"] =
1809 &TestingAutomationProvider::GetDownloadsInfo;
1810 browser_handler_map_["WaitForAllDownloadsToComplete"] =
1811 &TestingAutomationProvider::WaitForAllDownloadsToComplete;
1812 browser_handler_map_["PerformActionOnDownload"] =
1813 &TestingAutomationProvider::PerformActionOnDownload;
1815 browser_handler_map_["GetInitialLoadTimes"] =
1816 &TestingAutomationProvider::GetInitialLoadTimes;
1818 browser_handler_map_["SaveTabContents"] =
1819 &TestingAutomationProvider::SaveTabContents;
1821 browser_handler_map_["AddSavedPassword"] =
1822 &TestingAutomationProvider::AddSavedPassword;
1823 browser_handler_map_["RemoveSavedPassword"] =
1824 &TestingAutomationProvider::RemoveSavedPassword;
1825 browser_handler_map_["GetSavedPasswords"] =
1826 &TestingAutomationProvider::GetSavedPasswords;
1828 browser_handler_map_["FindInPage"] = &TestingAutomationProvider::FindInPage;
1830 browser_handler_map_["GetAllNotifications"] =
1831 &TestingAutomationProvider::GetAllNotifications;
1832 browser_handler_map_["CloseNotification"] =
1833 &TestingAutomationProvider::CloseNotification;
1834 browser_handler_map_["WaitForNotificationCount"] =
1835 &TestingAutomationProvider::WaitForNotificationCount;
1837 browser_handler_map_["GetNTPInfo"] =
1838 &TestingAutomationProvider::GetNTPInfo;
1839 browser_handler_map_["RemoveNTPMostVisitedThumbnail"] =
1840 &TestingAutomationProvider::RemoveNTPMostVisitedThumbnail;
1841 browser_handler_map_["RestoreAllNTPMostVisitedThumbnails"] =
1842 &TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails;
1844 browser_handler_map_["KillRendererProcess"] =
1845 &TestingAutomationProvider::KillRendererProcess;
1847 browser_handler_map_["LaunchApp"] = &TestingAutomationProvider::LaunchApp;
1848 browser_handler_map_["SetAppLaunchType"] =
1849 &TestingAutomationProvider::SetAppLaunchType;
1851 browser_handler_map_["GetV8HeapStats"] =
1852 &TestingAutomationProvider::GetV8HeapStats;
1853 browser_handler_map_["GetFPS"] =
1854 &TestingAutomationProvider::GetFPS;
1856 browser_handler_map_["IsFullscreenForBrowser"] =
1857 &TestingAutomationProvider::IsFullscreenForBrowser;
1858 browser_handler_map_["IsFullscreenForTab"] =
1859 &TestingAutomationProvider::IsFullscreenForTab;
1860 browser_handler_map_["IsMouseLocked"] =
1861 &TestingAutomationProvider::IsMouseLocked;
1862 browser_handler_map_["IsMouseLockPermissionRequested"] =
1863 &TestingAutomationProvider::IsMouseLockPermissionRequested;
1864 browser_handler_map_["IsFullscreenPermissionRequested"] =
1865 &TestingAutomationProvider::IsFullscreenPermissionRequested;
1866 browser_handler_map_["IsFullscreenBubbleDisplayed"] =
1867 &TestingAutomationProvider::IsFullscreenBubbleDisplayed;
1868 browser_handler_map_["IsFullscreenBubbleDisplayingButtons"] =
1869 &TestingAutomationProvider::IsFullscreenBubbleDisplayingButtons;
1870 browser_handler_map_["AcceptCurrentFullscreenOrMouseLockRequest"] =
1871 &TestingAutomationProvider::AcceptCurrentFullscreenOrMouseLockRequest;
1872 browser_handler_map_["DenyCurrentFullscreenOrMouseLockRequest"] =
1873 &TestingAutomationProvider::DenyCurrentFullscreenOrMouseLockRequest;
1876 scoped_ptr<base::DictionaryValue>
1877 TestingAutomationProvider::ParseJSONRequestCommand(
1878 const std::string& json_request,
1879 std::string* command,
1880 std::string* error) {
1881 scoped_ptr<base::DictionaryValue> dict_value;
1882 scoped_ptr<base::Value> values(
1883 base::JSONReader::ReadAndReturnError(json_request,
1884 base::JSON_ALLOW_TRAILING_COMMAS, NULL, error));
1885 if (values.get()) {
1886 // Make sure input is a dict with a string command.
1887 if (values->GetType() != base::Value::TYPE_DICTIONARY) {
1888 *error = "Command dictionary is not a dictionary.";
1889 } else {
1890 dict_value.reset(static_cast<base::DictionaryValue*>(values.release()));
1891 if (!dict_value->GetStringASCII("command", command)) {
1892 *error = "Command key string missing from dictionary.";
1893 dict_value.reset(NULL);
1897 return dict_value.Pass();
1900 void TestingAutomationProvider::SendJSONRequestWithBrowserHandle(
1901 int handle,
1902 const std::string& json_request,
1903 IPC::Message* reply_message) {
1904 Browser* browser = NULL;
1905 if (browser_tracker_->ContainsHandle(handle))
1906 browser = browser_tracker_->GetResource(handle);
1907 if (browser || handle < 0) {
1908 SendJSONRequest(browser, json_request, reply_message);
1909 } else {
1910 AutomationJSONReply(this, reply_message).SendError(
1911 "The browser window does not exist.");
1915 void TestingAutomationProvider::SendJSONRequestWithBrowserIndex(
1916 int index,
1917 const std::string& json_request,
1918 IPC::Message* reply_message) {
1919 Browser* browser = index < 0 ? NULL : automation_util::GetBrowserAt(index);
1920 if (!browser && index >= 0) {
1921 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
1922 "Browser window with index=%d does not exist.", index));
1923 } else {
1924 SendJSONRequest(browser, json_request, reply_message);
1928 void TestingAutomationProvider::SendJSONRequest(Browser* browser,
1929 const std::string& json_request,
1930 IPC::Message* reply_message) {
1931 std::string command, error_string;
1932 scoped_ptr<base::DictionaryValue> dict_value(
1933 ParseJSONRequestCommand(json_request, &command, &error_string));
1934 if (!dict_value.get() || command.empty()) {
1935 AutomationJSONReply(this, reply_message).SendError(error_string);
1936 return;
1939 if (handler_map_.empty() || browser_handler_map_.empty())
1940 BuildJSONHandlerMaps();
1942 // Look for command in handlers that take a Browser.
1943 if (browser_handler_map_.find(std::string(command)) !=
1944 browser_handler_map_.end() && browser) {
1945 (this->*browser_handler_map_[command])(browser, dict_value.get(),
1946 reply_message);
1947 // Look for command in handlers that don't take a Browser.
1948 } else if (handler_map_.find(std::string(command)) != handler_map_.end()) {
1949 (this->*handler_map_[command])(dict_value.get(), reply_message);
1950 // Command has no handler.
1951 } else {
1952 error_string = base::StringPrintf("Unknown command '%s'. Options: ",
1953 command.c_str());
1954 for (std::map<std::string, JsonHandler>::const_iterator it =
1955 handler_map_.begin(); it != handler_map_.end(); ++it) {
1956 error_string += it->first + ", ";
1958 for (std::map<std::string, BrowserJsonHandler>::const_iterator it =
1959 browser_handler_map_.begin(); it != browser_handler_map_.end(); ++it) {
1960 error_string += it->first + ", ";
1962 AutomationJSONReply(this, reply_message).SendError(error_string);
1966 void TestingAutomationProvider::BringBrowserToFrontJSON(
1967 base::DictionaryValue* args,
1968 IPC::Message* reply_message) {
1969 AutomationJSONReply reply(this, reply_message);
1970 Browser* browser;
1971 std::string error_msg;
1972 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
1973 reply.SendError(error_msg);
1974 return;
1976 browser->window()->Activate();
1977 reply.SendSuccess(NULL);
1980 // Sample json input: { "command": "SetWindowDimensions",
1981 // "x": 20, # optional
1982 // "y": 20, # optional
1983 // "width": 800, # optional
1984 // "height": 600 } # optional
1985 void TestingAutomationProvider::SetWindowDimensions(
1986 Browser* browser,
1987 base::DictionaryValue* args,
1988 IPC::Message* reply_message) {
1989 gfx::Rect rect = browser->window()->GetRestoredBounds();
1990 int x, y, width, height;
1991 if (args->GetInteger("x", &x))
1992 rect.set_x(x);
1993 if (args->GetInteger("y", &y))
1994 rect.set_y(y);
1995 if (args->GetInteger("width", &width))
1996 rect.set_width(width);
1997 if (args->GetInteger("height", &height))
1998 rect.set_height(height);
1999 browser->window()->SetBounds(rect);
2000 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
2003 base::ListValue* TestingAutomationProvider::GetInfobarsInfo(WebContents* wc) {
2004 // Each infobar may have different properties depending on the type.
2005 base::ListValue* infobars = new base::ListValue;
2006 InfoBarService* infobar_service = InfoBarService::FromWebContents(wc);
2007 for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
2008 base::DictionaryValue* infobar_item = new base::DictionaryValue;
2009 InfoBarDelegate* infobar = infobar_service->infobar_at(i)->delegate();
2010 switch (infobar->GetInfoBarAutomationType()) {
2011 case InfoBarDelegate::CONFIRM_INFOBAR:
2012 infobar_item->SetString("type", "confirm_infobar");
2013 break;
2014 case InfoBarDelegate::PASSWORD_INFOBAR:
2015 infobar_item->SetString("type", "password_infobar");
2016 break;
2017 case InfoBarDelegate::RPH_INFOBAR:
2018 infobar_item->SetString("type", "rph_infobar");
2019 break;
2020 case InfoBarDelegate::UNKNOWN_INFOBAR:
2021 infobar_item->SetString("type", "unknown_infobar");
2022 break;
2024 if (infobar->AsConfirmInfoBarDelegate()) {
2025 // Also covers ThemeInstalledInfoBarDelegate.
2026 ConfirmInfoBarDelegate* confirm_infobar =
2027 infobar->AsConfirmInfoBarDelegate();
2028 infobar_item->SetString("text", confirm_infobar->GetMessageText());
2029 infobar_item->SetString("link_text", confirm_infobar->GetLinkText());
2030 base::ListValue* buttons_list = new base::ListValue;
2031 int buttons = confirm_infobar->GetButtons();
2032 if (buttons & ConfirmInfoBarDelegate::BUTTON_OK) {
2033 base::StringValue* button_label = new base::StringValue(
2034 confirm_infobar->GetButtonLabel(
2035 ConfirmInfoBarDelegate::BUTTON_OK));
2036 buttons_list->Append(button_label);
2038 if (buttons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
2039 base::StringValue* button_label = new base::StringValue(
2040 confirm_infobar->GetButtonLabel(
2041 ConfirmInfoBarDelegate::BUTTON_CANCEL));
2042 buttons_list->Append(button_label);
2044 infobar_item->Set("buttons", buttons_list);
2045 } else if (infobar->AsExtensionInfoBarDelegate()) {
2046 infobar_item->SetString("type", "extension_infobar");
2047 } else {
2048 infobar_item->SetString("type", "unknown_infobar");
2050 infobars->Append(infobar_item);
2052 return infobars;
2055 // Sample json input: { "command": "PerformActionOnInfobar",
2056 // "action": "dismiss",
2057 // "infobar_index": 0,
2058 // "tab_index": 0 }
2059 // Sample output: {}
2060 void TestingAutomationProvider::PerformActionOnInfobar(
2061 Browser* browser,
2062 base::DictionaryValue* args,
2063 IPC::Message* reply_message) {
2064 AutomationJSONReply reply(this, reply_message);
2065 int tab_index;
2066 int infobar_index_int;
2067 std::string action;
2068 if (!args->GetInteger("tab_index", &tab_index) ||
2069 !args->GetInteger("infobar_index", &infobar_index_int) ||
2070 !args->GetString("action", &action)) {
2071 reply.SendError("Invalid or missing args");
2072 return;
2074 size_t infobar_index = static_cast<size_t>(infobar_index_int);
2076 WebContents* web_contents =
2077 browser->tab_strip_model()->GetWebContentsAt(tab_index);
2078 if (!web_contents) {
2079 reply.SendError(base::StringPrintf("No such tab at index %d", tab_index));
2080 return;
2083 InfoBarService* infobar_service =
2084 InfoBarService::FromWebContents(web_contents);
2085 if (infobar_index >= infobar_service->infobar_count()) {
2086 reply.SendError(base::StringPrintf("No such infobar at index %" PRIuS,
2087 infobar_index));
2088 return;
2090 InfoBar* infobar = infobar_service->infobar_at(infobar_index);
2091 InfoBarDelegate* infobar_delegate = infobar->delegate();
2093 if (action == "dismiss") {
2094 infobar_delegate->InfoBarDismissed();
2095 infobar_service->RemoveInfoBar(infobar);
2096 reply.SendSuccess(NULL);
2097 return;
2099 if ((action == "accept") || (action == "cancel")) {
2100 ConfirmInfoBarDelegate* confirm_infobar_delegate =
2101 infobar_delegate->AsConfirmInfoBarDelegate();
2102 if (!confirm_infobar_delegate) {
2103 reply.SendError("Not a confirm infobar");
2104 return;
2106 if ((action == "accept") ?
2107 confirm_infobar_delegate->Accept() : confirm_infobar_delegate->Cancel())
2108 infobar_service->RemoveInfoBar(infobar);
2109 reply.SendSuccess(NULL);
2110 return;
2113 reply.SendError("Invalid action");
2116 namespace {
2118 // Gets info about BrowserChildProcessHost. Must run on IO thread to
2119 // honor the semantics of BrowserChildProcessHostIterator.
2120 // Used by AutomationProvider::GetBrowserInfo().
2121 void GetChildProcessHostInfo(base::ListValue* child_processes) {
2122 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
2123 // Only add processes which are already started, since we need their handle.
2124 if (iter.GetData().handle == base::kNullProcessHandle)
2125 continue;
2126 base::DictionaryValue* item = new base::DictionaryValue;
2127 item->SetString("name", iter.GetData().name);
2128 item->SetString(
2129 "type",
2130 content::GetProcessTypeNameInEnglish(iter.GetData().process_type));
2131 item->SetInteger("pid", base::GetProcId(iter.GetData().handle));
2132 child_processes->Append(item);
2136 } // namespace
2138 // Sample json input: { "command": "GetBrowserInfo" }
2139 // Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for
2140 // sample json output.
2141 void TestingAutomationProvider::GetBrowserInfo(
2142 base::DictionaryValue* args,
2143 IPC::Message* reply_message) {
2144 base::ThreadRestrictions::ScopedAllowIO allow_io; // needed for PathService
2145 base::DictionaryValue* properties = new base::DictionaryValue;
2146 properties->SetString("ChromeVersion", chrome::kChromeVersion);
2147 properties->SetString("BrowserProcessExecutableName",
2148 chrome::kBrowserProcessExecutableName);
2149 properties->SetString("HelperProcessExecutableName",
2150 chrome::kHelperProcessExecutableName);
2151 properties->SetString("BrowserProcessExecutablePath",
2152 chrome::kBrowserProcessExecutablePath);
2153 properties->SetString("HelperProcessExecutablePath",
2154 chrome::kHelperProcessExecutablePath);
2155 properties->SetString("command_line_string",
2156 CommandLine::ForCurrentProcess()->GetCommandLineString());
2157 base::FilePath dumps_path;
2158 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
2159 properties->SetString("DIR_CRASH_DUMPS", dumps_path.value());
2160 #if defined(USE_AURA)
2161 properties->SetBoolean("aura", true);
2162 #else
2163 properties->SetBoolean("aura", false);
2164 #endif
2166 std::string branding;
2167 #if defined(GOOGLE_CHROME_BUILD)
2168 branding = "Google Chrome";
2169 #elif defined(CHROMIUM_BUILD)
2170 branding = "Chromium";
2171 #else
2172 branding = "Unknown Branding";
2173 #endif
2174 properties->SetString("branding", branding);
2176 bool is_official_build = false;
2177 #if defined(OFFICIAL_BUILD)
2178 is_official_build = true;
2179 #endif
2180 properties->SetBoolean("is_official", is_official_build);
2182 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2183 return_value->Set("properties", properties);
2185 return_value->SetInteger("browser_pid", base::GetCurrentProcId());
2186 // Add info about all windows in a list of dictionaries, one dictionary
2187 // item per window.
2188 base::ListValue* windows = new base::ListValue;
2189 int windex = 0;
2191 for (chrome::BrowserIterator it; !it.done(); it.Next(), ++windex) {
2192 base::DictionaryValue* browser_item = new base::DictionaryValue;
2193 Browser* browser = *it;
2194 browser_item->SetInteger("index", windex);
2195 // Window properties
2196 gfx::Rect rect = browser->window()->GetRestoredBounds();
2197 browser_item->SetInteger("x", rect.x());
2198 browser_item->SetInteger("y", rect.y());
2199 browser_item->SetInteger("width", rect.width());
2200 browser_item->SetInteger("height", rect.height());
2201 browser_item->SetBoolean("fullscreen",
2202 browser->window()->IsFullscreen());
2203 base::ListValue* visible_page_actions = new base::ListValue;
2204 // Add info about all visible page actions. Skipped on panels, which do not
2205 // have a location bar.
2206 LocationBar* loc_bar = browser->window()->GetLocationBar();
2207 if (loc_bar) {
2208 LocationBarTesting* loc_bar_test =
2209 loc_bar->GetLocationBarForTesting();
2210 size_t page_action_visible_count =
2211 static_cast<size_t>(loc_bar_test->PageActionVisibleCount());
2212 for (size_t i = 0; i < page_action_visible_count; ++i) {
2213 base::StringValue* extension_id = new base::StringValue(
2214 loc_bar_test->GetVisiblePageAction(i)->extension_id());
2215 visible_page_actions->Append(extension_id);
2218 browser_item->Set("visible_page_actions", visible_page_actions);
2219 browser_item->SetInteger("selected_tab",
2220 browser->tab_strip_model()->active_index());
2221 browser_item->SetBoolean("incognito",
2222 browser->profile()->IsOffTheRecord());
2223 browser_item->SetString("profile_path",
2224 browser->profile()->GetPath().BaseName().MaybeAsASCII());
2225 std::string type;
2226 switch (browser->type()) {
2227 case Browser::TYPE_TABBED:
2228 type = "tabbed";
2229 break;
2230 case Browser::TYPE_POPUP:
2231 type = "popup";
2232 break;
2233 default:
2234 type = "unknown";
2235 break;
2237 browser_item->SetString("type", type);
2238 // For each window, add info about all tabs in a list of dictionaries,
2239 // one dictionary item per tab.
2240 base::ListValue* tabs = new base::ListValue;
2241 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
2242 WebContents* wc = browser->tab_strip_model()->GetWebContentsAt(i);
2243 base::DictionaryValue* tab = new base::DictionaryValue;
2244 tab->SetInteger("index", i);
2245 tab->SetString("url", wc->GetURL().spec());
2246 tab->SetInteger("renderer_pid",
2247 base::GetProcId(wc->GetRenderProcessHost()->GetHandle()));
2248 tab->Set("infobars", GetInfobarsInfo(wc));
2249 tab->SetBoolean("pinned", browser->tab_strip_model()->IsTabPinned(i));
2250 tabs->Append(tab);
2252 browser_item->Set("tabs", tabs);
2254 windows->Append(browser_item);
2256 return_value->Set("windows", windows);
2258 #if defined(OS_LINUX)
2259 int flags = ChildProcessHost::CHILD_ALLOW_SELF;
2260 #else
2261 int flags = ChildProcessHost::CHILD_NORMAL;
2262 #endif
2264 // Add all extension processes in a list of dictionaries, one dictionary
2265 // item per extension process.
2266 base::ListValue* extension_views = new base::ListValue;
2267 ProfileManager* profile_manager = g_browser_process->profile_manager();
2268 std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
2269 for (size_t i = 0; i < profiles.size(); ++i) {
2270 extensions::ProcessManager* process_manager =
2271 extensions::ExtensionSystem::Get(profiles[i])->process_manager();
2272 if (!process_manager)
2273 continue;
2274 const extensions::ProcessManager::ViewSet view_set =
2275 process_manager->GetAllViews();
2276 for (extensions::ProcessManager::ViewSet::const_iterator jt =
2277 view_set.begin();
2278 jt != view_set.end(); ++jt) {
2279 content::RenderViewHost* render_view_host = *jt;
2280 // Don't add dead extension processes.
2281 if (!render_view_host->IsRenderViewLive())
2282 continue;
2283 // Don't add views for which we can't obtain an extension.
2284 // TODO(benwells): work out why this happens. It only happens for one
2285 // test, and only on the bots.
2286 const Extension* extension =
2287 process_manager->GetExtensionForRenderViewHost(render_view_host);
2288 if (!extension)
2289 continue;
2290 base::DictionaryValue* item = new base::DictionaryValue;
2291 item->SetString("name", extension->name());
2292 item->SetString("extension_id", extension->id());
2293 item->SetInteger(
2294 "pid",
2295 base::GetProcId(render_view_host->GetProcess()->GetHandle()));
2296 base::DictionaryValue* view = new base::DictionaryValue;
2297 view->SetInteger(
2298 "render_process_id",
2299 render_view_host->GetProcess()->GetID());
2300 view->SetInteger(
2301 "render_view_id",
2302 render_view_host->GetRoutingID());
2303 item->Set("view", view);
2304 std::string type;
2305 WebContents* web_contents =
2306 WebContents::FromRenderViewHost(render_view_host);
2307 extensions::ViewType view_type = extensions::GetViewType(web_contents);
2308 switch (view_type) {
2309 case extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE:
2310 type = "EXTENSION_BACKGROUND_PAGE";
2311 break;
2312 case extensions::VIEW_TYPE_EXTENSION_POPUP:
2313 type = "EXTENSION_POPUP";
2314 break;
2315 case extensions::VIEW_TYPE_EXTENSION_INFOBAR:
2316 type = "EXTENSION_INFOBAR";
2317 break;
2318 case extensions::VIEW_TYPE_EXTENSION_DIALOG:
2319 type = "EXTENSION_DIALOG";
2320 break;
2321 case extensions::VIEW_TYPE_APP_SHELL:
2322 type = "APP_SHELL";
2323 break;
2324 case extensions::VIEW_TYPE_PANEL:
2325 type = "PANEL";
2326 break;
2327 default:
2328 type = "unknown";
2329 break;
2331 item->SetString("view_type", type);
2332 item->SetString("url", web_contents->GetURL().spec());
2333 item->SetBoolean("loaded", !render_view_host->IsLoading());
2334 extension_views->Append(item);
2337 return_value->Set("extension_views", extension_views);
2339 return_value->SetString("child_process_path",
2340 ChildProcessHost::GetChildPath(flags).value());
2341 // Child processes are the processes for plugins and other workers.
2342 // Add all child processes in a list of dictionaries, one dictionary item
2343 // per child process.
2344 base::ListValue* child_processes = new base::ListValue;
2345 return_value->Set("child_processes", child_processes);
2346 BrowserThread::PostTaskAndReply(
2347 BrowserThread::IO, FROM_HERE,
2348 base::Bind(&GetChildProcessHostInfo, child_processes),
2349 base::Bind(&AutomationJSONReply::SendSuccess,
2350 base::Owned(new AutomationJSONReply(this, reply_message)),
2351 base::Owned(return_value.release())));
2354 // Sample json input: { "command": "GetProcessInfo" }
2355 // Refer to GetProcessInfo() in chrome/test/pyautolib/pyauto.py for
2356 // sample json output.
2357 void TestingAutomationProvider::GetProcessInfo(
2358 base::DictionaryValue* args,
2359 IPC::Message* reply_message) {
2360 scoped_refptr<ProcessInfoObserver>
2361 proc_observer(new ProcessInfoObserver(this, reply_message));
2362 // TODO(jamescook): Maybe this shouldn't update UMA stats?
2363 proc_observer->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
2366 // Sample json input: { "command": "GetNavigationInfo" }
2367 // Refer to GetNavigationInfo() in chrome/test/pyautolib/pyauto.py for
2368 // sample json output.
2369 void TestingAutomationProvider::GetNavigationInfo(
2370 Browser* browser,
2371 base::DictionaryValue* args,
2372 IPC::Message* reply_message) {
2373 AutomationJSONReply reply(this, reply_message);
2374 int tab_index;
2375 WebContents* web_contents = NULL;
2376 if (!args->GetInteger("tab_index", &tab_index) ||
2377 !(web_contents =
2378 browser->tab_strip_model()->GetWebContentsAt(tab_index))) {
2379 reply.SendError("tab_index missing or invalid.");
2380 return;
2382 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2383 const NavigationController& controller = web_contents->GetController();
2384 NavigationEntry* nav_entry = controller.GetActiveEntry();
2385 DCHECK(nav_entry);
2387 // Security info.
2388 base::DictionaryValue* ssl = new base::DictionaryValue;
2389 std::map<content::SecurityStyle, std::string> style_to_string;
2390 style_to_string[content::SECURITY_STYLE_UNKNOWN] = "SECURITY_STYLE_UNKNOWN";
2391 style_to_string[content::SECURITY_STYLE_UNAUTHENTICATED] =
2392 "SECURITY_STYLE_UNAUTHENTICATED";
2393 style_to_string[content::SECURITY_STYLE_AUTHENTICATION_BROKEN] =
2394 "SECURITY_STYLE_AUTHENTICATION_BROKEN";
2395 style_to_string[content::SECURITY_STYLE_AUTHENTICATED] =
2396 "SECURITY_STYLE_AUTHENTICATED";
2398 SSLStatus ssl_status = nav_entry->GetSSL();
2399 ssl->SetString("security_style",
2400 style_to_string[ssl_status.security_style]);
2401 ssl->SetBoolean("ran_insecure_content",
2402 !!(ssl_status.content_status & SSLStatus::RAN_INSECURE_CONTENT));
2403 ssl->SetBoolean("displayed_insecure_content",
2404 !!(ssl_status.content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT));
2405 return_value->Set("ssl", ssl);
2407 // Page type.
2408 std::map<content::PageType, std::string> pagetype_to_string;
2409 pagetype_to_string[content::PAGE_TYPE_NORMAL] = "NORMAL_PAGE";
2410 pagetype_to_string[content::PAGE_TYPE_ERROR] = "ERROR_PAGE";
2411 pagetype_to_string[content::PAGE_TYPE_INTERSTITIAL] =
2412 "INTERSTITIAL_PAGE";
2413 return_value->SetString("page_type",
2414 pagetype_to_string[nav_entry->GetPageType()]);
2416 return_value->SetString("favicon_url", nav_entry->GetFavicon().url.spec());
2417 reply.SendSuccess(return_value.get());
2420 // Sample json input: { "command": "GetHistoryInfo",
2421 // "search_text": "some text" }
2422 // Refer chrome/test/pyautolib/history_info.py for sample json output.
2423 void TestingAutomationProvider::GetHistoryInfo(Browser* browser,
2424 base::DictionaryValue* args,
2425 IPC::Message* reply_message) {
2426 consumer_.CancelAllRequests();
2428 base::string16 search_text;
2429 args->GetString("search_text", &search_text);
2431 // Fetch history.
2432 HistoryService* hs = HistoryServiceFactory::GetForProfile(
2433 browser->profile(), Profile::EXPLICIT_ACCESS);
2434 history::QueryOptions options;
2435 // The observer owns itself. It deletes itself after it fetches history.
2436 AutomationProviderHistoryObserver* history_observer =
2437 new AutomationProviderHistoryObserver(this, reply_message);
2438 hs->QueryHistory(
2439 search_text,
2440 options,
2441 &consumer_,
2442 base::Bind(&AutomationProviderHistoryObserver::HistoryQueryComplete,
2443 base::Unretained(history_observer)));
2446 // Sample json input: { "command": "GetDownloadsInfo" }
2447 // Refer chrome/test/pyautolib/download_info.py for sample json output.
2448 void TestingAutomationProvider::GetDownloadsInfo(Browser* browser,
2449 base::DictionaryValue* args,
2450 IPC::Message* reply_message) {
2451 AutomationJSONReply reply(this, reply_message);
2452 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2453 base::ListValue* list_of_downloads = new base::ListValue;
2455 DownloadService* download_service(
2456 DownloadServiceFactory::GetForBrowserContext(browser->profile()));
2458 if (download_service->HasCreatedDownloadManager()) {
2459 std::vector<DownloadItem*> downloads;
2460 BrowserContext::GetDownloadManager(browser->profile())->GetAllDownloads(
2461 &downloads);
2463 for (std::vector<DownloadItem*>::iterator it = downloads.begin();
2464 it != downloads.end();
2465 it++) { // Fill info about each download item.
2466 list_of_downloads->Append(GetDictionaryFromDownloadItem(
2467 *it, browser->profile()->IsOffTheRecord()));
2470 return_value->Set("downloads", list_of_downloads);
2471 reply.SendSuccess(return_value.get());
2474 void TestingAutomationProvider::WaitForAllDownloadsToComplete(
2475 Browser* browser,
2476 base::DictionaryValue* args,
2477 IPC::Message* reply_message) {
2478 base::ListValue* pre_download_ids = NULL;
2480 if (!args->GetList("pre_download_ids", &pre_download_ids)) {
2481 AutomationJSONReply(this, reply_message)
2482 .SendError(
2483 base::StringPrintf("List of IDs of previous downloads required."));
2484 return;
2487 DownloadService* download_service =
2488 DownloadServiceFactory::GetForBrowserContext(browser->profile());
2489 if (!download_service->HasCreatedDownloadManager()) {
2490 // No download manager, so no downloads to wait for.
2491 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
2492 return;
2495 // This observer will delete itself.
2496 new AllDownloadsCompleteObserver(
2497 this, reply_message,
2498 BrowserContext::GetDownloadManager(browser->profile()),
2499 pre_download_ids);
2502 // See PerformActionOnDownload() in chrome/test/pyautolib/pyauto.py for sample
2503 // json input and output.
2504 void TestingAutomationProvider::PerformActionOnDownload(
2505 Browser* browser,
2506 base::DictionaryValue* args,
2507 IPC::Message* reply_message) {
2508 int id;
2509 std::string action;
2511 DownloadService* download_service =
2512 DownloadServiceFactory::GetForBrowserContext(browser->profile());
2513 if (!download_service->HasCreatedDownloadManager()) {
2514 AutomationJSONReply(this, reply_message).SendError("No download manager.");
2515 return;
2517 if (!args->GetInteger("id", &id) || !args->GetString("action", &action)) {
2518 AutomationJSONReply(this, reply_message)
2519 .SendError("Must include int id and string action.");
2520 return;
2523 DownloadManager* download_manager =
2524 BrowserContext::GetDownloadManager(browser->profile());
2525 DownloadItem* selected_item = download_manager->GetDownload(id);
2526 if (!selected_item) {
2527 AutomationJSONReply(this, reply_message)
2528 .SendError(base::StringPrintf("No download with an id of %d\n", id));
2529 return;
2532 DownloadItem::DownloadState download_state = selected_item->GetState();
2534 // We need to be IN_PROGRESS for these actions.
2535 if ((action == "pause" || action == "resume" || action == "cancel") &&
2536 download_state != DownloadItem::IN_PROGRESS) {
2537 AutomationJSONReply(this, reply_message)
2538 .SendError(base::StringPrintf(
2539 "Action '%s' called on download that is not in progress.",
2540 action.c_str()));
2541 return;
2544 if (action == "open") {
2545 selected_item->AddObserver(
2546 new AutomationProviderDownloadUpdatedObserver(
2547 this, reply_message, true, browser->profile()->IsOffTheRecord()));
2548 selected_item->OpenDownload();
2549 } else if (action == "toggle_open_files_like_this") {
2550 DownloadPrefs* prefs =
2551 DownloadPrefs::FromBrowserContext(selected_item->GetBrowserContext());
2552 base::FilePath path = selected_item->GetTargetFilePath();
2553 if (!selected_item->ShouldOpenFileBasedOnExtension())
2554 prefs->EnableAutoOpenBasedOnExtension(path);
2555 else
2556 prefs->DisableAutoOpenBasedOnExtension(path);
2557 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
2558 } else if (action == "remove") {
2559 new AutomationProviderDownloadModelChangedObserver(
2560 this, reply_message, download_manager);
2561 selected_item->Remove();
2562 } else if (action == "decline_dangerous_download") {
2563 new AutomationProviderDownloadModelChangedObserver(
2564 this, reply_message, download_manager);
2565 selected_item->Remove();
2566 } else if (action == "save_dangerous_download") {
2567 selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
2568 this, reply_message, false, browser->profile()->IsOffTheRecord()));
2569 selected_item->ValidateDangerousDownload();
2570 } else if (action == "pause") {
2571 if (selected_item->IsPaused()) {
2572 // Action would be a no-op; respond right from here. No-op implies
2573 // the test is poorly written or failing, so make it an error return.
2574 AutomationJSONReply(this, reply_message)
2575 .SendError("Action 'pause' called on already paused download.");
2576 } else {
2577 selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
2578 this, reply_message, false, browser->profile()->IsOffTheRecord()));
2579 selected_item->Pause();
2581 } else if (action == "resume") {
2582 if (!selected_item->IsPaused()) {
2583 // Action would be a no-op; respond right from here. No-op implies
2584 // the test is poorly written or failing, so make it an error return.
2585 AutomationJSONReply(this, reply_message)
2586 .SendError("Action 'resume' called on unpaused download.");
2587 } else {
2588 selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
2589 this, reply_message, false, browser->profile()->IsOffTheRecord()));
2590 selected_item->Resume();
2592 } else if (action == "cancel") {
2593 selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
2594 this, reply_message, false, browser->profile()->IsOffTheRecord()));
2595 selected_item->Cancel(true);
2596 } else {
2597 AutomationJSONReply(this, reply_message)
2598 .SendError(
2599 base::StringPrintf("Invalid action '%s' given.", action.c_str()));
2603 void TestingAutomationProvider::SetDownloadShelfVisibleJSON(
2604 base::DictionaryValue* args,
2605 IPC::Message* reply_message) {
2606 AutomationJSONReply reply(this, reply_message);
2607 Browser* browser;
2608 std::string error_msg;
2609 bool is_visible;
2610 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
2611 reply.SendError(error_msg);
2612 return;
2614 if (!args->GetBoolean("is_visible", &is_visible)) {
2615 reply.SendError("'is_visible' missing or invalid.");
2616 return;
2618 if (is_visible) {
2619 browser->window()->GetDownloadShelf()->Show();
2620 } else {
2621 browser->window()->GetDownloadShelf()->Close(DownloadShelf::AUTOMATIC);
2623 reply.SendSuccess(NULL);
2626 void TestingAutomationProvider::IsDownloadShelfVisibleJSON(
2627 base::DictionaryValue* args,
2628 IPC::Message* reply_message) {
2629 AutomationJSONReply reply(this, reply_message);
2630 Browser* browser;
2631 std::string error_msg;
2632 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
2633 reply.SendError(error_msg);
2634 return;
2636 base::DictionaryValue dict;
2637 dict.SetBoolean("is_visible", browser->window()->IsDownloadShelfVisible());
2638 reply.SendSuccess(&dict);
2641 void TestingAutomationProvider::GetDownloadDirectoryJSON(
2642 base::DictionaryValue* args,
2643 IPC::Message* reply_message) {
2644 AutomationJSONReply reply(this, reply_message);
2645 WebContents* web_contents;
2646 std::string error;
2647 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
2648 reply.SendError(error);
2649 return;
2651 DownloadManager* dlm =
2652 BrowserContext::GetDownloadManager(
2653 web_contents->GetController().GetBrowserContext());
2654 base::DictionaryValue dict;
2655 dict.SetString("path",
2656 DownloadPrefs::FromDownloadManager(dlm)->DownloadPath().value());
2657 reply.SendSuccess(&dict);
2660 // Sample JSON input { "command": "LoadSearchEngineInfo" }
2661 void TestingAutomationProvider::LoadSearchEngineInfo(
2662 Browser* browser,
2663 base::DictionaryValue* args,
2664 IPC::Message* reply_message) {
2665 TemplateURLService* url_model =
2666 TemplateURLServiceFactory::GetForProfile(browser->profile());
2667 if (url_model->loaded()) {
2668 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
2669 return;
2671 url_model->AddObserver(new AutomationProviderSearchEngineObserver(
2672 this, browser->profile(), reply_message));
2673 url_model->Load();
2676 // Sample JSON input { "command": "GetSearchEngineInfo" }
2677 // Refer to pyauto.py for sample output.
2678 void TestingAutomationProvider::GetSearchEngineInfo(
2679 Browser* browser,
2680 base::DictionaryValue* args,
2681 IPC::Message* reply_message) {
2682 TemplateURLService* url_model =
2683 TemplateURLServiceFactory::GetForProfile(browser->profile());
2684 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2685 base::ListValue* search_engines = new base::ListValue;
2686 TemplateURLService::TemplateURLVector template_urls =
2687 url_model->GetTemplateURLs();
2688 for (TemplateURLService::TemplateURLVector::const_iterator it =
2689 template_urls.begin(); it != template_urls.end(); ++it) {
2690 base::DictionaryValue* search_engine = new base::DictionaryValue;
2691 search_engine->SetString("short_name",
2692 base::UTF16ToUTF8((*it)->short_name()));
2693 search_engine->SetString("keyword", base::UTF16ToUTF8((*it)->keyword()));
2694 search_engine->SetBoolean("in_default_list", (*it)->ShowInDefaultList());
2695 search_engine->SetBoolean("is_default",
2696 (*it) == url_model->GetDefaultSearchProvider());
2697 search_engine->SetBoolean("is_valid", (*it)->url_ref().IsValid());
2698 search_engine->SetBoolean("supports_replacement",
2699 (*it)->url_ref().SupportsReplacement());
2700 search_engine->SetString("url", (*it)->url());
2701 search_engine->SetString("host", (*it)->url_ref().GetHost());
2702 search_engine->SetString("path", (*it)->url_ref().GetPath());
2703 search_engine->SetString("display_url",
2704 base::UTF16ToUTF8((*it)->url_ref().DisplayURL()));
2705 search_engines->Append(search_engine);
2707 return_value->Set("search_engines", search_engines);
2708 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2711 // Refer to pyauto.py for sample JSON input.
2712 void TestingAutomationProvider::AddOrEditSearchEngine(
2713 Browser* browser,
2714 base::DictionaryValue* args,
2715 IPC::Message* reply_message) {
2716 TemplateURLService* url_model =
2717 TemplateURLServiceFactory::GetForProfile(browser->profile());
2718 base::string16 new_title;
2719 base::string16 new_keyword;
2720 std::string new_url;
2721 std::string keyword;
2722 if (!args->GetString("new_title", &new_title) ||
2723 !args->GetString("new_keyword", &new_keyword) ||
2724 !args->GetString("new_url", &new_url)) {
2725 AutomationJSONReply(this, reply_message).SendError(
2726 "One or more inputs invalid");
2727 return;
2729 std::string new_ref_url = TemplateURLRef::DisplayURLToURLRef(
2730 base::UTF8ToUTF16(new_url));
2731 scoped_ptr<KeywordEditorController> controller(
2732 new KeywordEditorController(browser->profile()));
2733 if (args->GetString("keyword", &keyword)) {
2734 TemplateURL* template_url =
2735 url_model->GetTemplateURLForKeyword(base::UTF8ToUTF16(keyword));
2736 if (template_url == NULL) {
2737 AutomationJSONReply(this, reply_message).SendError(
2738 "No match for keyword: " + keyword);
2739 return;
2741 url_model->AddObserver(new AutomationProviderSearchEngineObserver(
2742 this, browser->profile(), reply_message));
2743 controller->ModifyTemplateURL(template_url, new_title, new_keyword,
2744 new_ref_url);
2745 } else {
2746 url_model->AddObserver(new AutomationProviderSearchEngineObserver(
2747 this, browser->profile(), reply_message));
2748 controller->AddTemplateURL(new_title, new_keyword, new_ref_url);
2752 // Sample json input: { "command": "PerformActionOnSearchEngine",
2753 // "keyword": keyword, "action": action }
2754 void TestingAutomationProvider::PerformActionOnSearchEngine(
2755 Browser* browser,
2756 base::DictionaryValue* args,
2757 IPC::Message* reply_message) {
2758 TemplateURLService* url_model =
2759 TemplateURLServiceFactory::GetForProfile(browser->profile());
2760 std::string keyword;
2761 std::string action;
2762 if (!args->GetString("keyword", &keyword) ||
2763 !args->GetString("action", &action)) {
2764 AutomationJSONReply(this, reply_message).SendError(
2765 "One or more inputs invalid");
2766 return;
2768 TemplateURL* template_url =
2769 url_model->GetTemplateURLForKeyword(base::UTF8ToUTF16(keyword));
2770 if (template_url == NULL) {
2771 AutomationJSONReply(this, reply_message).SendError(
2772 "No match for keyword: " + keyword);
2773 return;
2775 if (action == "delete") {
2776 url_model->AddObserver(new AutomationProviderSearchEngineObserver(
2777 this, browser->profile(), reply_message));
2778 url_model->Remove(template_url);
2779 } else if (action == "default") {
2780 url_model->AddObserver(new AutomationProviderSearchEngineObserver(
2781 this, browser->profile(), reply_message));
2782 url_model->SetDefaultSearchProvider(template_url);
2783 } else {
2784 AutomationJSONReply(this, reply_message).SendError(
2785 "Invalid action: " + action);
2789 // Sample json input: { "command": "GetLocalStatePrefsInfo" }
2790 // Refer chrome/test/pyautolib/prefs_info.py for sample json output.
2791 void TestingAutomationProvider::GetLocalStatePrefsInfo(
2792 base::DictionaryValue* args,
2793 IPC::Message* reply_message) {
2794 scoped_ptr<base::DictionaryValue> items(
2795 g_browser_process->local_state()->GetPreferenceValues());
2796 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2797 return_value->Set("prefs", items.release()); // return_value owns items.
2798 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2801 // Sample json input: { "command": "SetLocalStatePrefs", "path": path,
2802 // "value": value }
2803 void TestingAutomationProvider::SetLocalStatePrefs(
2804 base::DictionaryValue* args,
2805 IPC::Message* reply_message) {
2806 std::string path;
2807 base::Value* val = NULL;
2808 AutomationJSONReply reply(this, reply_message);
2809 if (args->GetString("path", &path) && args->Get("value", &val)) {
2810 PrefService* pref_service = g_browser_process->local_state();
2811 const PrefService::Preference* pref =
2812 pref_service->FindPreference(path.c_str());
2813 if (!pref) { // Not a registered pref.
2814 reply.SendError("pref not registered.");
2815 return;
2816 } else if (pref->IsManaged()) { // Do not attempt to change a managed pref.
2817 reply.SendError("pref is managed. cannot be changed.");
2818 return;
2819 } else { // Set the pref.
2820 pref_service->Set(path.c_str(), *val);
2822 } else {
2823 reply.SendError("no pref path or value given.");
2824 return;
2827 reply.SendSuccess(NULL);
2830 // Sample json input: { "command": "GetPrefsInfo", "windex": 0 }
2831 // Refer chrome/test/pyautolib/prefs_info.py for sample json output.
2832 void TestingAutomationProvider::GetPrefsInfo(base::DictionaryValue* args,
2833 IPC::Message* reply_message) {
2834 AutomationJSONReply reply(this, reply_message);
2835 Browser* browser;
2836 std::string error_msg;
2837 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
2838 reply.SendError(error_msg);
2839 return;
2841 scoped_ptr<base::DictionaryValue> items(
2842 browser->profile()->GetPrefs()->GetPreferenceValues());
2844 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2845 return_value->Set("prefs", items.release()); // return_value owns items.
2846 reply.SendSuccess(return_value.get());
2849 // Sample json input:
2850 // { "command": "SetPrefs",
2851 // "windex": 0,
2852 // "path": path,
2853 // "value": value }
2854 void TestingAutomationProvider::SetPrefs(base::DictionaryValue* args,
2855 IPC::Message* reply_message) {
2856 AutomationJSONReply reply(this, reply_message);
2857 Browser* browser;
2858 std::string error_msg;
2859 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
2860 reply.SendError(error_msg);
2861 return;
2863 std::string path;
2864 base::Value* val = NULL;
2865 if (args->GetString("path", &path) && args->Get("value", &val)) {
2866 PrefService* pref_service = browser->profile()->GetPrefs();
2867 const PrefService::Preference* pref =
2868 pref_service->FindPreference(path.c_str());
2869 if (!pref) { // Not a registered pref.
2870 reply.SendError("pref not registered.");
2871 return;
2872 } else if (pref->IsManaged()) { // Do not attempt to change a managed pref.
2873 reply.SendError("pref is managed. cannot be changed.");
2874 return;
2875 } else { // Set the pref.
2876 pref_service->Set(path.c_str(), *val);
2878 } else {
2879 reply.SendError("no pref path or value given.");
2880 return;
2883 reply.SendSuccess(NULL);
2886 // Sample json input: { "command": "GetOmniboxInfo" }
2887 // Refer chrome/test/pyautolib/omnibox_info.py for sample json output.
2888 void TestingAutomationProvider::GetOmniboxInfo(Browser* browser,
2889 base::DictionaryValue* args,
2890 IPC::Message* reply_message) {
2891 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2892 AutomationJSONReply reply(this, reply_message);
2894 LocationBar* loc_bar = browser->window()->GetLocationBar();
2895 if (!loc_bar) {
2896 reply.SendError("The specified browser does not have a location bar.");
2897 return;
2899 const OmniboxView* omnibox_view = loc_bar->GetOmniboxView();
2900 const OmniboxEditModel* model = omnibox_view->model();
2902 // Fill up matches.
2903 base::ListValue* matches = new base::ListValue;
2904 const AutocompleteResult& result = model->result();
2905 for (AutocompleteResult::const_iterator i(result.begin()); i != result.end();
2906 ++i) {
2907 const AutocompleteMatch& match = *i;
2908 base::DictionaryValue* item =
2909 new base::DictionaryValue; // owned by return_value
2910 item->SetString("type", AutocompleteMatchType::ToString(match.type));
2911 item->SetBoolean("starred", match.starred);
2912 item->SetString("destination_url", match.destination_url.spec());
2913 item->SetString("contents", match.contents);
2914 item->SetString("description", match.description);
2915 matches->Append(item);
2917 return_value->Set("matches", matches);
2919 // Fill up other properties.
2920 base::DictionaryValue* properties =
2921 new base::DictionaryValue; // owned by return_value
2922 properties->SetBoolean("has_focus", model->has_focus());
2923 properties->SetBoolean("query_in_progress",
2924 !model->autocomplete_controller()->done());
2925 properties->SetString("keyword", model->keyword());
2926 properties->SetString("text", omnibox_view->GetText());
2927 return_value->Set("properties", properties);
2929 reply.SendSuccess(return_value.get());
2932 // Sample json input: { "command": "SetOmniboxText",
2933 // "text": "goog" }
2934 void TestingAutomationProvider::SetOmniboxText(Browser* browser,
2935 base::DictionaryValue* args,
2936 IPC::Message* reply_message) {
2937 base::string16 text;
2938 AutomationJSONReply reply(this, reply_message);
2939 if (!args->GetString("text", &text)) {
2940 reply.SendError("text missing");
2941 return;
2943 chrome::FocusLocationBar(browser);
2944 LocationBar* loc_bar = browser->window()->GetLocationBar();
2945 if (!loc_bar) {
2946 reply.SendError("The specified browser does not have a location bar.");
2947 return;
2949 OmniboxView* omnibox_view = loc_bar->GetOmniboxView();
2950 omnibox_view->model()->OnSetFocus(false);
2951 omnibox_view->SetUserText(text);
2952 reply.SendSuccess(NULL);
2955 // Sample json input: { "command": "OmniboxMovePopupSelection",
2956 // "count": 1 }
2957 // Negative count implies up, positive implies down. Count values will be
2958 // capped by the size of the popup list.
2959 void TestingAutomationProvider::OmniboxMovePopupSelection(
2960 Browser* browser,
2961 base::DictionaryValue* args,
2962 IPC::Message* reply_message) {
2963 int count;
2964 AutomationJSONReply reply(this, reply_message);
2965 if (!args->GetInteger("count", &count)) {
2966 reply.SendError("count missing");
2967 return;
2969 LocationBar* loc_bar = browser->window()->GetLocationBar();
2970 if (!loc_bar) {
2971 reply.SendError("The specified browser does not have a location bar.");
2972 return;
2974 loc_bar->GetOmniboxView()->model()->OnUpOrDownKeyPressed(count);
2975 reply.SendSuccess(NULL);
2978 // Sample json input: { "command": "OmniboxAcceptInput" }
2979 void TestingAutomationProvider::OmniboxAcceptInput(
2980 Browser* browser,
2981 base::DictionaryValue* args,
2982 IPC::Message* reply_message) {
2983 NavigationController& controller =
2984 browser->tab_strip_model()->GetActiveWebContents()->GetController();
2985 LocationBar* loc_bar = browser->window()->GetLocationBar();
2986 if (!loc_bar) {
2987 AutomationJSONReply(this, reply_message).SendError(
2988 "The specified browser does not have a location bar.");
2989 return;
2991 new OmniboxAcceptNotificationObserver(&controller, this, reply_message);
2992 loc_bar->AcceptInput();
2995 // Sample json input: { "command": "GetInitialLoadTimes" }
2996 // Refer to InitialLoadObserver::GetTimingInformation() for sample output.
2997 void TestingAutomationProvider::GetInitialLoadTimes(
2998 Browser*,
2999 base::DictionaryValue*,
3000 IPC::Message* reply_message) {
3001 scoped_ptr<base::DictionaryValue> return_value(
3002 initial_load_observer_->GetTimingInformation());
3004 std::string json_return;
3005 base::JSONWriter::Write(return_value.get(), &json_return);
3006 AutomationMsg_SendJSONRequest::WriteReplyParams(
3007 reply_message, json_return, true);
3008 Send(reply_message);
3011 // Sample json input: { "command": "GetPluginsInfo" }
3012 // Refer chrome/test/pyautolib/plugins_info.py for sample json output.
3013 void TestingAutomationProvider::GetPluginsInfo(
3014 Browser* browser,
3015 base::DictionaryValue* args,
3016 IPC::Message* reply_message) {
3017 PluginService::GetInstance()->GetPlugins(
3018 base::Bind(&TestingAutomationProvider::GetPluginsInfoCallback,
3019 this, browser, args, reply_message));
3022 void TestingAutomationProvider::GetPluginsInfoCallback(
3023 Browser* browser,
3024 base::DictionaryValue* args,
3025 IPC::Message* reply_message,
3026 const std::vector<content::WebPluginInfo>& plugins) {
3027 PluginPrefs* plugin_prefs =
3028 PluginPrefs::GetForProfile(browser->profile()).get();
3029 base::ListValue* items = new base::ListValue;
3030 for (std::vector<content::WebPluginInfo>::const_iterator it =
3031 plugins.begin();
3032 it != plugins.end();
3033 ++it) {
3034 base::DictionaryValue* item = new base::DictionaryValue;
3035 item->SetString("name", it->name);
3036 item->SetString("path", it->path.value());
3037 item->SetString("version", it->version);
3038 item->SetString("desc", it->desc);
3039 item->SetBoolean("enabled", plugin_prefs->IsPluginEnabled(*it));
3040 // Add info about mime types.
3041 base::ListValue* mime_types = new base::ListValue();
3042 for (std::vector<content::WebPluginMimeType>::const_iterator type_it =
3043 it->mime_types.begin();
3044 type_it != it->mime_types.end();
3045 ++type_it) {
3046 base::DictionaryValue* mime_type = new base::DictionaryValue();
3047 mime_type->SetString("mimeType", type_it->mime_type);
3048 mime_type->SetString("description", type_it->description);
3050 base::ListValue* file_extensions = new base::ListValue();
3051 for (std::vector<std::string>::const_iterator ext_it =
3052 type_it->file_extensions.begin();
3053 ext_it != type_it->file_extensions.end();
3054 ++ext_it) {
3055 file_extensions->Append(new base::StringValue(*ext_it));
3057 mime_type->Set("fileExtensions", file_extensions);
3059 mime_types->Append(mime_type);
3061 item->Set("mimeTypes", mime_types);
3062 items->Append(item);
3064 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
3065 return_value->Set("plugins", items); // return_value owns items.
3067 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
3070 // Sample json input:
3071 // { "command": "EnablePlugin",
3072 // "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
3073 void TestingAutomationProvider::EnablePlugin(Browser* browser,
3074 base::DictionaryValue* args,
3075 IPC::Message* reply_message) {
3076 base::FilePath::StringType path;
3077 if (!args->GetString("path", &path)) {
3078 AutomationJSONReply(this, reply_message).SendError("path not specified.");
3079 return;
3081 PluginPrefs* plugin_prefs =
3082 PluginPrefs::GetForProfile(browser->profile()).get();
3083 plugin_prefs->EnablePlugin(
3084 true,
3085 base::FilePath(path),
3086 base::Bind(&DidEnablePlugin,
3087 AsWeakPtr(),
3088 reply_message,
3089 path,
3090 "Could not enable plugin for path %s."));
3093 // Sample json input:
3094 // { "command": "DisablePlugin",
3095 // "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
3096 void TestingAutomationProvider::DisablePlugin(Browser* browser,
3097 base::DictionaryValue* args,
3098 IPC::Message* reply_message) {
3099 base::FilePath::StringType path;
3100 if (!args->GetString("path", &path)) {
3101 AutomationJSONReply(this, reply_message).SendError("path not specified.");
3102 return;
3104 PluginPrefs* plugin_prefs =
3105 PluginPrefs::GetForProfile(browser->profile()).get();
3106 plugin_prefs->EnablePlugin(
3107 false,
3108 base::FilePath(path),
3109 base::Bind(&DidEnablePlugin,
3110 AsWeakPtr(),
3111 reply_message,
3112 path,
3113 "Could not disable plugin for path %s."));
3116 // Sample json input:
3117 // { "command": "SaveTabContents",
3118 // "tab_index": 0,
3119 // "filename": <a full pathname> }
3120 // Sample json output:
3121 // {}
3122 void TestingAutomationProvider::SaveTabContents(
3123 Browser* browser,
3124 base::DictionaryValue* args,
3125 IPC::Message* reply_message) {
3126 int tab_index = 0;
3127 base::FilePath::StringType filename;
3128 base::FilePath::StringType parent_directory;
3129 WebContents* web_contents = NULL;
3131 if (!args->GetInteger("tab_index", &tab_index) ||
3132 !args->GetString("filename", &filename)) {
3133 AutomationJSONReply(this, reply_message)
3134 .SendError("tab_index or filename param missing");
3135 return;
3136 } else {
3137 web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
3138 if (!web_contents) {
3139 AutomationJSONReply(this, reply_message).SendError("no tab at tab_index");
3140 return;
3143 // We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't
3144 // used. Nevertheless, SavePackage requires it be valid. Sigh.
3145 parent_directory = base::FilePath(filename).DirName().value();
3146 if (!web_contents->SavePage(
3147 base::FilePath(filename),
3148 base::FilePath(parent_directory),
3149 content::SAVE_PAGE_TYPE_AS_ONLY_HTML)) {
3150 AutomationJSONReply(this, reply_message).SendError(
3151 "Could not initiate SavePage");
3152 return;
3154 // The observer will delete itself when done.
3155 new SavePackageNotificationObserver(
3156 BrowserContext::GetDownloadManager(browser->profile()),
3157 this, reply_message);
3160 namespace {
3162 // Translates a dictionary password to a PasswordForm struct.
3163 autofill::PasswordForm GetPasswordFormFromDict(
3164 const base::DictionaryValue& password_dict) {
3166 // If the time is specified, change time to the specified time.
3167 base::Time time = base::Time::Now();
3168 int it;
3169 double dt;
3170 if (password_dict.GetInteger("time", &it))
3171 time = base::Time::FromTimeT(it);
3172 else if (password_dict.GetDouble("time", &dt))
3173 time = base::Time::FromDoubleT(dt);
3175 std::string signon_realm;
3176 base::string16 username_value;
3177 base::string16 password_value;
3178 base::string16 origin_url_text;
3179 base::string16 username_element;
3180 base::string16 password_element;
3181 base::string16 submit_element;
3182 base::string16 action_target_text;
3183 bool blacklist;
3184 base::string16 old_password_element;
3185 base::string16 old_password_value;
3187 // We don't care if any of these fail - they are either optional or checked
3188 // before this function is called.
3189 password_dict.GetString("signon_realm", &signon_realm);
3190 password_dict.GetString("username_value", &username_value);
3191 password_dict.GetString("password_value", &password_value);
3192 password_dict.GetString("origin_url", &origin_url_text);
3193 password_dict.GetString("username_element", &username_element);
3194 password_dict.GetString("password_element", &password_element);
3195 password_dict.GetString("submit_element", &submit_element);
3196 password_dict.GetString("action_target", &action_target_text);
3197 if (!password_dict.GetBoolean("blacklist", &blacklist))
3198 blacklist = false;
3200 GURL origin_gurl(origin_url_text);
3201 GURL action_target(action_target_text);
3203 autofill::PasswordForm password_form;
3204 password_form.signon_realm = signon_realm;
3205 password_form.username_value = username_value;
3206 password_form.password_value = password_value;
3207 password_form.origin = origin_gurl;
3208 password_form.username_element = username_element;
3209 password_form.password_element = password_element;
3210 password_form.submit_element = submit_element;
3211 password_form.action = action_target;
3212 password_form.blacklisted_by_user = blacklist;
3213 password_form.date_created = time;
3215 return password_form;
3218 } // namespace
3220 // See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json
3221 // input.
3222 // Sample json output: { "password_added": true }
3223 void TestingAutomationProvider::AddSavedPassword(
3224 Browser* browser,
3225 base::DictionaryValue* args,
3226 IPC::Message* reply_message) {
3227 base::DictionaryValue* password_dict = NULL;
3228 if (!args->GetDictionary("password", &password_dict)) {
3229 AutomationJSONReply(this, reply_message).SendError(
3230 "Must specify a password dictionary.");
3231 return;
3234 // The "signon realm" is effectively the primary key and must be included.
3235 // Check here before calling GetPasswordFormFromDict.
3236 if (!password_dict->HasKey("signon_realm")) {
3237 AutomationJSONReply(this, reply_message).SendError(
3238 "Password must include a value for 'signon_realm.'");
3239 return;
3242 autofill::PasswordForm new_password =
3243 GetPasswordFormFromDict(*password_dict);
3245 // Use IMPLICIT_ACCESS since new passwords aren't added in incognito mode.
3246 PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
3247 browser->profile(), Profile::IMPLICIT_ACCESS).get();
3249 // The password store does not exist for an incognito window.
3250 if (password_store == NULL) {
3251 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
3252 return_value->SetBoolean("password_added", false);
3253 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
3254 return;
3257 // This observer will delete itself.
3258 PasswordStoreLoginsChangedObserver* observer =
3259 new PasswordStoreLoginsChangedObserver(this, reply_message,
3260 PasswordStoreChange::ADD,
3261 "password_added");
3262 observer->Init();
3263 password_store->AddLogin(new_password);
3266 // See RemoveSavedPassword() in chrome/test/functional/pyauto.py for sample
3267 // json input.
3268 // Sample json output: {}
3269 void TestingAutomationProvider::RemoveSavedPassword(
3270 Browser* browser,
3271 base::DictionaryValue* args,
3272 IPC::Message* reply_message) {
3273 base::DictionaryValue* password_dict = NULL;
3275 if (!args->GetDictionary("password", &password_dict)) {
3276 AutomationJSONReply(this, reply_message).SendError(
3277 "Must specify a password dictionary.");
3278 return;
3281 // The "signon realm" is effectively the primary key and must be included.
3282 // Check here before calling GetPasswordFormFromDict.
3283 if (!password_dict->HasKey("signon_realm")) {
3284 AutomationJSONReply(this, reply_message).SendError(
3285 "Password must include a value for 'signon_realm.'");
3286 return;
3288 autofill::PasswordForm to_remove =
3289 GetPasswordFormFromDict(*password_dict);
3291 // Use EXPLICIT_ACCESS since passwords can be removed in incognito mode.
3292 PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
3293 browser->profile(), Profile::EXPLICIT_ACCESS).get();
3294 if (password_store == NULL) {
3295 AutomationJSONReply(this, reply_message).SendError(
3296 "Unable to get password store.");
3297 return;
3300 // This observer will delete itself.
3301 PasswordStoreLoginsChangedObserver* observer =
3302 new PasswordStoreLoginsChangedObserver(
3303 this, reply_message, PasswordStoreChange::REMOVE, std::string());
3304 observer->Init();
3306 password_store->RemoveLogin(to_remove);
3309 // Sample json input: { "command": "GetSavedPasswords" }
3310 // Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample
3311 // json output.
3312 void TestingAutomationProvider::GetSavedPasswords(
3313 Browser* browser,
3314 base::DictionaryValue* args,
3315 IPC::Message* reply_message) {
3316 // Use EXPLICIT_ACCESS since saved passwords can be retrieved in
3317 // incognito mode.
3318 PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
3319 browser->profile(), Profile::EXPLICIT_ACCESS).get();
3321 if (password_store == NULL) {
3322 AutomationJSONReply reply(this, reply_message);
3323 reply.SendError("Unable to get password store.");
3324 return;
3326 password_store->GetAutofillableLogins(
3327 new AutomationProviderGetPasswordsObserver(this, reply_message));
3328 // Observer deletes itself after sending the result.
3331 namespace {
3333 // Get the WebContents from a dictionary of arguments.
3334 WebContents* GetWebContentsFromDict(const Browser* browser,
3335 const base::DictionaryValue* args,
3336 std::string* error_message) {
3337 int tab_index;
3338 if (!args->GetInteger("tab_index", &tab_index)) {
3339 *error_message = "Must include tab_index.";
3340 return NULL;
3343 WebContents* web_contents =
3344 browser->tab_strip_model()->GetWebContentsAt(tab_index);
3345 if (!web_contents) {
3346 *error_message = base::StringPrintf("No tab at index %d.", tab_index);
3347 return NULL;
3349 return web_contents;
3352 } // namespace
3354 void TestingAutomationProvider::FindInPage(
3355 Browser* browser,
3356 base::DictionaryValue* args,
3357 IPC::Message* reply_message) {
3358 std::string error_message;
3359 WebContents* web_contents =
3360 GetWebContentsFromDict(browser, args, &error_message);
3361 if (!web_contents) {
3362 AutomationJSONReply(this, reply_message).SendError(error_message);
3363 return;
3365 base::string16 search_string;
3366 bool forward;
3367 bool match_case;
3368 bool find_next;
3369 if (!args->GetString("search_string", &search_string)) {
3370 AutomationJSONReply(this, reply_message).
3371 SendError("Must include search_string string.");
3372 return;
3374 if (!args->GetBoolean("forward", &forward)) {
3375 AutomationJSONReply(this, reply_message).
3376 SendError("Must include forward boolean.");
3377 return;
3379 if (!args->GetBoolean("match_case", &match_case)) {
3380 AutomationJSONReply(this, reply_message).
3381 SendError("Must include match_case boolean.");
3382 return;
3384 if (!args->GetBoolean("find_next", &find_next)) {
3385 AutomationJSONReply(this, reply_message).
3386 SendError("Must include find_next boolean.");
3387 return;
3389 SendFindRequest(web_contents,
3390 true,
3391 search_string,
3392 forward,
3393 match_case,
3394 find_next,
3395 reply_message);
3398 void TestingAutomationProvider::OpenFindInPage(
3399 base::DictionaryValue* args,
3400 IPC::Message* reply_message) {
3401 AutomationJSONReply reply(this, reply_message);
3402 Browser* browser;
3403 std::string error_msg;
3404 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
3405 reply.SendError(error_msg);
3406 return;
3408 chrome::FindInPage(browser, false, false);
3409 reply.SendSuccess(NULL);
3412 void TestingAutomationProvider::IsFindInPageVisible(
3413 base::DictionaryValue* args,
3414 IPC::Message* reply_message) {
3415 AutomationJSONReply reply(this, reply_message);
3416 bool visible;
3417 Browser* browser;
3418 std::string error_msg;
3419 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
3420 reply.SendError(error_msg);
3421 return;
3423 FindBarTesting* find_bar =
3424 browser->GetFindBarController()->find_bar()->GetFindBarTesting();
3425 find_bar->GetFindBarWindowInfo(NULL, &visible);
3426 base::DictionaryValue dict;
3427 dict.SetBoolean("is_visible", visible);
3428 reply.SendSuccess(&dict);
3431 void TestingAutomationProvider::InstallExtension(
3432 base::DictionaryValue* args, IPC::Message* reply_message) {
3433 base::FilePath::StringType path_string;
3434 bool with_ui;
3435 bool from_webstore = false;
3436 Browser* browser;
3437 content::WebContents* tab;
3438 std::string error_msg;
3439 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error_msg)) {
3440 AutomationJSONReply(this, reply_message).SendError(error_msg);
3441 return;
3443 if (!args->GetString("path", &path_string)) {
3444 AutomationJSONReply(this, reply_message).SendError(
3445 "Missing or invalid 'path'");
3446 return;
3448 if (!args->GetBoolean("with_ui", &with_ui)) {
3449 AutomationJSONReply(this, reply_message).SendError(
3450 "Missing or invalid 'with_ui'");
3451 return;
3453 args->GetBoolean("from_webstore", &from_webstore);
3455 ExtensionService* service = extensions::ExtensionSystem::Get(
3456 browser->profile())->extension_service();
3457 extensions::ProcessManager* manager =
3458 extensions::ExtensionSystem::Get(browser->profile())->process_manager();
3459 if (service && manager) {
3460 // The observer will delete itself when done.
3461 new ExtensionReadyNotificationObserver(
3462 manager,
3463 service,
3464 this,
3465 reply_message);
3467 base::FilePath extension_path(path_string);
3468 // If the given path has a 'crx' extension, assume it is a packed extension
3469 // and install it. Otherwise load it as an unpacked extension.
3470 if (extension_path.MatchesExtension(FILE_PATH_LITERAL(".crx"))) {
3471 scoped_ptr<ExtensionInstallPrompt> client(
3472 with_ui ? new ExtensionInstallPrompt(tab) : NULL);
3473 scoped_refptr<extensions::CrxInstaller> installer(
3474 extensions::CrxInstaller::Create(service, client.Pass()));
3475 if (!with_ui)
3476 installer->set_allow_silent_install(true);
3477 installer->set_install_cause(extension_misc::INSTALL_CAUSE_AUTOMATION);
3478 if (from_webstore)
3479 installer->set_creation_flags(Extension::FROM_WEBSTORE);
3480 installer->InstallCrx(extension_path);
3481 } else {
3482 scoped_refptr<extensions::UnpackedInstaller> installer(
3483 extensions::UnpackedInstaller::Create(service));
3484 installer->set_prompt_for_plugins(with_ui);
3485 installer->Load(extension_path);
3487 } else {
3488 AutomationJSONReply(this, reply_message).SendError(
3489 "Extensions service/process manager is not available");
3493 namespace {
3495 base::ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
3496 extensions::URLPatternSet pattern_set;
3497 if (effective_perm) {
3498 pattern_set =
3499 extensions::PermissionsData::GetEffectiveHostPermissions(ext);
3500 } else {
3501 pattern_set = ext->GetActivePermissions()->explicit_hosts();
3504 base::ListValue* permissions = new base::ListValue;
3505 for (extensions::URLPatternSet::const_iterator perm = pattern_set.begin();
3506 perm != pattern_set.end(); ++perm) {
3507 permissions->Append(new base::StringValue(perm->GetAsString()));
3510 return permissions;
3513 base::ListValue* GetAPIPermissions(const Extension* ext) {
3514 base::ListValue* permissions = new base::ListValue;
3515 std::set<std::string> perm_list =
3516 ext->GetActivePermissions()->GetAPIsAsStrings();
3517 for (std::set<std::string>::const_iterator perm = perm_list.begin();
3518 perm != perm_list.end(); ++perm) {
3519 permissions->Append(new base::StringValue(perm->c_str()));
3521 return permissions;
3524 } // namespace
3526 // Sample json input: { "command": "GetExtensionsInfo" }
3527 // See GetExtensionsInfo() in chrome/test/pyautolib/pyauto.py for sample json
3528 // output.
3529 void TestingAutomationProvider::GetExtensionsInfo(base::DictionaryValue* args,
3530 IPC::Message* reply_message) {
3531 AutomationJSONReply reply(this, reply_message);
3532 Browser* browser;
3533 std::string error_msg;
3534 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
3535 reply.SendError(error_msg);
3536 return;
3538 ExtensionService* service = extensions::ExtensionSystem::Get(
3539 browser->profile())->extension_service();
3540 if (!service) {
3541 reply.SendError("No extensions service.");
3542 return;
3544 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
3545 base::ListValue* extensions_values = new base::ListValue;
3546 const extensions::ExtensionSet* extensions = service->extensions();
3547 const extensions::ExtensionSet* disabled_extensions =
3548 service->disabled_extensions();
3549 ExtensionList all;
3550 all.insert(all.end(),
3551 extensions->begin(),
3552 extensions->end());
3553 all.insert(all.end(),
3554 disabled_extensions->begin(),
3555 disabled_extensions->end());
3556 ExtensionActionManager* extension_action_manager =
3557 ExtensionActionManager::Get(browser->profile());
3558 for (ExtensionList::const_iterator it = all.begin();
3559 it != all.end(); ++it) {
3560 const Extension* extension = it->get();
3561 std::string id = extension->id();
3562 base::DictionaryValue* extension_value = new base::DictionaryValue;
3563 extension_value->SetString("id", id);
3564 extension_value->SetString("version", extension->VersionString());
3565 extension_value->SetString("name", extension->name());
3566 extension_value->SetString("public_key", extension->public_key());
3567 extension_value->SetString("description", extension->description());
3568 extension_value->SetString(
3569 "background_url",
3570 extensions::BackgroundInfo::GetBackgroundURL(extension).spec());
3571 extension_value->SetString("options_url",
3572 extensions::ManifestURL::GetOptionsPage(extension).spec());
3573 extension_value->Set("host_permissions",
3574 GetHostPermissions(extension, false));
3575 extension_value->Set("effective_host_permissions",
3576 GetHostPermissions(extension, true));
3577 extension_value->Set("api_permissions", GetAPIPermissions(extension));
3578 Manifest::Location location = extension->location();
3579 extension_value->SetBoolean("is_component",
3580 location == Manifest::COMPONENT);
3581 extension_value->SetBoolean("is_internal",
3582 location == Manifest::INTERNAL);
3583 extension_value->SetBoolean("is_user_installed",
3584 location == Manifest::INTERNAL ||
3585 Manifest::IsUnpackedLocation(location));
3586 extension_value->SetBoolean("is_enabled", service->IsExtensionEnabled(id));
3587 extension_value->SetBoolean("allowed_in_incognito",
3588 extension_util::IsIncognitoEnabled(id, service));
3589 extension_value->SetBoolean(
3590 "has_page_action",
3591 extension_action_manager->GetPageAction(*extension) != NULL);
3592 extensions_values->Append(extension_value);
3594 return_value->Set("extensions", extensions_values);
3595 reply.SendSuccess(return_value.get());
3598 // See UninstallExtensionById() in chrome/test/pyautolib/pyauto.py for sample
3599 // json input.
3600 // Sample json output: {}
3601 void TestingAutomationProvider::UninstallExtensionById(
3602 base::DictionaryValue* args,
3603 IPC::Message* reply_message) {
3604 const Extension* extension;
3605 std::string error;
3606 Browser* browser;
3607 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
3608 AutomationJSONReply(this, reply_message).SendError(error);
3609 return;
3611 if (!GetExtensionFromJSONArgs(
3612 args, "id", browser->profile(), &extension, &error)) {
3613 AutomationJSONReply(this, reply_message).SendError(error);
3614 return;
3616 ExtensionService* service = extensions::ExtensionSystem::Get(
3617 browser->profile())->extension_service();
3618 if (!service) {
3619 AutomationJSONReply(this, reply_message).SendError(
3620 "No extensions service.");
3621 return;
3624 // Wait for a notification indicating that the extension with the given ID
3625 // has been uninstalled. This observer will delete itself.
3626 new ExtensionUninstallObserver(this, reply_message, extension->id());
3627 service->UninstallExtension(extension->id(), false, NULL);
3630 // See SetExtensionStateById() in chrome/test/pyautolib/pyauto.py
3631 // for sample json input.
3632 void TestingAutomationProvider::SetExtensionStateById(
3633 base::DictionaryValue* args,
3634 IPC::Message* reply_message) {
3635 const Extension* extension;
3636 std::string error;
3637 Browser* browser;
3638 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
3639 AutomationJSONReply(this, reply_message).SendError(error);
3640 return;
3642 if (!GetExtensionFromJSONArgs(
3643 args, "id", browser->profile(), &extension, &error)) {
3644 AutomationJSONReply(this, reply_message).SendError(error);
3645 return;
3648 bool enable;
3649 if (!args->GetBoolean("enable", &enable)) {
3650 AutomationJSONReply(this, reply_message)
3651 .SendError("Missing or invalid key: enable");
3652 return;
3655 bool allow_in_incognito;
3656 if (!args->GetBoolean("allow_in_incognito", &allow_in_incognito)) {
3657 AutomationJSONReply(this, reply_message)
3658 .SendError("Missing or invalid key: allow_in_incognito");
3659 return;
3662 if (allow_in_incognito && !enable) {
3663 AutomationJSONReply(this, reply_message)
3664 .SendError("Invalid state: Disabled extension "
3665 "cannot be allowed in incognito mode.");
3666 return;
3669 ExtensionService* service = extensions::ExtensionSystem::Get(
3670 browser->profile())->extension_service();
3671 extensions::ProcessManager* manager =
3672 extensions::ExtensionSystem::Get(browser->profile())->process_manager();
3673 if (!service) {
3674 AutomationJSONReply(this, reply_message)
3675 .SendError("No extensions service or process manager.");
3676 return;
3679 if (enable) {
3680 if (!service->IsExtensionEnabled(extension->id())) {
3681 new ExtensionReadyNotificationObserver(
3682 manager,
3683 service,
3684 this,
3685 reply_message);
3686 service->EnableExtension(extension->id());
3687 } else {
3688 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
3690 } else {
3691 service->DisableExtension(extension->id(),
3692 Extension::DISABLE_USER_ACTION);
3693 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
3696 extension_util::SetIsIncognitoEnabled(
3697 extension->id(), service, allow_in_incognito);
3700 // See TriggerPageActionById() in chrome/test/pyautolib/pyauto.py
3701 // for sample json input.
3702 void TestingAutomationProvider::TriggerPageActionById(
3703 base::DictionaryValue* args,
3704 IPC::Message* reply_message) {
3705 std::string error;
3706 Browser* browser;
3707 WebContents* tab;
3708 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
3709 AutomationJSONReply(this, reply_message).SendError(error);
3710 return;
3712 const Extension* extension;
3713 if (!GetEnabledExtensionFromJSONArgs(
3714 args, "id", browser->profile(), &extension, &error)) {
3715 AutomationJSONReply(this, reply_message).SendError(error);
3716 return;
3718 ExtensionAction* page_action =
3719 ExtensionActionManager::Get(browser->profile())->
3720 GetPageAction(*extension);
3721 if (!page_action) {
3722 AutomationJSONReply(this, reply_message).SendError(
3723 "Extension doesn't have any page action.");
3724 return;
3726 EnsureTabSelected(browser, tab);
3728 bool pressed = false;
3729 LocationBarTesting* loc_bar =
3730 browser->window()->GetLocationBar()->GetLocationBarForTesting();
3731 size_t page_action_visible_count =
3732 static_cast<size_t>(loc_bar->PageActionVisibleCount());
3733 for (size_t i = 0; i < page_action_visible_count; ++i) {
3734 if (loc_bar->GetVisiblePageAction(i) == page_action) {
3735 loc_bar->TestPageActionPressed(i);
3736 pressed = true;
3737 break;
3740 if (!pressed) {
3741 AutomationJSONReply(this, reply_message).SendError(
3742 "Extension's page action is not visible.");
3743 return;
3746 if (page_action->HasPopup(extensions::ExtensionTabUtil::GetTabId(tab))) {
3747 // This observer will delete itself.
3748 new ExtensionPopupObserver(
3749 this, reply_message, extension->id());
3750 } else {
3751 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
3755 // See TriggerBrowserActionById() in chrome/test/pyautolib/pyauto.py
3756 // for sample json input.
3757 void TestingAutomationProvider::TriggerBrowserActionById(
3758 base::DictionaryValue* args,
3759 IPC::Message* reply_message) {
3760 std::string error;
3761 Browser* browser;
3762 WebContents* tab;
3763 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
3764 AutomationJSONReply(this, reply_message).SendError(error);
3765 return;
3767 const Extension* extension;
3768 if (!GetEnabledExtensionFromJSONArgs(
3769 args, "id", browser->profile(), &extension, &error)) {
3770 AutomationJSONReply(this, reply_message).SendError(error);
3771 return;
3773 ExtensionAction* action = ExtensionActionManager::Get(browser->profile())->
3774 GetBrowserAction(*extension);
3775 if (!action) {
3776 AutomationJSONReply(this, reply_message).SendError(
3777 "Extension doesn't have any browser action.");
3778 return;
3780 EnsureTabSelected(browser, tab);
3782 BrowserActionTestUtil browser_actions(browser);
3783 int num_browser_actions = browser_actions.NumberOfBrowserActions();
3784 int action_index = -1;
3785 #if defined(TOOLKIT_VIEWS)
3786 for (int i = 0; i < num_browser_actions; ++i) {
3787 if (extension->id() == browser_actions.GetExtensionId(i)) {
3788 action_index = i;
3789 break;
3792 #else
3793 // TODO(kkania): Implement the platform-specific GetExtensionId() in
3794 // BrowserActionTestUtil.
3795 if (num_browser_actions != 1) {
3796 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
3797 "Found %d browser actions. Only one browser action must be active.",
3798 num_browser_actions));
3799 return;
3801 // This extension has a browser action, and there's only one action, so this
3802 // must be the first one.
3803 action_index = 0;
3804 #endif
3805 if (action_index == -1) {
3806 AutomationJSONReply(this, reply_message).SendError(
3807 "Extension's browser action is not visible.");
3808 return;
3810 browser_actions.Press(action_index);
3812 if (action->HasPopup(extensions::ExtensionTabUtil::GetTabId(tab))) {
3813 // This observer will delete itself.
3814 new ExtensionPopupObserver(
3815 this, reply_message, extension->id());
3816 } else {
3817 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
3821 void TestingAutomationProvider::ActionOnSSLBlockingPage(
3822 base::DictionaryValue* args,
3823 IPC::Message* reply_message) {
3824 WebContents* web_contents;
3825 bool proceed;
3826 std::string error;
3827 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
3828 AutomationJSONReply(this, reply_message).SendError(error);
3829 return;
3831 if (!args->GetBoolean("proceed", &proceed)) {
3832 AutomationJSONReply(this, reply_message).SendError(
3833 "'proceed' is missing or invalid");
3834 return;
3836 NavigationController& controller = web_contents->GetController();
3837 NavigationEntry* entry = controller.GetActiveEntry();
3838 if (entry->GetPageType() == content::PAGE_TYPE_INTERSTITIAL) {
3839 InterstitialPage* ssl_blocking_page =
3840 InterstitialPage::GetInterstitialPage(web_contents);
3841 if (ssl_blocking_page) {
3842 if (proceed) {
3843 new NavigationNotificationObserver(&controller, this, reply_message, 1,
3844 false, true);
3845 ssl_blocking_page->Proceed();
3846 return;
3848 ssl_blocking_page->DontProceed();
3849 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
3850 return;
3853 AutomationJSONReply(this, reply_message).SendError(error);
3856 void TestingAutomationProvider::GetSecurityState(base::DictionaryValue* args,
3857 IPC::Message* reply_message) {
3858 AutomationJSONReply reply(this, reply_message);
3859 WebContents* web_contents;
3860 std::string error;
3861 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
3862 reply.SendError(error);
3863 return;
3865 NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
3866 base::DictionaryValue dict;
3867 dict.SetInteger("security_style",
3868 static_cast<int>(entry->GetSSL().security_style));
3869 dict.SetInteger("ssl_cert_status",
3870 static_cast<int>(entry->GetSSL().cert_status));
3871 dict.SetInteger("insecure_content_status",
3872 static_cast<int>(entry->GetSSL().content_status));
3873 reply.SendSuccess(&dict);
3876 // Sample json input: { "command": "UpdateExtensionsNow" }
3877 // Sample json output: {}
3878 void TestingAutomationProvider::UpdateExtensionsNow(
3879 base::DictionaryValue* args,
3880 IPC::Message* reply_message) {
3881 std::string error;
3882 Browser* browser;
3883 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
3884 AutomationJSONReply(this, reply_message).SendError(error);
3885 return;
3887 ExtensionService* service = extensions::ExtensionSystem::Get(
3888 browser->profile())->extension_service();
3889 if (!service) {
3890 AutomationJSONReply(this, reply_message).SendError(
3891 "No extensions service.");
3892 return;
3895 extensions::ExtensionUpdater* updater = service->updater();
3896 if (!updater) {
3897 AutomationJSONReply(this, reply_message).SendError(
3898 "No updater for extensions service.");
3899 return;
3902 extensions::ProcessManager* manager =
3903 extensions::ExtensionSystem::Get(browser->profile())->process_manager();
3904 if (!manager) {
3905 AutomationJSONReply(this, reply_message).SendError(
3906 "No extension process manager.");
3907 return;
3910 // Create a new observer that waits until the extensions have been fully
3911 // updated (we should not send the reply until after all extensions have
3912 // been updated). This observer will delete itself.
3913 ExtensionsUpdatedObserver* observer = new ExtensionsUpdatedObserver(
3914 manager, this, reply_message);
3915 extensions::ExtensionUpdater::CheckParams params;
3916 params.install_immediately = true;
3917 params.callback = base::Bind(&ExtensionsUpdatedObserver::UpdateCheckFinished,
3918 base::Unretained(observer));
3919 updater->CheckNow(params);
3922 namespace {
3924 void SendSuccessIfAlive(
3925 base::WeakPtr<AutomationProvider> provider,
3926 IPC::Message* reply_message) {
3927 if (provider.get())
3928 AutomationJSONReply(provider.get(), reply_message).SendSuccess(NULL);
3931 } // namespace
3933 void TestingAutomationProvider::OverrideGeoposition(
3934 base::DictionaryValue* args,
3935 IPC::Message* reply_message) {
3936 double latitude, longitude, altitude;
3937 if (!args->GetDouble("latitude", &latitude) ||
3938 !args->GetDouble("longitude", &longitude) ||
3939 !args->GetDouble("altitude", &altitude)) {
3940 AutomationJSONReply(this, reply_message).SendError(
3941 "Missing or invalid geolocation parameters");
3942 return;
3944 content::Geoposition position;
3945 position.latitude = latitude;
3946 position.longitude = longitude;
3947 position.altitude = altitude;
3948 position.accuracy = 0.;
3949 position.timestamp = base::Time::Now();
3951 content::GeolocationProvider::OverrideLocationForTesting(
3952 position,
3953 base::Bind(&SendSuccessIfAlive, AsWeakPtr(), reply_message));
3956 // Refer to GetAllNotifications() in chrome/test/pyautolib/pyauto.py for
3957 // sample json input/output.
3958 void TestingAutomationProvider::GetAllNotifications(
3959 Browser* browser,
3960 base::DictionaryValue* args,
3961 IPC::Message* reply_message) {
3962 new GetAllNotificationsObserver(this, reply_message);
3965 // Refer to CloseNotification() in chrome/test/pyautolib/pyauto.py for
3966 // sample json input.
3967 // Returns empty json message.
3968 void TestingAutomationProvider::CloseNotification(
3969 Browser* browser,
3970 base::DictionaryValue* args,
3971 IPC::Message* reply_message) {
3972 int index;
3973 if (!args->GetInteger("index", &index)) {
3974 AutomationJSONReply(this, reply_message)
3975 .SendError("'index' missing or invalid.");
3976 return;
3978 BalloonNotificationUIManager* manager =
3979 BalloonNotificationUIManager::GetInstanceForTesting();
3980 BalloonCollection* collection = manager->balloon_collection();
3981 const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
3982 int balloon_count = static_cast<int>(balloons.size());
3983 if (index < 0 || index >= balloon_count) {
3984 AutomationJSONReply(this, reply_message)
3985 .SendError(base::StringPrintf("No notification at index %d", index));
3986 return;
3988 std::vector<const Notification*> queued_notes;
3989 manager->GetQueuedNotificationsForTesting(&queued_notes);
3990 if (queued_notes.empty()) {
3991 new OnNotificationBalloonCountObserver(
3992 this, reply_message, balloon_count - 1);
3993 } else {
3994 new NewNotificationBalloonObserver(this, reply_message);
3996 manager->CancelById(balloons[index]->notification().notification_id());
3999 // Refer to WaitForNotificationCount() in chrome/test/pyautolib/pyauto.py for
4000 // sample json input.
4001 // Returns empty json message.
4002 void TestingAutomationProvider::WaitForNotificationCount(
4003 Browser* browser,
4004 base::DictionaryValue* args,
4005 IPC::Message* reply_message) {
4006 int count;
4007 if (!args->GetInteger("count", &count)) {
4008 AutomationJSONReply(this, reply_message)
4009 .SendError("'count' missing or invalid.");
4010 return;
4012 // This will delete itself when finished.
4013 new OnNotificationBalloonCountObserver(this, reply_message, count);
4016 // Sample JSON input: { "command": "GetNTPInfo" }
4017 // For output, refer to chrome/test/pyautolib/ntp_model.py.
4018 void TestingAutomationProvider::GetNTPInfo(
4019 Browser* browser,
4020 base::DictionaryValue* args,
4021 IPC::Message* reply_message) {
4022 // This observer will delete itself.
4023 new NTPInfoObserver(this, reply_message);
4026 void TestingAutomationProvider::RemoveNTPMostVisitedThumbnail(
4027 Browser* browser,
4028 base::DictionaryValue* args,
4029 IPC::Message* reply_message) {
4030 AutomationJSONReply reply(this, reply_message);
4031 std::string url;
4032 if (!args->GetString("url", &url)) {
4033 reply.SendError("Missing or invalid 'url' key.");
4034 return;
4036 history::TopSites* top_sites = browser->profile()->GetTopSites();
4037 if (!top_sites) {
4038 reply.SendError("TopSites service is not initialized.");
4039 return;
4041 top_sites->AddBlacklistedURL(GURL(url));
4042 reply.SendSuccess(NULL);
4045 void TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails(
4046 Browser* browser,
4047 base::DictionaryValue* args,
4048 IPC::Message* reply_message) {
4049 AutomationJSONReply reply(this, reply_message);
4050 history::TopSites* top_sites = browser->profile()->GetTopSites();
4051 if (!top_sites) {
4052 reply.SendError("TopSites service is not initialized.");
4053 return;
4055 top_sites->ClearBlacklistedURLs();
4056 reply.SendSuccess(NULL);
4059 void TestingAutomationProvider::KillRendererProcess(
4060 Browser* browser,
4061 base::DictionaryValue* args,
4062 IPC::Message* reply_message) {
4063 int pid;
4064 uint32 kAccessFlags = base::kProcessAccessTerminate |
4065 base::kProcessAccessWaitForTermination |
4066 base::kProcessAccessQueryInformation;
4068 if (!args->GetInteger("pid", &pid)) {
4069 AutomationJSONReply(this, reply_message)
4070 .SendError("'pid' key missing or invalid.");
4071 return;
4073 base::ProcessHandle process;
4074 if (!base::OpenProcessHandleWithAccess(static_cast<base::ProcessId>(pid),
4075 kAccessFlags,
4076 &process)) {
4077 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
4078 "Failed to open process handle for pid %d", pid));
4079 return;
4081 new RendererProcessClosedObserver(this, reply_message);
4082 base::KillProcess(process, 0, false);
4083 base::CloseProcessHandle(process);
4086 bool TestingAutomationProvider::BuildWebKeyEventFromArgs(
4087 base::DictionaryValue* args,
4088 std::string* error,
4089 NativeWebKeyboardEvent* event) {
4090 int type, modifiers;
4091 bool is_system_key;
4092 base::string16 unmodified_text, text;
4093 std::string key_identifier;
4094 if (!args->GetInteger("type", &type)) {
4095 *error = "'type' missing or invalid.";
4096 return false;
4098 if (!args->GetBoolean("isSystemKey", &is_system_key)) {
4099 *error = "'isSystemKey' missing or invalid.";
4100 return false;
4102 if (!args->GetString("unmodifiedText", &unmodified_text)) {
4103 *error = "'unmodifiedText' missing or invalid.";
4104 return false;
4106 if (!args->GetString("text", &text)) {
4107 *error = "'text' missing or invalid.";
4108 return false;
4110 if (!args->GetInteger("nativeKeyCode", &event->nativeKeyCode)) {
4111 *error = "'nativeKeyCode' missing or invalid.";
4112 return false;
4114 if (!args->GetInteger("windowsKeyCode", &event->windowsKeyCode)) {
4115 *error = "'windowsKeyCode' missing or invalid.";
4116 return false;
4118 if (!args->GetInteger("modifiers", &modifiers)) {
4119 *error = "'modifiers' missing or invalid.";
4120 return false;
4122 if (args->GetString("keyIdentifier", &key_identifier)) {
4123 base::strlcpy(event->keyIdentifier,
4124 key_identifier.c_str(),
4125 blink::WebKeyboardEvent::keyIdentifierLengthCap);
4126 } else {
4127 *error = "'keyIdentifier' missing or invalid.";
4128 return false;
4131 if (type == automation::kRawKeyDownType) {
4132 event->type = blink::WebInputEvent::RawKeyDown;
4133 } else if (type == automation::kKeyDownType) {
4134 event->type = blink::WebInputEvent::KeyDown;
4135 } else if (type == automation::kKeyUpType) {
4136 event->type = blink::WebInputEvent::KeyUp;
4137 } else if (type == automation::kCharType) {
4138 event->type = blink::WebInputEvent::Char;
4139 } else {
4140 *error = "'type' refers to an unrecognized keyboard event type";
4141 return false;
4144 base::string16 unmodified_text_truncated = unmodified_text.substr(
4145 0, blink::WebKeyboardEvent::textLengthCap - 1);
4146 memcpy(event->unmodifiedText,
4147 unmodified_text_truncated.c_str(),
4148 unmodified_text_truncated.length() + 1);
4149 base::string16 text_truncated = text.substr(
4150 0, blink::WebKeyboardEvent::textLengthCap - 1);
4151 memcpy(event->text, text_truncated.c_str(), text_truncated.length() + 1);
4153 event->modifiers = 0;
4154 if (modifiers & automation::kShiftKeyMask)
4155 event->modifiers |= blink::WebInputEvent::ShiftKey;
4156 if (modifiers & automation::kControlKeyMask)
4157 event->modifiers |= blink::WebInputEvent::ControlKey;
4158 if (modifiers & automation::kAltKeyMask)
4159 event->modifiers |= blink::WebInputEvent::AltKey;
4160 if (modifiers & automation::kMetaKeyMask)
4161 event->modifiers |= blink::WebInputEvent::MetaKey;
4163 event->isSystemKey = is_system_key;
4164 event->timeStampSeconds = base::Time::Now().ToDoubleT();
4165 event->skip_in_browser = true;
4166 return true;
4169 void TestingAutomationProvider::SendWebkitKeyEvent(
4170 base::DictionaryValue* args,
4171 IPC::Message* reply_message) {
4172 if (SendErrorIfModalDialogActive(this, reply_message))
4173 return;
4175 NativeWebKeyboardEvent event;
4176 // In the event of an error, BuildWebKeyEventFromArgs handles telling what
4177 // went wrong and sending the reply message; if it fails, we just have to
4178 // stop here.
4179 std::string error;
4180 if (!BuildWebKeyEventFromArgs(args, &error, &event)) {
4181 AutomationJSONReply(this, reply_message).SendError(error);
4182 return;
4185 RenderViewHost* view;
4186 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
4187 AutomationJSONReply(this, reply_message).SendError(error);
4188 return;
4190 new InputEventAckNotificationObserver(this, reply_message, event.type, 1);
4191 view->ForwardKeyboardEvent(event);
4194 namespace {
4196 // Gets the active JavaScript modal dialog, or NULL if none.
4197 JavaScriptAppModalDialog* GetActiveJavaScriptModalDialog(
4198 std::string* error_msg) {
4199 AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance();
4200 if (!dialog_queue->HasActiveDialog() ||
4201 !dialog_queue->active_dialog()->IsJavaScriptModalDialog()) {
4202 *error_msg = "No JavaScriptModalDialog open";
4203 return NULL;
4205 return static_cast<JavaScriptAppModalDialog*>(dialog_queue->active_dialog());
4208 } // namespace
4210 void TestingAutomationProvider::GetAppModalDialogMessage(
4211 base::DictionaryValue* args, IPC::Message* reply_message) {
4212 AutomationJSONReply reply(this, reply_message);
4213 std::string error_msg;
4214 JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg);
4215 if (!dialog) {
4216 reply.SendError(error_msg);
4217 return;
4219 base::DictionaryValue result_dict;
4220 result_dict.SetString("message", base::UTF16ToUTF8(dialog->message_text()));
4221 reply.SendSuccess(&result_dict);
4224 void TestingAutomationProvider::AcceptOrDismissAppModalDialog(
4225 base::DictionaryValue* args, IPC::Message* reply_message) {
4226 AutomationJSONReply reply(this, reply_message);
4227 bool accept;
4228 if (!args->GetBoolean("accept", &accept)) {
4229 reply.SendError("Missing or invalid 'accept'");
4230 return;
4233 std::string error_msg;
4234 JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg);
4235 if (!dialog) {
4236 reply.SendError(error_msg);
4237 return;
4239 if (accept) {
4240 std::string prompt_text;
4241 if (args->GetString("prompt_text", &prompt_text))
4242 dialog->SetOverridePromptText(base::UTF8ToUTF16(prompt_text));
4243 dialog->native_dialog()->AcceptAppModalDialog();
4244 } else {
4245 dialog->native_dialog()->CancelAppModalDialog();
4247 reply.SendSuccess(NULL);
4250 // Sample JSON input: { "command": "LaunchApp",
4251 // "id": "ahfgeienlihckogmohjhadlkjgocpleb" }
4252 // Sample JSON output: {}
4253 void TestingAutomationProvider::LaunchApp(
4254 Browser* browser,
4255 base::DictionaryValue* args,
4256 IPC::Message* reply_message) {
4257 std::string id;
4258 if (!args->GetString("id", &id)) {
4259 AutomationJSONReply(this, reply_message).SendError(
4260 "Must include string id.");
4261 return;
4264 ExtensionService* service = extensions::ExtensionSystem::Get(
4265 browser->profile())->extension_service();
4266 if (!service) {
4267 AutomationJSONReply(this, reply_message).SendError(
4268 "No extensions service.");
4269 return;
4272 const Extension* extension = service->GetExtensionById(
4273 id, false /* do not include disabled extensions */);
4274 if (!extension) {
4275 AutomationJSONReply(this, reply_message).SendError(
4276 base::StringPrintf(
4277 "Extension with ID '%s' doesn't exist or is disabled.",
4278 id.c_str()));
4279 return;
4282 WebContents* old_contents =
4283 browser->tab_strip_model()->GetActiveWebContents();
4284 if (!old_contents) {
4285 AutomationJSONReply(this, reply_message).SendError(
4286 "Cannot identify selected tab contents.");
4287 return;
4290 AppLaunchParams launch_params(profile(), extension, CURRENT_TAB);
4291 // This observer will delete itself.
4292 new AppLaunchObserver(&old_contents->GetController(), this, reply_message,
4293 launch_params.container);
4294 OpenApplication(launch_params);
4297 // Sample JSON input: { "command": "SetAppLaunchType",
4298 // "id": "ahfgeienlihckogmohjhadlkjgocpleb",
4299 // "launch_type": "pinned" }
4300 // Sample JSON output: {}
4301 void TestingAutomationProvider::SetAppLaunchType(
4302 Browser* browser,
4303 base::DictionaryValue* args,
4304 IPC::Message* reply_message) {
4305 AutomationJSONReply reply(this, reply_message);
4307 std::string id;
4308 if (!args->GetString("id", &id)) {
4309 reply.SendError("Must include string id.");
4310 return;
4313 std::string launch_type_str;
4314 if (!args->GetString("launch_type", &launch_type_str)) {
4315 reply.SendError("Must specify app launch type.");
4316 return;
4319 ExtensionService* service = extensions::ExtensionSystem::Get(
4320 browser->profile())->extension_service();
4321 if (!service) {
4322 reply.SendError("No extensions service.");
4323 return;
4326 const Extension* extension = service->GetExtensionById(
4327 id, true /* include disabled extensions */);
4328 if (!extension) {
4329 reply.SendError(base::StringPrintf(
4330 "Extension with ID '%s' doesn't exist.", id.c_str()));
4331 return;
4334 extensions::LaunchType launch_type;
4335 if (launch_type_str == "pinned") {
4336 launch_type = extensions::LAUNCH_TYPE_PINNED;
4337 } else if (launch_type_str == "regular") {
4338 launch_type = extensions::LAUNCH_TYPE_REGULAR;
4339 } else if (launch_type_str == "fullscreen") {
4340 launch_type = extensions::LAUNCH_TYPE_FULLSCREEN;
4341 } else if (launch_type_str == "window") {
4342 launch_type = extensions::LAUNCH_TYPE_WINDOW;
4343 } else {
4344 reply.SendError(base::StringPrintf(
4345 "Unexpected launch type '%s'.", launch_type_str.c_str()));
4346 return;
4349 extensions::SetLaunchType(service, extension->id(), launch_type);
4350 reply.SendSuccess(NULL);
4353 // Sample json input: { "command": "GetV8HeapStats",
4354 // "tab_index": 0 }
4355 // Refer to GetV8HeapStats() in chrome/test/pyautolib/pyauto.py for
4356 // sample json output.
4357 void TestingAutomationProvider::GetV8HeapStats(
4358 Browser* browser,
4359 base::DictionaryValue* args,
4360 IPC::Message* reply_message) {
4361 WebContents* web_contents;
4362 int tab_index;
4364 if (!args->GetInteger("tab_index", &tab_index)) {
4365 AutomationJSONReply(this, reply_message).SendError(
4366 "Missing 'tab_index' argument.");
4367 return;
4370 web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
4371 if (!web_contents) {
4372 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
4373 "Could not get WebContents at tab index %d", tab_index));
4374 return;
4377 RenderViewHost* render_view = web_contents->GetRenderViewHost();
4379 // This observer will delete itself.
4380 new V8HeapStatsObserver(
4381 this, reply_message,
4382 base::GetProcId(render_view->GetProcess()->GetHandle()));
4383 render_view->Send(new ChromeViewMsg_GetV8HeapStats);
4386 // Sample json input: { "command": "GetFPS",
4387 // "tab_index": 0 }
4388 // Refer to GetFPS() in chrome/test/pyautolib/pyauto.py for
4389 // sample json output.
4390 void TestingAutomationProvider::GetFPS(
4391 Browser* browser,
4392 base::DictionaryValue* args,
4393 IPC::Message* reply_message) {
4394 WebContents* web_contents;
4395 int tab_index;
4397 if (!args->GetInteger("tab_index", &tab_index)) {
4398 AutomationJSONReply(this, reply_message).SendError(
4399 "Missing 'tab_index' argument.");
4400 return;
4403 web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
4404 if (!web_contents) {
4405 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
4406 "Could not get WebContents at tab index %d", tab_index));
4407 return;
4410 RenderViewHost* render_view = web_contents->GetRenderViewHost();
4411 int routing_id = render_view->GetRoutingID();
4413 // This observer will delete itself.
4414 new FPSObserver(
4415 this, reply_message,
4416 base::GetProcId(render_view->GetProcess()->GetHandle()),
4417 routing_id);
4418 render_view->Send(new ChromeViewMsg_GetFPS(routing_id));
4421 void TestingAutomationProvider::IsFullscreenForBrowser(Browser* browser,
4422 base::DictionaryValue* args,
4423 IPC::Message* reply_message) {
4424 base::DictionaryValue dict;
4425 dict.SetBoolean("result",
4426 browser->fullscreen_controller()->IsFullscreenForBrowser());
4427 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4430 void TestingAutomationProvider::IsFullscreenForTab(Browser* browser,
4431 base::DictionaryValue* args,
4432 IPC::Message* reply_message) {
4433 base::DictionaryValue dict;
4434 dict.SetBoolean("result",
4435 browser->fullscreen_controller()->IsFullscreenForTabOrPending());
4436 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4439 void TestingAutomationProvider::IsMouseLocked(Browser* browser,
4440 base::DictionaryValue* args,
4441 IPC::Message* reply_message) {
4442 base::DictionaryValue dict;
4443 dict.SetBoolean("result", browser->tab_strip_model()->GetActiveWebContents()->
4444 GetRenderViewHost()->GetView()->IsMouseLocked());
4445 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4448 void TestingAutomationProvider::IsMouseLockPermissionRequested(
4449 Browser* browser,
4450 base::DictionaryValue* args,
4451 IPC::Message* reply_message) {
4452 FullscreenExitBubbleType type =
4453 browser->fullscreen_controller()->GetFullscreenExitBubbleType();
4454 bool mouse_lock = false;
4455 fullscreen_bubble::PermissionRequestedByType(type, NULL, &mouse_lock);
4456 base::DictionaryValue dict;
4457 dict.SetBoolean("result", mouse_lock);
4458 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4461 void TestingAutomationProvider::IsFullscreenPermissionRequested(
4462 Browser* browser,
4463 base::DictionaryValue* args,
4464 IPC::Message* reply_message) {
4465 FullscreenExitBubbleType type =
4466 browser->fullscreen_controller()->GetFullscreenExitBubbleType();
4467 bool fullscreen = false;
4468 fullscreen_bubble::PermissionRequestedByType(type, &fullscreen, NULL);
4469 base::DictionaryValue dict;
4470 dict.SetBoolean("result", fullscreen);
4471 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4474 void TestingAutomationProvider::IsFullscreenBubbleDisplayed(Browser* browser,
4475 base::DictionaryValue* args,
4476 IPC::Message* reply_message) {
4477 FullscreenExitBubbleType type =
4478 browser->fullscreen_controller()->GetFullscreenExitBubbleType();
4479 base::DictionaryValue dict;
4480 dict.SetBoolean("result",
4481 type != FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
4482 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4485 void TestingAutomationProvider::IsFullscreenBubbleDisplayingButtons(
4486 Browser* browser,
4487 base::DictionaryValue* args,
4488 IPC::Message* reply_message) {
4489 FullscreenExitBubbleType type =
4490 browser->fullscreen_controller()->GetFullscreenExitBubbleType();
4491 base::DictionaryValue dict;
4492 dict.SetBoolean("result", fullscreen_bubble::ShowButtonsForType(type));
4493 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4496 void TestingAutomationProvider::AcceptCurrentFullscreenOrMouseLockRequest(
4497 Browser* browser,
4498 base::DictionaryValue* args,
4499 IPC::Message* reply_message) {
4500 browser->fullscreen_controller()->OnAcceptFullscreenPermission();
4501 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4504 void TestingAutomationProvider::DenyCurrentFullscreenOrMouseLockRequest(
4505 Browser* browser,
4506 base::DictionaryValue* args,
4507 IPC::Message* reply_message) {
4508 browser->fullscreen_controller()->OnDenyFullscreenPermission();
4509 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4512 void TestingAutomationProvider::WaitForTabToBeRestored(
4513 base::DictionaryValue* args,
4514 IPC::Message* reply_message) {
4515 WebContents* web_contents;
4516 std::string error;
4517 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
4518 AutomationJSONReply(this, reply_message).SendError(error);
4519 return;
4521 NavigationController& controller = web_contents->GetController();
4522 new NavigationControllerRestoredObserver(this, &controller, reply_message);
4525 void TestingAutomationProvider::RefreshPolicies(
4526 base::DictionaryValue* args,
4527 IPC::Message* reply_message) {
4528 #if !defined(ENABLE_CONFIGURATION_POLICY)
4529 AutomationJSONReply(this, reply_message).SendError(
4530 "Configuration Policy disabled");
4531 #else
4532 // Some policies (e.g. URLBlacklist) post tasks to other message loops
4533 // before they start enforcing updated policy values; make sure those tasks
4534 // have finished after a policy update.
4535 // Updates of the URLBlacklist are done on IO, after building the blacklist
4536 // on FILE, which is initiated from IO.
4537 base::Closure reply =
4538 base::Bind(SendSuccessReply, AsWeakPtr(), reply_message);
4539 g_browser_process->policy_service()->RefreshPolicies(
4540 base::Bind(PostTask, BrowserThread::IO,
4541 base::Bind(PostTask, BrowserThread::FILE,
4542 base::Bind(PostTask, BrowserThread::IO,
4543 base::Bind(PostTask, BrowserThread::UI, reply)))));
4544 #endif
4547 static int AccessArray(const volatile int arr[], const volatile int *index) {
4548 return arr[*index];
4551 void TestingAutomationProvider::SimulateAsanMemoryBug(
4552 base::DictionaryValue* args, IPC::Message* reply_message) {
4553 // This array is volatile not to let compiler optimize us out.
4554 volatile int testarray[3] = {0, 0, 0};
4556 // Send the reply while we can.
4557 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4559 // Cause Address Sanitizer to abort this process.
4560 volatile int index = 5;
4561 AccessArray(testarray, &index);
4564 void TestingAutomationProvider::GetIndicesFromTab(
4565 base::DictionaryValue* args,
4566 IPC::Message* reply_message) {
4567 AutomationJSONReply reply(this, reply_message);
4568 int id_or_handle = 0;
4569 bool has_id = args->HasKey("tab_id");
4570 bool has_handle = args->HasKey("tab_handle");
4571 if (has_id && has_handle) {
4572 reply.SendError(
4573 "Both 'tab_id' and 'tab_handle' were specified. Only one is allowed");
4574 return;
4575 } else if (!has_id && !has_handle) {
4576 reply.SendError("Either 'tab_id' or 'tab_handle' must be specified");
4577 return;
4579 if (has_id && !args->GetInteger("tab_id", &id_or_handle)) {
4580 reply.SendError("'tab_id' is invalid");
4581 return;
4583 if (has_handle && (!args->GetInteger("tab_handle", &id_or_handle) ||
4584 !tab_tracker_->ContainsHandle(id_or_handle))) {
4585 reply.SendError("'tab_handle' is invalid");
4586 return;
4588 int id = id_or_handle;
4589 if (has_handle) {
4590 SessionTabHelper* session_tab_helper =
4591 SessionTabHelper::FromWebContents(
4592 tab_tracker_->GetResource(id_or_handle)->GetWebContents());
4593 id = session_tab_helper->session_id().id();
4595 chrome::BrowserIterator it;
4596 int browser_index = 0;
4597 for (; !it.done(); it.Next(), ++browser_index) {
4598 Browser* browser = *it;
4599 for (int tab_index = 0;
4600 tab_index < browser->tab_strip_model()->count();
4601 ++tab_index) {
4602 WebContents* tab =
4603 browser->tab_strip_model()->GetWebContentsAt(tab_index);
4604 SessionTabHelper* session_tab_helper =
4605 SessionTabHelper::FromWebContents(tab);
4606 if (session_tab_helper->session_id().id() == id) {
4607 base::DictionaryValue dict;
4608 dict.SetInteger("windex", browser_index);
4609 dict.SetInteger("tab_index", tab_index);
4610 reply.SendSuccess(&dict);
4611 return;
4615 reply.SendError("Could not find tab among current browser windows");
4618 void TestingAutomationProvider::NavigateToURL(
4619 base::DictionaryValue* args,
4620 IPC::Message* reply_message) {
4621 if (SendErrorIfModalDialogActive(this, reply_message))
4622 return;
4624 int navigation_count;
4625 std::string url, error;
4626 Browser* browser;
4627 WebContents* web_contents;
4628 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
4629 AutomationJSONReply(this, reply_message).SendError(error);
4630 return;
4632 if (!args->GetString("url", &url)) {
4633 AutomationJSONReply(this, reply_message)
4634 .SendError("'url' missing or invalid");
4635 return;
4637 if (!args->GetInteger("navigation_count", &navigation_count)) {
4638 AutomationJSONReply(this, reply_message)
4639 .SendError("'navigation_count' missing or invalid");
4640 return;
4642 if (navigation_count > 0) {
4643 new NavigationNotificationObserver(
4644 &web_contents->GetController(), this, reply_message,
4645 navigation_count, false, true);
4646 } else {
4647 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4649 OpenURLParams params(
4650 GURL(url), content::Referrer(), CURRENT_TAB,
4651 content::PageTransitionFromInt(
4652 content::PAGE_TRANSITION_TYPED |
4653 content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
4654 false);
4655 browser->OpenURLFromTab(web_contents, params);
4658 void TestingAutomationProvider::GetActiveTabIndexJSON(
4659 base::DictionaryValue* args,
4660 IPC::Message* reply_message) {
4661 AutomationJSONReply reply(this, reply_message);
4662 Browser* browser;
4663 std::string error_msg;
4664 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
4665 reply.SendError(error_msg);
4666 return;
4668 int tab_index = browser->tab_strip_model()->active_index();
4669 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
4670 return_value->SetInteger("tab_index", tab_index);
4671 reply.SendSuccess(return_value.get());
4674 void TestingAutomationProvider::AppendTabJSON(base::DictionaryValue* args,
4675 IPC::Message* reply_message) {
4676 TabAppendedNotificationObserver* observer = NULL;
4677 int append_tab_response = -1;
4678 Browser* browser;
4679 std::string error_msg, url;
4680 if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
4681 AutomationJSONReply(this, reply_message).SendError(error_msg);
4682 return;
4684 if (!args->GetString("url", &url)) {
4685 AutomationJSONReply(this, reply_message)
4686 .SendError("'url' missing or invalid");
4687 return;
4689 observer = new TabAppendedNotificationObserver(browser, this, reply_message,
4690 true);
4691 WebContents* contents =
4692 chrome::AddSelectedTabWithURL(browser, GURL(url),
4693 content::PAGE_TRANSITION_TYPED);
4694 if (contents) {
4695 append_tab_response = GetIndexForNavigationController(
4696 &contents->GetController(), browser);
4699 if (!contents || append_tab_response < 0) {
4700 if (observer) {
4701 observer->ReleaseReply();
4702 delete observer;
4704 AutomationJSONReply(this, reply_message).SendError("Failed to append tab.");
4708 void TestingAutomationProvider::WaitUntilNavigationCompletes(
4709 base::DictionaryValue* args,
4710 IPC::Message* reply_message) {
4711 if (SendErrorIfModalDialogActive(this, reply_message))
4712 return;
4714 std::string error;
4715 Browser* browser;
4716 WebContents* web_contents;
4717 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
4718 AutomationJSONReply(this, reply_message).SendError(error);
4719 return;
4721 NavigationNotificationObserver* observer =
4722 new NavigationNotificationObserver(&web_contents->GetController(), this,
4723 reply_message, 1, true, true);
4724 if (!web_contents->IsLoading()) {
4725 observer->ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
4726 return;
4730 void TestingAutomationProvider::ExecuteJavascriptJSON(
4731 base::DictionaryValue* args,
4732 IPC::Message* reply_message) {
4733 if (SendErrorIfModalDialogActive(this, reply_message))
4734 return;
4736 base::string16 frame_xpath, javascript;
4737 std::string error;
4738 RenderViewHost* render_view;
4739 if (!GetRenderViewFromJSONArgs(args, profile(), &render_view, &error)) {
4740 AutomationJSONReply(this, reply_message).SendError(error);
4741 return;
4743 if (!args->GetString("frame_xpath", &frame_xpath)) {
4744 AutomationJSONReply(this, reply_message)
4745 .SendError("'frame_xpath' missing or invalid");
4746 return;
4748 if (!args->GetString("javascript", &javascript)) {
4749 AutomationJSONReply(this, reply_message)
4750 .SendError("'javascript' missing or invalid");
4751 return;
4754 new DomOperationMessageSender(this, reply_message, true);
4755 ExecuteJavascriptInRenderViewFrame(frame_xpath, javascript, reply_message,
4756 render_view);
4759 void TestingAutomationProvider::ExecuteJavascriptInRenderView(
4760 base::DictionaryValue* args,
4761 IPC::Message* reply_message) {
4762 base::string16 frame_xpath, javascript, extension_id, url_text;
4763 int render_process_id, render_view_id;
4764 if (!args->GetString("frame_xpath", &frame_xpath)) {
4765 AutomationJSONReply(this, reply_message)
4766 .SendError("'frame_xpath' missing or invalid");
4767 return;
4769 if (!args->GetString("javascript", &javascript)) {
4770 AutomationJSONReply(this, reply_message)
4771 .SendError("'javascript' missing or invalid");
4772 return;
4774 if (!args->GetInteger("view.render_process_id", &render_process_id)) {
4775 AutomationJSONReply(this, reply_message)
4776 .SendError("'view.render_process_id' missing or invalid");
4777 return;
4779 if (!args->GetInteger("view.render_view_id", &render_view_id)) {
4780 AutomationJSONReply(this, reply_message)
4781 .SendError("'view.render_view_id' missing or invalid");
4782 return;
4785 RenderViewHost* rvh = RenderViewHost::FromID(render_process_id,
4786 render_view_id);
4787 if (!rvh) {
4788 AutomationJSONReply(this, reply_message).SendError(
4789 "A RenderViewHost object was not found with the given view ID.");
4790 return;
4793 new DomOperationMessageSender(this, reply_message, true);
4794 ExecuteJavascriptInRenderViewFrame(frame_xpath, javascript, reply_message,
4795 rvh);
4798 void TestingAutomationProvider::AddDomEventObserver(
4799 base::DictionaryValue* args,
4800 IPC::Message* reply_message) {
4801 if (SendErrorIfModalDialogActive(this, reply_message))
4802 return;
4804 AutomationJSONReply reply(this, reply_message);
4805 std::string event_name;
4806 int automation_id;
4807 bool recurring;
4808 if (!args->GetString("event_name", &event_name)) {
4809 reply.SendError("'event_name' missing or invalid");
4810 return;
4812 if (!args->GetInteger("automation_id", &automation_id)) {
4813 reply.SendError("'automation_id' missing or invalid");
4814 return;
4816 if (!args->GetBoolean("recurring", &recurring)) {
4817 reply.SendError("'recurring' missing or invalid");
4818 return;
4821 if (!automation_event_queue_.get())
4822 automation_event_queue_.reset(new AutomationEventQueue);
4824 int observer_id = automation_event_queue_->AddObserver(
4825 new DomEventObserver(automation_event_queue_.get(), event_name,
4826 automation_id, recurring));
4827 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
4828 return_value->SetInteger("observer_id", observer_id);
4829 reply.SendSuccess(return_value.get());
4832 void TestingAutomationProvider::RemoveEventObserver(
4833 base::DictionaryValue* args,
4834 IPC::Message* reply_message) {
4835 AutomationJSONReply reply(this, reply_message);
4836 int observer_id;
4837 if (!args->GetInteger("observer_id", &observer_id) ||
4838 !automation_event_queue_.get()) {
4839 reply.SendError("'observer_id' missing or invalid");
4840 return;
4842 if (automation_event_queue_->RemoveObserver(observer_id)) {
4843 reply.SendSuccess(NULL);
4844 return;
4846 reply.SendError("Invalid observer id.");
4849 void TestingAutomationProvider::ClearEventQueue(
4850 base::DictionaryValue* args,
4851 IPC::Message* reply_message) {
4852 automation_event_queue_.reset();
4853 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4856 void TestingAutomationProvider::GetNextEvent(
4857 base::DictionaryValue* args,
4858 IPC::Message* reply_message) {
4859 scoped_ptr<AutomationJSONReply> reply(
4860 new AutomationJSONReply(this, reply_message));
4861 int observer_id;
4862 bool blocking;
4863 if (!args->GetInteger("observer_id", &observer_id)) {
4864 reply->SendError("'observer_id' missing or invalid");
4865 return;
4867 if (!args->GetBoolean("blocking", &blocking)) {
4868 reply->SendError("'blocking' missing or invalid");
4869 return;
4871 if (!automation_event_queue_.get()) {
4872 reply->SendError(
4873 "No observers are attached to the queue. Did you create any?");
4874 return;
4877 // The reply will be freed once a matching event is added to the queue.
4878 automation_event_queue_->GetNextEvent(reply.release(), observer_id, blocking);
4881 void TestingAutomationProvider::GoForward(
4882 base::DictionaryValue* args,
4883 IPC::Message* reply_message) {
4884 if (SendErrorIfModalDialogActive(this, reply_message))
4885 return;
4887 WebContents* web_contents;
4888 std::string error;
4889 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
4890 AutomationJSONReply(this, reply_message).SendError(error);
4891 return;
4893 NavigationController& controller = web_contents->GetController();
4894 if (!controller.CanGoForward()) {
4895 base::DictionaryValue dict;
4896 dict.SetBoolean("did_go_forward", false);
4897 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4898 return;
4900 new NavigationNotificationObserver(&controller, this, reply_message,
4901 1, false, true);
4902 controller.GoForward();
4905 void TestingAutomationProvider::ExecuteBrowserCommandAsyncJSON(
4906 base::DictionaryValue* args,
4907 IPC::Message* reply_message) {
4908 AutomationJSONReply reply(this, reply_message);
4909 int command;
4910 Browser* browser;
4911 std::string error;
4912 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
4913 reply.SendError(error);
4914 return;
4916 if (!args->GetInteger("accelerator", &command)) {
4917 reply.SendError("'accelerator' missing or invalid.");
4918 return;
4920 if (!chrome::SupportsCommand(browser, command)) {
4921 reply.SendError(base::StringPrintf("Browser does not support command=%d.",
4922 command));
4923 return;
4925 if (!chrome::IsCommandEnabled(browser, command)) {
4926 reply.SendError(base::StringPrintf(
4927 "Browser command=%d not enabled.", command));
4928 return;
4930 chrome::ExecuteCommand(browser, command);
4931 reply.SendSuccess(NULL);
4934 void TestingAutomationProvider::ExecuteBrowserCommandJSON(
4935 base::DictionaryValue* args,
4936 IPC::Message* reply_message) {
4937 int command;
4938 Browser* browser;
4939 std::string error;
4940 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
4941 AutomationJSONReply(this, reply_message).SendError(error);
4942 return;
4944 if (!args->GetInteger("accelerator", &command)) {
4945 AutomationJSONReply(this, reply_message).SendError(
4946 "'accelerator' missing or invalid.");
4947 return;
4949 if (!chrome::SupportsCommand(browser, command)) {
4950 AutomationJSONReply(this, reply_message).SendError(
4951 base::StringPrintf("Browser does not support command=%d.", command));
4952 return;
4954 if (!chrome::IsCommandEnabled(browser, command)) {
4955 AutomationJSONReply(this, reply_message).SendError(
4956 base::StringPrintf("Browser command=%d not enabled.", command));
4957 return;
4959 // First check if we can handle the command without using an observer.
4960 for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
4961 if (command == kSynchronousCommands[i]) {
4962 chrome::ExecuteCommand(browser, command);
4963 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
4964 return;
4967 // Use an observer if we have one, otherwise fail.
4968 if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
4969 this, browser, command, reply_message, true)) {
4970 chrome::ExecuteCommand(browser, command);
4971 return;
4973 AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
4974 "Unable to register observer for browser command=%d.", command));
4977 void TestingAutomationProvider::IsMenuCommandEnabledJSON(
4978 base::DictionaryValue* args,
4979 IPC::Message* reply_message) {
4980 int command;
4981 Browser* browser;
4982 std::string error;
4983 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
4984 AutomationJSONReply(this, reply_message).SendError(error);
4985 return;
4987 if (!args->GetInteger("accelerator", &command)) {
4988 AutomationJSONReply(this, reply_message).SendError(
4989 "'accelerator' missing or invalid.");
4990 return;
4992 base::DictionaryValue dict;
4993 dict.SetBoolean("enabled", chrome::IsCommandEnabled(browser, command));
4994 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
4997 void TestingAutomationProvider::GetTabInfo(
4998 base::DictionaryValue* args,
4999 IPC::Message* reply_message) {
5000 AutomationJSONReply reply(this, reply_message);
5001 Browser* browser;
5002 WebContents* tab;
5003 std::string error;
5004 if (GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
5005 NavigationEntry* entry = tab->GetController().GetActiveEntry();
5006 if (!entry) {
5007 reply.SendError("Unable to get active navigation entry");
5008 return;
5010 base::DictionaryValue dict;
5011 dict.SetString("title", entry->GetTitleForDisplay(std::string()));
5012 dict.SetString("url", entry->GetVirtualURL().spec());
5013 reply.SendSuccess(&dict);
5014 } else {
5015 reply.SendError(error);
5019 void TestingAutomationProvider::GetTabCountJSON(
5020 base::DictionaryValue* args,
5021 IPC::Message* reply_message) {
5022 AutomationJSONReply reply(this, reply_message);
5023 Browser* browser;
5024 std::string error;
5025 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
5026 reply.SendError(error);
5027 return;
5029 base::DictionaryValue dict;
5030 dict.SetInteger("tab_count", browser->tab_strip_model()->count());
5031 reply.SendSuccess(&dict);
5034 void TestingAutomationProvider::GoBack(
5035 base::DictionaryValue* args,
5036 IPC::Message* reply_message) {
5037 if (SendErrorIfModalDialogActive(this, reply_message))
5038 return;
5040 WebContents* web_contents;
5041 std::string error;
5042 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
5043 AutomationJSONReply(this, reply_message).SendError(error);
5044 return;
5046 NavigationController& controller = web_contents->GetController();
5047 if (!controller.CanGoBack()) {
5048 base::DictionaryValue dict;
5049 dict.SetBoolean("did_go_back", false);
5050 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
5051 return;
5053 new NavigationNotificationObserver(&controller, this, reply_message,
5054 1, false, true);
5055 controller.GoBack();
5058 void TestingAutomationProvider::ReloadJSON(
5059 base::DictionaryValue* args,
5060 IPC::Message* reply_message) {
5061 if (SendErrorIfModalDialogActive(this, reply_message))
5062 return;
5064 WebContents* web_contents;
5065 std::string error;
5066 if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
5067 AutomationJSONReply(this, reply_message).SendError(error);
5068 return;
5070 NavigationController& controller = web_contents->GetController();
5071 new NavigationNotificationObserver(&controller, this, reply_message,
5072 1, false, true);
5073 controller.Reload(false);
5076 void TestingAutomationProvider::GetCookiesJSON(
5077 base::DictionaryValue* args, IPC::Message* reply_message) {
5078 automation_util::GetCookiesJSON(this, args, reply_message);
5081 void TestingAutomationProvider::DeleteCookieJSON(
5082 base::DictionaryValue* args, IPC::Message* reply_message) {
5083 automation_util::DeleteCookieJSON(this, args, reply_message);
5086 void TestingAutomationProvider::SetCookieJSON(
5087 base::DictionaryValue* args, IPC::Message* reply_message) {
5088 automation_util::SetCookieJSON(this, args, reply_message);
5091 void TestingAutomationProvider::GetCookiesInBrowserContext(
5092 base::DictionaryValue* args,
5093 IPC::Message* reply_message) {
5094 AutomationJSONReply reply(this, reply_message);
5095 WebContents* web_contents;
5096 std::string value, url_string;
5097 int windex, value_size;
5098 if (!args->GetInteger("windex", &windex)) {
5099 reply.SendError("'windex' missing or invalid.");
5100 return;
5102 web_contents = automation_util::GetWebContentsAt(windex, 0);
5103 if (!web_contents) {
5104 reply.SendError("'windex' does not refer to a browser window.");
5105 return;
5107 if (!args->GetString("url", &url_string)) {
5108 reply.SendError("'url' missing or invalid.");
5109 return;
5111 GURL url(url_string);
5112 if (!url.is_valid()) {
5113 reply.SendError("Invalid url.");
5114 return;
5116 automation_util::GetCookies(url, web_contents, &value_size, &value);
5117 if (value_size == -1) {
5118 reply.SendError(
5119 base::StringPrintf("Unable to retrieve cookies for url=%s.",
5120 url_string.c_str()));
5121 return;
5123 base::DictionaryValue dict;
5124 dict.SetString("cookies", value);
5125 reply.SendSuccess(&dict);
5128 void TestingAutomationProvider::DeleteCookieInBrowserContext(
5129 base::DictionaryValue* args,
5130 IPC::Message* reply_message) {
5131 AutomationJSONReply reply(this, reply_message);
5132 WebContents* web_contents;
5133 std::string cookie_name, url_string;
5134 int windex;
5135 bool success = false;
5136 if (!args->GetInteger("windex", &windex)) {
5137 reply.SendError("'windex' missing or invalid.");
5138 return;
5140 web_contents = automation_util::GetWebContentsAt(windex, 0);
5141 if (!web_contents) {
5142 reply.SendError("'windex' does not refer to a browser window.");
5143 return;
5145 if (!args->GetString("cookie_name", &cookie_name)) {
5146 reply.SendError("'cookie_name' missing or invalid.");
5147 return;
5149 if (!args->GetString("url", &url_string)) {
5150 reply.SendError("'url' missing or invalid.");
5151 return;
5153 GURL url(url_string);
5154 if (!url.is_valid()) {
5155 reply.SendError("Invalid url.");
5156 return;
5158 automation_util::DeleteCookie(url, cookie_name, web_contents, &success);
5159 if (!success) {
5160 reply.SendError(
5161 base::StringPrintf("Failed to delete cookie with name=%s for url=%s.",
5162 cookie_name.c_str(), url_string.c_str()));
5163 return;
5165 reply.SendSuccess(NULL);
5168 void TestingAutomationProvider::SetCookieInBrowserContext(
5169 base::DictionaryValue* args,
5170 IPC::Message* reply_message) {
5171 AutomationJSONReply reply(this, reply_message);
5172 WebContents* web_contents;
5173 std::string value, url_string;
5174 int windex, response_value = -1;
5175 if (!args->GetInteger("windex", &windex)) {
5176 reply.SendError("'windex' missing or invalid.");
5177 return;
5179 web_contents = automation_util::GetWebContentsAt(windex, 0);
5180 if (!web_contents) {
5181 reply.SendError("'windex' does not refer to a browser window.");
5182 return;
5184 if (!args->GetString("value", &value)) {
5185 reply.SendError("'value' missing or invalid.");
5186 return;
5188 if (!args->GetString("url", &url_string)) {
5189 reply.SendError("'url' missing or invalid.");
5190 return;
5192 GURL url(url_string);
5193 if (!url.is_valid()) {
5194 reply.SendError("Invalid url.");
5195 return;
5197 automation_util::SetCookie(url, value, web_contents, &response_value);
5198 if (response_value != 1) {
5199 reply.SendError(base::StringPrintf(
5200 "Unable set cookie for url=%s.", url_string.c_str()));
5201 return;
5203 reply.SendSuccess(NULL);
5206 void TestingAutomationProvider::GetTabIds(
5207 base::DictionaryValue* args, IPC::Message* reply_message) {
5208 base::ListValue* id_list = new base::ListValue();
5209 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
5210 Browser* browser = *it;
5211 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
5212 int id = SessionTabHelper::FromWebContents(
5213 browser->tab_strip_model()->GetWebContentsAt(i))->session_id().id();
5214 id_list->Append(base::Value::CreateIntegerValue(id));
5217 base::DictionaryValue dict;
5218 dict.Set("ids", id_list);
5219 AutomationJSONReply(this, reply_message).SendSuccess(&dict);
5222 void TestingAutomationProvider::IsTabIdValid(
5223 base::DictionaryValue* args, IPC::Message* reply_message) {
5224 AutomationJSONReply reply(this, reply_message);
5225 int id;
5226 if (!args->GetInteger("id", &id)) {
5227 reply.SendError("'id' missing or invalid");
5228 return;
5230 bool is_valid = false;
5231 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
5232 Browser* browser = *it;
5233 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
5234 WebContents* tab = browser->tab_strip_model()->GetWebContentsAt(i);
5235 SessionTabHelper* session_tab_helper =
5236 SessionTabHelper::FromWebContents(tab);
5237 if (session_tab_helper->session_id().id() == id) {
5238 is_valid = true;
5239 break;
5243 base::DictionaryValue dict;
5244 dict.SetBoolean("is_valid", is_valid);
5245 reply.SendSuccess(&dict);
5248 void TestingAutomationProvider::CloseTabJSON(
5249 base::DictionaryValue* args, IPC::Message* reply_message) {
5250 Browser* browser;
5251 WebContents* tab;
5252 std::string error;
5253 bool wait_until_closed = false; // ChromeDriver does not use this.
5254 args->GetBoolean("wait_until_closed", &wait_until_closed);
5255 // Close tabs synchronously.
5256 if (GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
5257 if (wait_until_closed) {
5258 new TabClosedNotificationObserver(this, wait_until_closed, reply_message,
5259 true);
5261 chrome::CloseWebContents(browser, tab, false);
5262 if (!wait_until_closed)
5263 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
5264 return;
5266 // Close other types of views asynchronously.
5267 RenderViewHost* view;
5268 if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
5269 AutomationJSONReply(this, reply_message).SendError(error);
5270 return;
5272 view->ClosePage();
5273 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
5276 void TestingAutomationProvider::SetViewBounds(
5277 base::DictionaryValue* args,
5278 IPC::Message* reply_message) {
5279 AutomationJSONReply reply(this, reply_message);
5280 int x, y, width, height;
5281 if (!args->GetInteger("bounds.x", &x) ||
5282 !args->GetInteger("bounds.y", &y) ||
5283 !args->GetInteger("bounds.width", &width) ||
5284 !args->GetInteger("bounds.height", &height)) {
5285 reply.SendError("Missing or invalid 'bounds'");
5286 return;
5288 Browser* browser;
5289 std::string error;
5290 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
5291 reply.SendError(error);
5292 return;
5294 BrowserWindow* browser_window = browser->window();
5295 if (browser_window->IsMaximized()) {
5296 browser_window->Restore();
5298 browser_window->SetBounds(gfx::Rect(x, y, width, height));
5299 reply.SendSuccess(NULL);
5302 void TestingAutomationProvider::MaximizeView(
5303 base::DictionaryValue* args,
5304 IPC::Message* reply_message) {
5305 Browser* browser;
5306 std::string error;
5307 if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
5308 AutomationJSONReply(this, reply_message).SendError(error);
5309 return;
5312 #if defined(OS_LINUX)
5313 // Maximization on Linux is asynchronous, so create an observer object to be
5314 // notified upon maximization completion.
5315 new WindowMaximizedObserver(this, reply_message);
5316 #endif // defined(OS_LINUX)
5318 browser->window()->Maximize();
5320 #if !defined(OS_LINUX)
5321 // Send success reply right away for OS's with synchronous maximize command.
5322 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
5323 #endif // !defined(OS_LINUX)
5326 void TestingAutomationProvider::ActivateTabJSON(
5327 base::DictionaryValue* args,
5328 IPC::Message* reply_message) {
5329 if (SendErrorIfModalDialogActive(this, reply_message))
5330 return;
5332 AutomationJSONReply reply(this, reply_message);
5333 Browser* browser;
5334 WebContents* web_contents;
5335 std::string error;
5336 if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
5337 reply.SendError(error);
5338 return;
5340 TabStripModel* tab_strip = browser->tab_strip_model();
5341 tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents),
5342 true);
5343 reply.SendSuccess(NULL);
5346 void TestingAutomationProvider::IsPageActionVisible(
5347 base::DictionaryValue* args,
5348 IPC::Message* reply_message) {
5349 AutomationJSONReply reply(this, reply_message);
5351 WebContents* tab;
5352 std::string error;
5353 if (!GetTabFromJSONArgs(args, &tab, &error)) {
5354 reply.SendError(error);
5355 return;
5357 Browser* browser = automation_util::GetBrowserForTab(tab);
5358 if (!browser) {
5359 reply.SendError("Tab does not belong to an open browser");
5360 return;
5362 const Extension* extension;
5363 if (!GetEnabledExtensionFromJSONArgs(
5364 args, "extension_id", browser->profile(), &extension, &error)) {
5365 reply.SendError(error);
5366 return;
5368 ExtensionAction* page_action =
5369 ExtensionActionManager::Get(browser->profile())->
5370 GetPageAction(*extension);
5371 if (!page_action) {
5372 reply.SendError("Extension doesn't have any page action");
5373 return;
5375 EnsureTabSelected(browser, tab);
5377 bool is_visible = false;
5378 LocationBarTesting* loc_bar =
5379 browser->window()->GetLocationBar()->GetLocationBarForTesting();
5380 size_t page_action_visible_count =
5381 static_cast<size_t>(loc_bar->PageActionVisibleCount());
5382 for (size_t i = 0; i < page_action_visible_count; ++i) {
5383 if (loc_bar->GetVisiblePageAction(i) == page_action) {
5384 is_visible = true;
5385 break;
5388 base::DictionaryValue dict;
5389 dict.SetBoolean("is_visible", is_visible);
5390 reply.SendSuccess(&dict);
5393 void TestingAutomationProvider::CreateNewAutomationProvider(
5394 base::DictionaryValue* args,
5395 IPC::Message* reply_message) {
5396 AutomationJSONReply reply(this, reply_message);
5397 std::string channel_id;
5398 if (!args->GetString("channel_id", &channel_id)) {
5399 reply.SendError("'channel_id' missing or invalid");
5400 return;
5403 AutomationProvider* provider = new TestingAutomationProvider(profile_);
5404 provider->DisableInitialLoadObservers();
5405 // TODO(kkania): Remove this when crbug.com/91311 is fixed.
5406 // Named server channels should ideally be created and closed on the file
5407 // thread, within the IPC channel code.
5408 base::ThreadRestrictions::ScopedAllowIO allow_io;
5409 if (!provider->InitializeChannel(
5410 automation::kNamedInterfacePrefix + channel_id)) {
5411 reply.SendError("Failed to initialize channel: " + channel_id);
5412 return;
5414 DCHECK(g_browser_process);
5415 g_browser_process->GetAutomationProviderList()->AddProvider(provider);
5416 reply.SendSuccess(NULL);
5419 void TestingAutomationProvider::WaitForTabCountToBecome(
5420 int browser_handle,
5421 int target_tab_count,
5422 IPC::Message* reply_message) {
5423 if (!browser_tracker_->ContainsHandle(browser_handle)) {
5424 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message,
5425 false);
5426 Send(reply_message);
5427 return;
5430 Browser* browser = browser_tracker_->GetResource(browser_handle);
5432 // The observer will delete itself.
5433 new TabCountChangeObserver(this, browser, reply_message, target_tab_count);
5436 void TestingAutomationProvider::WaitForInfoBarCount(
5437 int tab_handle,
5438 size_t target_count,
5439 IPC::Message* reply_message) {
5440 if (!tab_tracker_->ContainsHandle(tab_handle)) {
5441 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
5442 Send(reply_message_);
5443 return;
5446 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
5447 if (!controller) {
5448 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
5449 Send(reply_message_);
5450 return;
5453 // The delegate will delete itself.
5454 new InfoBarCountObserver(this, reply_message,
5455 controller->GetWebContents(), target_count);
5458 void TestingAutomationProvider::WaitForProcessLauncherThreadToGoIdle(
5459 IPC::Message* reply_message) {
5460 new WaitForProcessLauncherThreadToGoIdleObserver(this, reply_message);
5463 void TestingAutomationProvider::OnRemoveProvider() {
5464 if (g_browser_process)
5465 g_browser_process->GetAutomationProviderList()->RemoveProvider(this);
5468 void TestingAutomationProvider::EnsureTabSelected(Browser* browser,
5469 WebContents* tab) {
5470 TabStripModel* tab_strip = browser->tab_strip_model();
5471 if (tab_strip->GetActiveWebContents() != tab)
5472 tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(tab), true);