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