automation_provider_observers.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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/automation_provider_observers.h" 6 7#include <deque> 8#include <string> 9#include <vector> 10 11#include "base/basictypes.h" 12#include "base/callback.h" 13#include "base/file_util.h" 14#include "base/json/json_writer.h" 15#include "base/scoped_ptr.h" 16#include "base/string_util.h" 17#include "base/stringprintf.h" 18#include "base/threading/thread_restrictions.h" 19#include "base/values.h" 20#include "chrome/app/chrome_command_ids.h" 21#include "chrome/browser/automation/automation_provider.h" 22#include "chrome/browser/automation/automation_provider_json.h" 23#include "chrome/browser/bookmarks/bookmark_model.h" 24#include "chrome/browser/browser_list.h" 25#include "chrome/browser/browser_process.h" 26#include "chrome/browser/dom_operation_notification_details.h" 27#include "chrome/browser/dom_ui/most_visited_handler.h" 28#include "chrome/browser/dom_ui/new_tab_ui.h" 29#include "chrome/browser/download/download_item.h" 30#include "chrome/browser/download/save_package.h" 31#include "chrome/browser/extensions/extension_host.h" 32#include "chrome/browser/extensions/extension_process_manager.h" 33#include "chrome/browser/extensions/extension_updater.h" 34#include "chrome/browser/history/top_sites.h" 35#include "chrome/browser/metrics/metric_event_duration_details.h" 36#include "chrome/browser/notifications/balloon.h" 37#include "chrome/browser/notifications/balloon_host.h" 38#include "chrome/browser/notifications/balloon_collection.h" 39#include "chrome/browser/notifications/notification.h" 40#include "chrome/browser/notifications/notification_ui_manager.h" 41#include "chrome/browser/printing/print_job.h" 42#include "chrome/browser/profiles/profile.h" 43#include "chrome/browser/renderer_host/render_process_host.h" 44#include "chrome/browser/renderer_host/render_view_host.h" 45#include "chrome/browser/search_engines/template_url_model.h" 46#include "chrome/browser/sessions/tab_restore_service.h" 47#include "chrome/browser/tab_contents/navigation_controller.h" 48#include "chrome/browser/tab_contents/tab_contents.h" 49#include "chrome/browser/tab_contents/thumbnail_generator.h" 50#include "chrome/browser/translate/page_translated_details.h" 51#include "chrome/browser/translate/translate_infobar_delegate.h" 52#include "chrome/browser/ui/browser.h" 53#include "chrome/browser/ui/login/login_prompt.h" 54#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 55#include "chrome/common/automation_constants.h" 56#include "chrome/common/extensions/extension.h" 57#include "chrome/common/notification_service.h" 58#include "gfx/codec/png_codec.h" 59#include "gfx/rect.h" 60#include "googleurl/src/gurl.h" 61 62#if defined(OS_CHROMEOS) 63#include "chrome/browser/chromeos/login/authentication_notification_details.h" 64#endif 65 66// Holds onto start and stop timestamps for a particular tab 67class InitialLoadObserver::TabTime { 68 public: 69 explicit TabTime(base::TimeTicks started) 70 : load_start_time_(started) { 71 } 72 void set_stop_time(base::TimeTicks stopped) { 73 load_stop_time_ = stopped; 74 } 75 base::TimeTicks stop_time() const { 76 return load_stop_time_; 77 } 78 base::TimeTicks start_time() const { 79 return load_start_time_; 80 } 81 private: 82 base::TimeTicks load_start_time_; 83 base::TimeTicks load_stop_time_; 84}; 85 86InitialLoadObserver::InitialLoadObserver(size_t tab_count, 87 AutomationProvider* automation) 88 : automation_(automation), 89 outstanding_tab_count_(tab_count), 90 init_time_(base::TimeTicks::Now()) { 91 if (outstanding_tab_count_ > 0) { 92 registrar_.Add(this, NotificationType::LOAD_START, 93 NotificationService::AllSources()); 94 registrar_.Add(this, NotificationType::LOAD_STOP, 95 NotificationService::AllSources()); 96 } 97} 98 99InitialLoadObserver::~InitialLoadObserver() { 100} 101 102void InitialLoadObserver::Observe(NotificationType type, 103 const NotificationSource& source, 104 const NotificationDetails& details) { 105 if (type == NotificationType::LOAD_START) { 106 if (outstanding_tab_count_ > loading_tabs_.size()) 107 loading_tabs_.insert(TabTimeMap::value_type( 108 source.map_key(), 109 TabTime(base::TimeTicks::Now()))); 110 } else if (type == NotificationType::LOAD_STOP) { 111 if (outstanding_tab_count_ > finished_tabs_.size()) { 112 TabTimeMap::iterator iter = loading_tabs_.find(source.map_key()); 113 if (iter != loading_tabs_.end()) { 114 finished_tabs_.insert(source.map_key()); 115 iter->second.set_stop_time(base::TimeTicks::Now()); 116 } 117 if (outstanding_tab_count_ == finished_tabs_.size()) 118 ConditionMet(); 119 } 120 } else { 121 NOTREACHED(); 122 } 123} 124 125DictionaryValue* InitialLoadObserver::GetTimingInformation() const { 126 ListValue* items = new ListValue; 127 for (TabTimeMap::const_iterator it = loading_tabs_.begin(); 128 it != loading_tabs_.end(); 129 ++it) { 130 DictionaryValue* item = new DictionaryValue; 131 base::TimeDelta delta_start = it->second.start_time() - init_time_; 132 133 item->SetReal("load_start_ms", delta_start.InMillisecondsF()); 134 if (it->second.stop_time().is_null()) { 135 item->Set("load_stop_ms", Value::CreateNullValue()); 136 } else { 137 base::TimeDelta delta_stop = it->second.stop_time() - init_time_; 138 item->SetReal("load_stop_ms", delta_stop.InMillisecondsF()); 139 } 140 items->Append(item); 141 } 142 DictionaryValue* return_value = new DictionaryValue; 143 return_value->Set("tabs", items); 144 return return_value; 145} 146 147void InitialLoadObserver::ConditionMet() { 148 registrar_.RemoveAll(); 149 automation_->OnInitialLoadsComplete(); 150} 151 152NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation) 153 : automation_(automation) { 154 registrar_.Add(this, NotificationType::INITIAL_NEW_TAB_UI_LOAD, 155 NotificationService::AllSources()); 156} 157 158NewTabUILoadObserver::~NewTabUILoadObserver() { 159} 160 161void NewTabUILoadObserver::Observe(NotificationType type, 162 const NotificationSource& source, 163 const NotificationDetails& details) { 164 if (type == NotificationType::INITIAL_NEW_TAB_UI_LOAD) { 165 Details<int> load_time(details); 166 automation_->Send( 167 new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr())); 168 } else { 169 NOTREACHED(); 170 } 171} 172 173NavigationControllerRestoredObserver::NavigationControllerRestoredObserver( 174 AutomationProvider* automation, 175 NavigationController* controller, 176 IPC::Message* reply_message) 177 : automation_(automation), 178 controller_(controller), 179 reply_message_(reply_message) { 180 if (FinishedRestoring()) { 181 SendDone(); 182 } else { 183 registrar_.Add(this, NotificationType::LOAD_STOP, 184 NotificationService::AllSources()); 185 } 186} 187 188NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() { 189} 190 191void NavigationControllerRestoredObserver::Observe( 192 NotificationType type, const NotificationSource& source, 193 const NotificationDetails& details) { 194 if (FinishedRestoring()) { 195 SendDone(); 196 registrar_.RemoveAll(); 197 } 198} 199 200bool NavigationControllerRestoredObserver::FinishedRestoring() { 201 return (!controller_->needs_reload() && !controller_->pending_entry() && 202 !controller_->tab_contents()->is_loading()); 203} 204 205void NavigationControllerRestoredObserver::SendDone() { 206 DCHECK(reply_message_ != NULL); 207 automation_->Send(reply_message_); 208} 209 210NavigationNotificationObserver::NavigationNotificationObserver( 211 NavigationController* controller, 212 AutomationProvider* automation, 213 IPC::Message* reply_message, 214 int number_of_navigations, 215 bool include_current_navigation) 216 : automation_(automation), 217 reply_message_(reply_message), 218 controller_(controller), 219 navigations_remaining_(number_of_navigations), 220 navigation_started_(false) { 221 DCHECK_LT(0, navigations_remaining_); 222 Source<NavigationController> source(controller_); 223 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, source); 224 registrar_.Add(this, NotificationType::LOAD_START, source); 225 registrar_.Add(this, NotificationType::LOAD_STOP, source); 226 registrar_.Add(this, NotificationType::AUTH_NEEDED, source); 227 registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source); 228 registrar_.Add(this, NotificationType::AUTH_CANCELLED, source); 229 230 if (include_current_navigation && controller->tab_contents()->is_loading()) 231 navigation_started_ = true; 232} 233 234NavigationNotificationObserver::~NavigationNotificationObserver() { 235 if (reply_message_) { 236 // This means we did not receive a notification for this navigation. 237 // Send over a failed navigation status back to the caller to ensure that 238 // the caller does not hang waiting for the response. 239 IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::Write( 240 reply_message_, AUTOMATION_MSG_NAVIGATION_ERROR); 241 automation_->Send(reply_message_); 242 reply_message_ = NULL; 243 } 244 245 automation_->RemoveNavigationStatusListener(this); 246} 247 248void NavigationNotificationObserver::Observe( 249 NotificationType type, const NotificationSource& source, 250 const NotificationDetails& details) { 251 // We listen for 2 events to determine when the navigation started because: 252 // - when this is used by the WaitForNavigation method, we might be invoked 253 // afer the load has started (but not after the entry was committed, as 254 // WaitForNavigation compares times of the last navigation). 255 // - when this is used with a page requiring authentication, we will not get 256 // a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so 257 // we need the NotificationType::LOAD_START. 258 if (type == NotificationType::NAV_ENTRY_COMMITTED || 259 type == NotificationType::LOAD_START) { 260 navigation_started_ = true; 261 } else if (type == NotificationType::LOAD_STOP) { 262 if (navigation_started_) { 263 navigation_started_ = false; 264 if (--navigations_remaining_ == 0) 265 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); 266 } 267 } else if (type == NotificationType::AUTH_SUPPLIED || 268 type == NotificationType::AUTH_CANCELLED) { 269 // The LoginHandler for this tab is no longer valid. 270 automation_->RemoveLoginHandler(controller_); 271 272 // Treat this as if navigation started again, since load start/stop don't 273 // occur while authentication is ongoing. 274 navigation_started_ = true; 275 } else if (type == NotificationType::AUTH_NEEDED) { 276 // Remember the login handler that wants authentication. 277 // We do this in all cases (not just when navigation_started_ == true) so 278 // tests can still wait for auth dialogs outside of navigation. 279 LoginHandler* handler = 280 Details<LoginNotificationDetails>(details)->handler(); 281 automation_->AddLoginHandler(controller_, handler); 282 283 // Respond that authentication is needed. 284 navigation_started_ = false; 285 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); 286 } else { 287 NOTREACHED(); 288 } 289} 290 291void NavigationNotificationObserver::ConditionMet( 292 AutomationMsg_NavigationResponseValues navigation_result) { 293 DCHECK(reply_message_ != NULL); 294 295 IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::Write( 296 reply_message_, navigation_result); 297 automation_->Send(reply_message_); 298 reply_message_ = NULL; 299 300 delete this; 301} 302 303TabStripNotificationObserver::TabStripNotificationObserver( 304 NotificationType notification, AutomationProvider* automation) 305 : automation_(automation), 306 notification_(notification) { 307 registrar_.Add(this, notification_, NotificationService::AllSources()); 308} 309 310TabStripNotificationObserver::~TabStripNotificationObserver() { 311} 312 313void TabStripNotificationObserver::Observe(NotificationType type, 314 const NotificationSource& source, 315 const NotificationDetails& details) { 316 if (type == notification_) { 317 ObserveTab(Source<NavigationController>(source).ptr()); 318 319 // If verified, no need to observe anymore 320 automation_->RemoveTabStripObserver(this); 321 delete this; 322 } else { 323 NOTREACHED(); 324 } 325} 326 327TabAppendedNotificationObserver::TabAppendedNotificationObserver( 328 Browser* parent, AutomationProvider* automation, 329 IPC::Message* reply_message) 330 : TabStripNotificationObserver(NotificationType::TAB_PARENTED, automation), 331 parent_(parent), 332 reply_message_(reply_message) { 333} 334 335void TabAppendedNotificationObserver::ObserveTab( 336 NavigationController* controller) { 337 if (automation_->GetIndexForNavigationController(controller, parent_) == 338 TabStripModel::kNoTab) { 339 // This tab notification doesn't belong to the parent_. 340 return; 341 } 342 343 automation_->AddNavigationStatusListener(controller, reply_message_, 1, 344 false); 345} 346 347TabClosedNotificationObserver::TabClosedNotificationObserver( 348 AutomationProvider* automation, bool wait_until_closed, 349 IPC::Message* reply_message) 350 : TabStripNotificationObserver(wait_until_closed ? 351 NotificationType::TAB_CLOSED : NotificationType::TAB_CLOSING, 352 automation), 353 reply_message_(reply_message), 354 for_browser_command_(false) { 355} 356 357void TabClosedNotificationObserver::ObserveTab( 358 NavigationController* controller) { 359 if (for_browser_command_) { 360 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_, 361 true); 362 } else { 363 AutomationMsg_CloseTab::WriteReplyParams(reply_message_, true); 364 } 365 automation_->Send(reply_message_); 366} 367 368void TabClosedNotificationObserver::set_for_browser_command( 369 bool for_browser_command) { 370 for_browser_command_ = for_browser_command; 371} 372 373TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation, 374 Browser* browser, 375 IPC::Message* reply_message, 376 int target_tab_count) 377 : automation_(automation), 378 reply_message_(reply_message), 379 tab_strip_model_(browser->tabstrip_model()), 380 target_tab_count_(target_tab_count) { 381 tab_strip_model_->AddObserver(this); 382 CheckTabCount(); 383} 384 385TabCountChangeObserver::~TabCountChangeObserver() { 386 tab_strip_model_->RemoveObserver(this); 387} 388 389void TabCountChangeObserver::TabInsertedAt(TabContentsWrapper* contents, 390 int index, 391 bool foreground) { 392 CheckTabCount(); 393} 394 395void TabCountChangeObserver::TabDetachedAt(TabContentsWrapper* contents, 396 int index) { 397 CheckTabCount(); 398} 399 400void TabCountChangeObserver::TabStripModelDeleted() { 401 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_, 402 false); 403 automation_->Send(reply_message_); 404 delete this; 405} 406 407void TabCountChangeObserver::CheckTabCount() { 408 if (tab_strip_model_->count() != target_tab_count_) 409 return; 410 411 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_, 412 true); 413 automation_->Send(reply_message_); 414 delete this; 415} 416 417bool DidExtensionHostsStopLoading(ExtensionProcessManager* manager) { 418 for (ExtensionProcessManager::const_iterator iter = manager->begin(); 419 iter != manager->end(); ++iter) { 420 if (!(*iter)->did_stop_loading()) 421 return false; 422 } 423 return true; 424} 425 426ExtensionInstallNotificationObserver::ExtensionInstallNotificationObserver( 427 AutomationProvider* automation, int id, IPC::Message* reply_message) 428 : automation_(automation), 429 id_(id), 430 reply_message_(reply_message) { 431 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 432 NotificationService::AllSources()); 433 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR, 434 NotificationService::AllSources()); 435 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, 436 NotificationService::AllSources()); 437} 438 439ExtensionInstallNotificationObserver::~ExtensionInstallNotificationObserver() { 440} 441 442void ExtensionInstallNotificationObserver::Observe( 443 NotificationType type, const NotificationSource& source, 444 const NotificationDetails& details) { 445 switch (type.value) { 446 case NotificationType::EXTENSION_LOADED: 447 SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED); 448 break; 449 case NotificationType::EXTENSION_INSTALL_ERROR: 450 case NotificationType::EXTENSION_UPDATE_DISABLED: 451 SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); 452 break; 453 default: 454 NOTREACHED(); 455 break; 456 } 457 458 delete this; 459} 460 461void ExtensionInstallNotificationObserver::SendResponse( 462 AutomationMsg_ExtensionResponseValues response) { 463 if (reply_message_ != NULL) { 464 switch (id_) { 465 case AutomationMsg_InstallExtension::ID: 466 AutomationMsg_InstallExtension::WriteReplyParams(reply_message_, 467 response); 468 break; 469 case AutomationMsg_LoadExpandedExtension::ID: 470 AutomationMsg_LoadExpandedExtension::WriteReplyParams(reply_message_, 471 response); 472 break; 473 default: 474 NOTREACHED(); 475 break; 476 } 477 478 automation_->Send(reply_message_); 479 reply_message_ = NULL; 480 } 481} 482 483ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver( 484 ExtensionProcessManager* manager, AutomationProvider* automation, int id, 485 IPC::Message* reply_message) 486 : manager_(manager), 487 automation_(automation), 488 id_(id), 489 reply_message_(reply_message), 490 extension_(NULL) { 491 registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING, 492 NotificationService::AllSources()); 493 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 494 NotificationService::AllSources()); 495 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR, 496 NotificationService::AllSources()); 497 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, 498 NotificationService::AllSources()); 499} 500 501ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() { 502} 503 504void ExtensionReadyNotificationObserver::Observe( 505 NotificationType type, const NotificationSource& source, 506 const NotificationDetails& details) { 507 bool success = false; 508 switch (type.value) { 509 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: 510 // Only continue on with this method if our extension has been loaded 511 // and all the extension hosts have stopped loading. 512 if (!extension_ || !DidExtensionHostsStopLoading(manager_)) 513 return; 514 success = true; 515 break; 516 case NotificationType::EXTENSION_LOADED: 517 extension_ = Details<const Extension>(details).ptr(); 518 if (!DidExtensionHostsStopLoading(manager_)) 519 return; 520 success = true; 521 break; 522 case NotificationType::EXTENSION_INSTALL_ERROR: 523 case NotificationType::EXTENSION_UPDATE_DISABLED: 524 success = false; 525 break; 526 default: 527 NOTREACHED(); 528 break; 529 } 530 531 if (id_ == AutomationMsg_InstallExtensionAndGetHandle::ID) { 532 // A handle of zero indicates an error. 533 int extension_handle = 0; 534 if (extension_) 535 extension_handle = automation_->AddExtension(extension_); 536 AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams( 537 reply_message_, extension_handle); 538 } else if (id_ == AutomationMsg_EnableExtension::ID) { 539 AutomationMsg_EnableExtension::WriteReplyParams(reply_message_, true); 540 } else { 541 NOTREACHED(); 542 LOG(ERROR) << "Cannot write reply params for unknown message id."; 543 } 544 545 automation_->Send(reply_message_); 546 delete this; 547} 548 549ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver() 550 : did_receive_unload_notification_(false) { 551 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 552 NotificationService::AllSources()); 553} 554 555ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() { 556} 557 558void ExtensionUnloadNotificationObserver::Observe( 559 NotificationType type, const NotificationSource& source, 560 const NotificationDetails& details) { 561 if (type.value == NotificationType::EXTENSION_UNLOADED) { 562 did_receive_unload_notification_ = true; 563 } else { 564 NOTREACHED(); 565 } 566} 567 568ExtensionTestResultNotificationObserver:: 569 ExtensionTestResultNotificationObserver(AutomationProvider* automation) 570 : automation_(automation) { 571 registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED, 572 NotificationService::AllSources()); 573 registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED, 574 NotificationService::AllSources()); 575} 576 577ExtensionTestResultNotificationObserver:: 578 ~ExtensionTestResultNotificationObserver() { 579} 580 581void ExtensionTestResultNotificationObserver::Observe( 582 NotificationType type, const NotificationSource& source, 583 const NotificationDetails& details) { 584 switch (type.value) { 585 case NotificationType::EXTENSION_TEST_PASSED: 586 results_.push_back(true); 587 messages_.push_back(""); 588 break; 589 590 case NotificationType::EXTENSION_TEST_FAILED: 591 results_.push_back(false); 592 messages_.push_back(*(Details<std::string>(details).ptr())); 593 break; 594 595 default: 596 NOTREACHED(); 597 } 598 // There may be a reply message waiting for this event, so check. 599 MaybeSendResult(); 600} 601 602void ExtensionTestResultNotificationObserver::MaybeSendResult() { 603 if (results_.size() > 0) { 604 // This release method should return the automation's current 605 // reply message, or NULL if there is no current one. If it is not 606 // NULL, we are stating that we will handle this reply message. 607 IPC::Message* reply_message = automation_->reply_message_release(); 608 // Send the result back if we have a reply message. 609 if (reply_message) { 610 AutomationMsg_WaitForExtensionTestResult::WriteReplyParams( 611 reply_message, results_.front(), messages_.front()); 612 results_.pop_front(); 613 messages_.pop_front(); 614 automation_->Send(reply_message); 615 } 616 } 617} 618 619BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver( 620 AutomationProvider* automation, IPC::Message* reply_message) 621 : automation_(automation), 622 reply_message_(reply_message), 623 for_browser_command_(false) { 624 registrar_.Add(this, NotificationType::BROWSER_OPENED, 625 NotificationService::AllSources()); 626} 627 628BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() { 629} 630 631void BrowserOpenedNotificationObserver::Observe( 632 NotificationType type, const NotificationSource& source, 633 const NotificationDetails& details) { 634 if (type == NotificationType::BROWSER_OPENED) { 635 if (for_browser_command_) { 636 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_, 637 true); 638 } 639 automation_->Send(reply_message_); 640 delete this; 641 } else { 642 NOTREACHED(); 643 } 644} 645 646void BrowserOpenedNotificationObserver::set_for_browser_command( 647 bool for_browser_command) { 648 for_browser_command_ = for_browser_command; 649} 650 651BrowserClosedNotificationObserver::BrowserClosedNotificationObserver( 652 Browser* browser, 653 AutomationProvider* automation, 654 IPC::Message* reply_message) 655 : automation_(automation), 656 reply_message_(reply_message), 657 for_browser_command_(false) { 658 registrar_.Add(this, NotificationType::BROWSER_CLOSED, 659 Source<Browser>(browser)); 660} 661 662void BrowserClosedNotificationObserver::Observe( 663 NotificationType type, const NotificationSource& source, 664 const NotificationDetails& details) { 665 DCHECK(type == NotificationType::BROWSER_CLOSED); 666 Details<bool> close_app(details); 667 DCHECK(reply_message_ != NULL); 668 if (for_browser_command_) { 669 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_, 670 true); 671 } else { 672 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_, true, 673 *(close_app.ptr())); 674 } 675 automation_->Send(reply_message_); 676 reply_message_ = NULL; 677 delete this; 678} 679 680void BrowserClosedNotificationObserver::set_for_browser_command( 681 bool for_browser_command) { 682 for_browser_command_ = for_browser_command; 683} 684 685BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver( 686 int target_count, 687 AutomationProvider* automation, 688 IPC::Message* reply_message) 689 : target_count_(target_count), 690 automation_(automation), 691 reply_message_(reply_message) { 692 registrar_.Add(this, NotificationType::BROWSER_OPENED, 693 NotificationService::AllSources()); 694 registrar_.Add(this, NotificationType::BROWSER_CLOSED, 695 NotificationService::AllSources()); 696} 697 698void BrowserCountChangeNotificationObserver::Observe( 699 NotificationType type, const NotificationSource& source, 700 const NotificationDetails& details) { 701 DCHECK(type == NotificationType::BROWSER_OPENED || 702 type == NotificationType::BROWSER_CLOSED); 703 int current_count = static_cast<int>(BrowserList::size()); 704 if (type == NotificationType::BROWSER_CLOSED) { 705 // At the time of the notification the browser being closed is not removed 706 // from the list. The real count is one less than the reported count. 707 DCHECK_LT(0, current_count); 708 current_count--; 709 } 710 if (current_count == target_count_) { 711 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams( 712 reply_message_, true); 713 automation_->Send(reply_message_); 714 reply_message_ = NULL; 715 delete this; 716 } 717} 718 719AppModalDialogShownObserver::AppModalDialogShownObserver( 720 AutomationProvider* automation, IPC::Message* reply_message) 721 : automation_(automation), 722 reply_message_(reply_message) { 723 registrar_.Add(this, NotificationType::APP_MODAL_DIALOG_SHOWN, 724 NotificationService::AllSources()); 725} 726 727AppModalDialogShownObserver::~AppModalDialogShownObserver() { 728} 729 730void AppModalDialogShownObserver::Observe( 731 NotificationType type, const NotificationSource& source, 732 const NotificationDetails& details) { 733 DCHECK(type == NotificationType::APP_MODAL_DIALOG_SHOWN); 734 735 AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams( 736 reply_message_, true); 737 automation_->Send(reply_message_); 738 reply_message_ = NULL; 739 delete this; 740} 741 742namespace { 743 744// Define mapping from command to notification 745struct CommandNotification { 746 int command; 747 NotificationType::Type notification_type; 748}; 749 750const struct CommandNotification command_notifications[] = { 751 {IDC_DUPLICATE_TAB, NotificationType::TAB_PARENTED}, 752 {IDC_NEW_TAB, NotificationType::INITIAL_NEW_TAB_UI_LOAD}, 753 754 // Returns as soon as the restored tab is created. To further wait until 755 // the content page is loaded, use WaitForTabToBeRestored. 756 {IDC_RESTORE_TAB, NotificationType::TAB_PARENTED}, 757 758 // For the following commands, we need to wait for a new tab to be created, 759 // load to finish, and title to change. 760 {IDC_MANAGE_EXTENSIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, 761 {IDC_OPTIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, 762 {IDC_PRINT, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, 763 {IDC_SHOW_DOWNLOADS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, 764 {IDC_SHOW_HISTORY, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, 765}; 766 767} // namespace 768 769ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() { 770} 771 772// static 773bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver( 774 AutomationProvider* automation, Browser* browser, int command, 775 IPC::Message* reply_message) { 776 bool result = true; 777 switch (command) { 778 case IDC_NEW_WINDOW: 779 case IDC_NEW_INCOGNITO_WINDOW: { 780 BrowserOpenedNotificationObserver* observer = 781 new BrowserOpenedNotificationObserver(automation, reply_message); 782 observer->set_for_browser_command(true); 783 break; 784 } 785 case IDC_CLOSE_WINDOW: { 786 BrowserClosedNotificationObserver* observer = 787 new BrowserClosedNotificationObserver(browser, automation, 788 reply_message); 789 observer->set_for_browser_command(true); 790 break; 791 } 792 case IDC_CLOSE_TAB: { 793 TabClosedNotificationObserver* observer = 794 new TabClosedNotificationObserver(automation, true, reply_message); 795 observer->set_for_browser_command(true); 796 break; 797 } 798 case IDC_BACK: 799 case IDC_FORWARD: 800 case IDC_RELOAD: { 801 automation->AddNavigationStatusListener( 802 &browser->GetSelectedTabContents()->controller(), 803 reply_message, 1, false); 804 break; 805 } 806 default: { 807 ExecuteBrowserCommandObserver* observer = 808 new ExecuteBrowserCommandObserver(automation, reply_message); 809 if (!observer->Register(command)) { 810 delete observer; 811 result = false; 812 } 813 break; 814 } 815 } 816 return result; 817} 818 819void ExecuteBrowserCommandObserver::Observe( 820 NotificationType type, const NotificationSource& source, 821 const NotificationDetails& details) { 822 if (type == notification_type_) { 823 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_, 824 true); 825 automation_->Send(reply_message_); 826 delete this; 827 } else { 828 NOTREACHED(); 829 } 830} 831 832ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver( 833 AutomationProvider* automation, IPC::Message* reply_message) 834 : automation_(automation), 835 notification_type_(NotificationType::ALL), 836 reply_message_(reply_message) { 837} 838 839bool ExecuteBrowserCommandObserver::Register(int command) { 840 if (!GetNotificationType(command, ¬ification_type_)) 841 return false; 842 registrar_.Add(this, notification_type_, NotificationService::AllSources()); 843 return true; 844} 845 846bool ExecuteBrowserCommandObserver::GetNotificationType( 847 int command, NotificationType::Type* type) { 848 if (!type) 849 return false; 850 bool found = false; 851 for (unsigned int i = 0; i < arraysize(command_notifications); i++) { 852 if (command_notifications[i].command == command) { 853 *type = command_notifications[i].notification_type; 854 found = true; 855 break; 856 } 857 } 858 return found; 859} 860 861FindInPageNotificationObserver::FindInPageNotificationObserver( 862 AutomationProvider* automation, TabContents* parent_tab, 863 bool reply_with_json, IPC::Message* reply_message) 864 : automation_(automation), 865 active_match_ordinal_(-1), 866 reply_with_json_(reply_with_json), 867 reply_message_(reply_message) { 868 registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE, 869 Source<TabContents>(parent_tab)); 870} 871 872FindInPageNotificationObserver::~FindInPageNotificationObserver() { 873} 874 875void FindInPageNotificationObserver::Observe( 876 NotificationType type, const NotificationSource& source, 877 const NotificationDetails& details) { 878 Details<FindNotificationDetails> find_details(details); 879 if (!(find_details->final_update() && reply_message_ != NULL)) { 880 DVLOG(1) << "Ignoring, since we only care about the final message"; 881 return; 882 } 883 // We get multiple responses and one of those will contain the ordinal. 884 // This message comes to us before the final update is sent. 885 if (find_details->request_id() == kFindInPageRequestId) { 886 if (reply_with_json_) { 887 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 888 return_value->SetInteger("match_count", 889 find_details->number_of_matches()); 890 gfx::Rect rect = find_details->selection_rect(); 891 // If MatchCount is > 0, then rect should not be Empty. 892 // We dont guard it here because we want to let the test 893 // code catch this invalid case if needed. 894 if (!rect.IsEmpty()) { 895 return_value->SetInteger("match_left", rect.x()); 896 return_value->SetInteger("match_top", rect.y()); 897 return_value->SetInteger("match_right", rect.right()); 898 return_value->SetInteger("match_bottom", rect.bottom()); 899 } 900 AutomationJSONReply(automation_, reply_message_) 901 .SendSuccess(return_value.get()); 902 delete this; 903 } else { 904 if (find_details->active_match_ordinal() > -1) { 905 active_match_ordinal_ = find_details->active_match_ordinal(); 906 AutomationMsg_Find::WriteReplyParams(reply_message_, 907 active_match_ordinal_, find_details->number_of_matches()); 908 automation_->Send(reply_message_); 909 reply_message_ = NULL; 910 } 911 } 912 } 913} 914 915// static 916const int FindInPageNotificationObserver::kFindInPageRequestId = -1; 917 918DomOperationObserver::DomOperationObserver() { 919 registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE, 920 NotificationService::AllSources()); 921} 922 923void DomOperationObserver::Observe( 924 NotificationType type, const NotificationSource& source, 925 const NotificationDetails& details) { 926 if (NotificationType::DOM_OPERATION_RESPONSE == type) { 927 Details<DomOperationNotificationDetails> dom_op_details(details); 928 OnDomOperationCompleted(dom_op_details->json()); 929 } 930} 931 932void DomOperationMessageSender::OnDomOperationCompleted( 933 const std::string& json) { 934 IPC::Message* reply_message = automation_->reply_message_release(); 935 if (reply_message) { 936 AutomationMsg_DomOperation::WriteReplyParams(reply_message, json); 937 automation_->Send(reply_message); 938 } else { 939 LOG(ERROR) << "DOM operation completed, but no reply message"; 940 } 941} 942 943DocumentPrintedNotificationObserver::DocumentPrintedNotificationObserver( 944 AutomationProvider* automation, IPC::Message* reply_message) 945 : automation_(automation), 946 success_(false), 947 reply_message_(reply_message) { 948 registrar_.Add(this, NotificationType::PRINT_JOB_EVENT, 949 NotificationService::AllSources()); 950} 951 952DocumentPrintedNotificationObserver::~DocumentPrintedNotificationObserver() { 953 DCHECK(reply_message_ != NULL); 954 AutomationMsg_PrintNow::WriteReplyParams(reply_message_, success_); 955 automation_->Send(reply_message_); 956 automation_->RemoveNavigationStatusListener(this); 957} 958 959void DocumentPrintedNotificationObserver::Observe( 960 NotificationType type, const NotificationSource& source, 961 const NotificationDetails& details) { 962 using namespace printing; 963 DCHECK(type == NotificationType::PRINT_JOB_EVENT); 964 switch (Details<JobEventDetails>(details)->type()) { 965 case JobEventDetails::JOB_DONE: { 966 // Succeeded. 967 success_ = true; 968 delete this; 969 break; 970 } 971 case JobEventDetails::USER_INIT_CANCELED: 972 case JobEventDetails::FAILED: { 973 // Failed. 974 delete this; 975 break; 976 } 977 case JobEventDetails::NEW_DOC: 978 case JobEventDetails::USER_INIT_DONE: 979 case JobEventDetails::DEFAULT_INIT_DONE: 980 case JobEventDetails::NEW_PAGE: 981 case JobEventDetails::PAGE_DONE: 982 case JobEventDetails::DOC_DONE: 983 case JobEventDetails::ALL_PAGES_REQUESTED: { 984 // Don't care. 985 break; 986 } 987 default: { 988 NOTREACHED(); 989 break; 990 } 991 } 992} 993 994MetricEventDurationObserver::MetricEventDurationObserver() { 995 registrar_.Add(this, NotificationType::METRIC_EVENT_DURATION, 996 NotificationService::AllSources()); 997} 998 999MetricEventDurationObserver::~MetricEventDurationObserver() {} 1000 1001int MetricEventDurationObserver::GetEventDurationMs( 1002 const std::string& event_name) { 1003 EventDurationMap::const_iterator it = durations_.find(event_name); 1004 if (it == durations_.end()) 1005 return -1; 1006 return it->second; 1007} 1008 1009void MetricEventDurationObserver::Observe(NotificationType type, 1010 const NotificationSource& source, const NotificationDetails& details) { 1011 if (type != NotificationType::METRIC_EVENT_DURATION) { 1012 NOTREACHED(); 1013 return; 1014 } 1015 MetricEventDurationDetails* metric_event_duration = 1016 Details<MetricEventDurationDetails>(details).ptr(); 1017 durations_[metric_event_duration->event_name] = 1018 metric_event_duration->duration_ms; 1019} 1020 1021PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation, 1022 IPC::Message* reply_message, 1023 TabContents* tab_contents) 1024 : automation_(automation), 1025 reply_message_(reply_message) { 1026 registrar_.Add(this, NotificationType::PAGE_TRANSLATED, 1027 Source<TabContents>(tab_contents)); 1028} 1029 1030PageTranslatedObserver::~PageTranslatedObserver() {} 1031 1032void PageTranslatedObserver::Observe(NotificationType type, 1033 const NotificationSource& source, 1034 const NotificationDetails& details) { 1035 DCHECK(type == NotificationType::PAGE_TRANSLATED); 1036 AutomationJSONReply reply(automation_, reply_message_); 1037 1038 PageTranslatedDetails* translated_details = 1039 Details<PageTranslatedDetails>(details).ptr(); 1040 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1041 return_value->SetBoolean( 1042 "translation_success", 1043 translated_details->error_type == TranslateErrors::NONE); 1044 reply.SendSuccess(return_value.get()); 1045 delete this; 1046} 1047 1048TabLanguageDeterminedObserver::TabLanguageDeterminedObserver( 1049 AutomationProvider* automation, IPC::Message* reply_message, 1050 TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar) 1051 : automation_(automation), 1052 reply_message_(reply_message), 1053 tab_contents_(tab_contents), 1054 translate_bar_(translate_bar) { 1055 registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, 1056 Source<TabContents>(tab_contents)); 1057} 1058 1059void TabLanguageDeterminedObserver::Observe( 1060 NotificationType type, const NotificationSource& source, 1061 const NotificationDetails& details) { 1062 DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED); 1063 1064 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1065 return_value->SetBoolean("page_translated", 1066 tab_contents_->language_state().IsPageTranslated()); 1067 return_value->SetBoolean( 1068 "can_translate_page", TranslatePrefs::CanTranslate( 1069 automation_->profile()->GetPrefs(), 1070 tab_contents_->language_state().original_language(), 1071 tab_contents_->GetURL())); 1072 return_value->SetString( 1073 "original_language", 1074 tab_contents_->language_state().original_language()); 1075 if (translate_bar_) { 1076 DictionaryValue* bar_info = new DictionaryValue; 1077 std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string; 1078 type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] = 1079 "BEFORE_TRANSLATE"; 1080 type_to_string[TranslateInfoBarDelegate::TRANSLATING] = 1081 "TRANSLATING"; 1082 type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] = 1083 "AFTER_TRANSLATE"; 1084 type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] = 1085 "TRANSLATION_ERROR"; 1086 1087 bar_info->SetBoolean("always_translate_lang_button_showing", 1088 translate_bar_->ShouldShowAlwaysTranslateButton()); 1089 bar_info->SetBoolean("never_translate_lang_button_showing", 1090 translate_bar_->ShouldShowNeverTranslateButton()); 1091 bar_info->SetString("bar_state", type_to_string[translate_bar_->type()]); 1092 bar_info->SetString("target_lang_code", 1093 translate_bar_->GetTargetLanguageCode()); 1094 bar_info->SetString("original_lang_code", 1095 translate_bar_->GetOriginalLanguageCode()); 1096 return_value->Set("translate_bar", bar_info); 1097 } 1098 AutomationJSONReply(automation_, reply_message_) 1099 .SendSuccess(return_value.get()); 1100 delete this; 1101} 1102 1103InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation, 1104 IPC::Message* reply_message, 1105 TabContents* tab_contents, 1106 int target_count) 1107 : automation_(automation), 1108 reply_message_(reply_message), 1109 tab_contents_(tab_contents), 1110 target_count_(target_count) { 1111 Source<TabContents> source(tab_contents); 1112 registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source); 1113 registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source); 1114 CheckCount(); 1115} 1116 1117void InfoBarCountObserver::Observe(NotificationType type, 1118 const NotificationSource& source, 1119 const NotificationDetails& details) { 1120 DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED || 1121 type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED); 1122 CheckCount(); 1123} 1124 1125void InfoBarCountObserver::CheckCount() { 1126 if (tab_contents_->infobar_delegate_count() != target_count_) 1127 return; 1128 1129 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, true); 1130 automation_->Send(reply_message_); 1131 delete this; 1132} 1133 1134#if defined(OS_CHROMEOS) 1135LoginManagerObserver::LoginManagerObserver( 1136 AutomationProvider* automation, 1137 IPC::Message* reply_message) 1138 : automation_(automation), 1139 reply_message_(reply_message) { 1140 1141 registrar_.Add(this, NotificationType::LOGIN_AUTHENTICATION, 1142 NotificationService::AllSources()); 1143} 1144 1145void LoginManagerObserver::Observe(NotificationType type, 1146 const NotificationSource& source, 1147 const NotificationDetails& details) { 1148 DCHECK(type == NotificationType::LOGIN_AUTHENTICATION); 1149 Details<AuthenticationNotificationDetails> auth_details(details); 1150 AutomationMsg_LoginWithUserAndPass::WriteReplyParams(reply_message_, 1151 auth_details->success()); 1152 automation_->Send(reply_message_); 1153 delete this; 1154} 1155#endif 1156 1157AutomationProviderBookmarkModelObserver:: 1158AutomationProviderBookmarkModelObserver( 1159 AutomationProvider* provider, 1160 IPC::Message* reply_message, 1161 BookmarkModel* model) { 1162 automation_provider_ = provider; 1163 reply_message_ = reply_message; 1164 model_ = model; 1165 model_->AddObserver(this); 1166} 1167 1168AutomationProviderBookmarkModelObserver:: 1169~AutomationProviderBookmarkModelObserver() { 1170 model_->RemoveObserver(this); 1171} 1172 1173void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model) { 1174 ReplyAndDelete(true); 1175} 1176 1177void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted( 1178 BookmarkModel* model) { 1179 ReplyAndDelete(false); 1180} 1181 1182void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) { 1183 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams( 1184 reply_message_, success); 1185 automation_provider_->Send(reply_message_); 1186 delete this; 1187} 1188 1189void AutomationProviderDownloadItemObserver::OnDownloadFileCompleted( 1190 DownloadItem* download) { 1191 download->RemoveObserver(this); 1192 if (--downloads_ == 0) { 1193 AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); 1194 delete this; 1195 } 1196} 1197 1198void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated( 1199 DownloadItem* download) { 1200 // If this observer is watching for open, only send the reply if the download 1201 // has been auto-opened. 1202 if (wait_for_open_ && !download->auto_opened()) 1203 return; 1204 1205 download->RemoveObserver(this); 1206 scoped_ptr<DictionaryValue> return_value( 1207 provider_->GetDictionaryFromDownloadItem(download)); 1208 AutomationJSONReply(provider_, reply_message_).SendSuccess( 1209 return_value.get()); 1210 delete this; 1211} 1212 1213void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened( 1214 DownloadItem* download) { 1215 download->RemoveObserver(this); 1216 scoped_ptr<DictionaryValue> return_value( 1217 provider_->GetDictionaryFromDownloadItem(download)); 1218 AutomationJSONReply(provider_, reply_message_).SendSuccess( 1219 return_value.get()); 1220 delete this; 1221} 1222 1223void AutomationProviderDownloadModelChangedObserver::ModelChanged() { 1224 AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); 1225 download_manager_->RemoveObserver(this); 1226 delete this; 1227} 1228 1229void AutomationProviderSearchEngineObserver::OnTemplateURLModelChanged() { 1230 TemplateURLModel* url_model = provider_->profile()->GetTemplateURLModel(); 1231 url_model->RemoveObserver(this); 1232 AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); 1233 delete this; 1234} 1235 1236void AutomationProviderHistoryObserver::HistoryQueryComplete( 1237 HistoryService::Handle request_handle, 1238 history::QueryResults* results) { 1239 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1240 1241 ListValue* history_list = new ListValue; 1242 for (size_t i = 0; i < results->size(); ++i) { 1243 DictionaryValue* page_value = new DictionaryValue; 1244 history::URLResult const &page = (*results)[i]; 1245 page_value->SetString("title", page.title()); 1246 page_value->SetString("url", page.url().spec()); 1247 page_value->SetReal("time", 1248 static_cast<double>(page.visit_time().ToDoubleT())); 1249 page_value->SetString("snippet", page.snippet().text()); 1250 page_value->SetBoolean( 1251 "starred", 1252 provider_->profile()->GetBookmarkModel()->IsBookmarked(page.url())); 1253 history_list->Append(page_value); 1254 } 1255 1256 return_value->Set("history", history_list); 1257 // Return history info. 1258 AutomationJSONReply reply(provider_, reply_message_); 1259 reply.SendSuccess(return_value.get()); 1260 delete this; 1261} 1262 1263void AutomationProviderImportSettingsObserver::ImportEnded() { 1264 // Send back an empty success message. 1265 AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); 1266 delete this; 1267} 1268 1269void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone( 1270 int handle, const std::vector<webkit_glue::PasswordForm*>& result) { 1271 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1272 1273 ListValue* passwords = new ListValue; 1274 for (std::vector<webkit_glue::PasswordForm*>::const_iterator it = 1275 result.begin(); it != result.end(); ++it) { 1276 DictionaryValue* password_val = new DictionaryValue; 1277 webkit_glue::PasswordForm* password_form = *it; 1278 password_val->SetString("username_value", password_form->username_value); 1279 password_val->SetString("password_value", password_form->password_value); 1280 password_val->SetString("signon_realm", password_form->signon_realm); 1281 password_val->SetReal( 1282 "time", static_cast<double>(password_form->date_created.ToDoubleT())); 1283 password_val->SetString("origin_url", password_form->origin.spec()); 1284 password_val->SetString("username_element", 1285 password_form->username_element); 1286 password_val->SetString("password_element", 1287 password_form->password_element); 1288 password_val->SetString("submit_element", 1289 password_form->submit_element); 1290 password_val->SetString("action_target", password_form->action.spec()); 1291 password_val->SetBoolean("blacklist", password_form->blacklisted_by_user); 1292 passwords->Append(password_val); 1293 } 1294 1295 return_value->Set("passwords", passwords); 1296 AutomationJSONReply(provider_, reply_message_).SendSuccess( 1297 return_value.get()); 1298 delete this; 1299} 1300 1301void AutomationProviderBrowsingDataObserver::OnBrowsingDataRemoverDone() { 1302 // Send back an empty success message 1303 AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); 1304 delete this; 1305} 1306 1307OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver( 1308 NavigationController* controller, 1309 AutomationProvider* automation, 1310 IPC::Message* reply_message) 1311 : automation_(automation), 1312 reply_message_(reply_message), 1313 controller_(controller) { 1314 Source<NavigationController> source(controller_); 1315 registrar_.Add(this, NotificationType::LOAD_STOP, source); 1316 // Pages requiring auth don't send LOAD_STOP. 1317 registrar_.Add(this, NotificationType::AUTH_NEEDED, source); 1318} 1319 1320OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() { 1321 automation_->RemoveNavigationStatusListener(this); 1322} 1323 1324void OmniboxAcceptNotificationObserver::Observe( 1325 NotificationType type, 1326 const NotificationSource& source, 1327 const NotificationDetails& details) { 1328 if (type == NotificationType::LOAD_STOP || 1329 type == NotificationType::AUTH_NEEDED) { 1330 AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); 1331 delete this; 1332 } else { 1333 NOTREACHED(); 1334 } 1335} 1336 1337SavePackageNotificationObserver::SavePackageNotificationObserver( 1338 SavePackage* save_package, 1339 AutomationProvider* automation, 1340 IPC::Message* reply_message) : automation_(automation), 1341 reply_message_(reply_message) { 1342 Source<SavePackage> source(save_package); 1343 registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED, 1344 source); 1345} 1346 1347void SavePackageNotificationObserver::Observe( 1348 NotificationType type, 1349 const NotificationSource& source, 1350 const NotificationDetails& details) { 1351 if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) { 1352 AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); 1353 delete this; 1354 } else { 1355 NOTREACHED(); 1356 } 1357} 1358 1359PageSnapshotTaker::PageSnapshotTaker(AutomationProvider* automation, 1360 IPC::Message* reply_message, 1361 RenderViewHost* render_view, 1362 const FilePath& path) 1363 : automation_(automation), 1364 reply_message_(reply_message), 1365 render_view_(render_view), 1366 image_path_(path), 1367 received_width_(false) {} 1368 1369void PageSnapshotTaker::Start() { 1370 ExecuteScript(L"window.domAutomationController.send(document.width);"); 1371} 1372 1373void PageSnapshotTaker::OnDomOperationCompleted(const std::string& json) { 1374 int dimension; 1375 if (!base::StringToInt(json, &dimension)) { 1376 LOG(ERROR) << "Could not parse received dimensions: " << json; 1377 SendMessage(false); 1378 } else if (!received_width_) { 1379 received_width_ = true; 1380 entire_page_size_.set_width(dimension); 1381 1382 ExecuteScript(L"window.domAutomationController.send(document.height);"); 1383 } else { 1384 entire_page_size_.set_height(dimension); 1385 1386 ThumbnailGenerator* generator = 1387 g_browser_process->GetThumbnailGenerator(); 1388 ThumbnailGenerator::ThumbnailReadyCallback* callback = 1389 NewCallback(this, &PageSnapshotTaker::OnSnapshotTaken); 1390 // Don't actually start the thumbnail generator, this leads to crashes on 1391 // Mac, crbug.com/62986. Instead, just hook the generator to the 1392 // RenderViewHost manually. 1393 render_view_->set_painting_observer(generator); 1394 generator->AskForSnapshot(render_view_, false, callback, 1395 entire_page_size_, entire_page_size_); 1396 } 1397} 1398 1399void PageSnapshotTaker::OnSnapshotTaken(const SkBitmap& bitmap) { 1400 base::ThreadRestrictions::ScopedAllowIO allow_io; 1401 std::vector<unsigned char> png_data; 1402 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data); 1403 int bytes_written = file_util::WriteFile(image_path_, 1404 reinterpret_cast<char*>(&png_data[0]), png_data.size()); 1405 SendMessage(bytes_written == static_cast<int>(png_data.size())); 1406} 1407 1408void PageSnapshotTaker::ExecuteScript(const std::wstring& javascript) { 1409 std::wstring set_automation_id; 1410 base::SStringPrintf( 1411 &set_automation_id, 1412 L"window.domAutomationController.setAutomationId(%d);", 1413 reply_message_->routing_id()); 1414 1415 render_view_->ExecuteJavascriptInWebFrame(L"", set_automation_id); 1416 render_view_->ExecuteJavascriptInWebFrame(L"", javascript); 1417} 1418 1419void PageSnapshotTaker::SendMessage(bool success) { 1420 AutomationMsg_CaptureEntirePageAsPNG::WriteReplyParams(reply_message_, 1421 success); 1422 automation_->Send(reply_message_); 1423 delete this; 1424} 1425 1426NTPInfoObserver::NTPInfoObserver( 1427 AutomationProvider* automation, 1428 IPC::Message* reply_message, 1429 CancelableRequestConsumer* consumer) 1430 : automation_(automation), 1431 reply_message_(reply_message), 1432 consumer_(consumer), 1433 request_(NULL), 1434 ntp_info_(new DictionaryValue) { 1435 top_sites_ = automation_->profile()->GetTopSites(); 1436 if (!top_sites_) { 1437 AutomationJSONReply(automation_, reply_message_) 1438 .SendError("Profile does not have service for querying the top sites."); 1439 return; 1440 } 1441 TabRestoreService* service = automation_->profile()->GetTabRestoreService(); 1442 if (!service) { 1443 AutomationJSONReply(automation_, reply_message_) 1444 .SendError("No TabRestoreService."); 1445 return; 1446 } 1447 1448 // Get the info that would be displayed in the recently closed section. 1449 ListValue* recently_closed_list = new ListValue; 1450 NewTabUI::AddRecentlyClosedEntries(service->entries(), 1451 recently_closed_list); 1452 ntp_info_->Set("recently_closed", recently_closed_list); 1453 1454 // Add default site URLs. 1455 ListValue* default_sites_list = new ListValue; 1456 std::vector<GURL> urls = MostVisitedHandler::GetPrePopulatedUrls(); 1457 for (size_t i = 0; i < urls.size(); ++i) { 1458 default_sites_list->Append(Value::CreateStringValue( 1459 urls[i].possibly_invalid_spec())); 1460 } 1461 ntp_info_->Set("default_sites", default_sites_list); 1462 1463 registrar_.Add(this, NotificationType::TOP_SITES_UPDATED, 1464 Source<history::TopSites>(top_sites_)); 1465 if (top_sites_->loaded()) { 1466 OnTopSitesLoaded(); 1467 } else { 1468 registrar_.Add(this, NotificationType::TOP_SITES_LOADED, 1469 Source<Profile>(automation_->profile())); 1470 } 1471} 1472 1473NTPInfoObserver::~NTPInfoObserver() {} 1474 1475void NTPInfoObserver::Observe(NotificationType type, 1476 const NotificationSource& source, 1477 const NotificationDetails& details) { 1478 if (type == NotificationType::TOP_SITES_LOADED) { 1479 OnTopSitesLoaded(); 1480 } else if (type == NotificationType::TOP_SITES_UPDATED) { 1481 Details<CancelableRequestProvider::Handle> request_details(details); 1482 if (request_ == *request_details.ptr()) { 1483 top_sites_->GetMostVisitedURLs( 1484 consumer_, 1485 NewCallback(this, &NTPInfoObserver::OnTopSitesReceived)); 1486 } 1487 } 1488} 1489 1490void NTPInfoObserver::OnTopSitesLoaded() { 1491 request_ = top_sites_->StartQueryForMostVisited(); 1492} 1493 1494void NTPInfoObserver::OnTopSitesReceived( 1495 const history::MostVisitedURLList& visited_list) { 1496 ListValue* list_value = new ListValue; 1497 for (size_t i = 0; i < visited_list.size(); ++i) { 1498 const history::MostVisitedURL& visited = visited_list[i]; 1499 if (visited.url.spec().empty()) 1500 break; // This is the signal that there are no more real visited sites. 1501 DictionaryValue* dict = new DictionaryValue; 1502 dict->SetString("url", visited.url.spec()); 1503 dict->SetString("title", visited.title); 1504 dict->SetBoolean("is_pinned", top_sites_->IsURLPinned(visited.url)); 1505 list_value->Append(dict); 1506 } 1507 ntp_info_->Set("most_visited", list_value); 1508 AutomationJSONReply(automation_, reply_message_).SendSuccess(ntp_info_.get()); 1509 delete this; 1510} 1511 1512AutocompleteEditFocusedObserver::AutocompleteEditFocusedObserver( 1513 AutomationProvider* automation, 1514 AutocompleteEditModel* autocomplete_edit, 1515 IPC::Message* reply_message) 1516 : automation_(automation), 1517 reply_message_(reply_message), 1518 autocomplete_edit_model_(autocomplete_edit) { 1519 Source<AutocompleteEditModel> source(autocomplete_edit); 1520 registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, source); 1521} 1522 1523void AutocompleteEditFocusedObserver::Observe( 1524 NotificationType type, 1525 const NotificationSource& source, 1526 const NotificationDetails& details) { 1527 DCHECK(type == NotificationType::AUTOCOMPLETE_EDIT_FOCUSED); 1528 AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams( 1529 reply_message_, true); 1530 automation_->Send(reply_message_); 1531 delete this; 1532} 1533 1534namespace { 1535 1536// Returns whether the notification's host has a non-null process handle. 1537bool IsNotificationProcessReady(Balloon* balloon) { 1538 return balloon->view() && 1539 balloon->view()->GetHost() && 1540 balloon->view()->GetHost()->render_view_host() && 1541 balloon->view()->GetHost()->render_view_host()->process()->GetHandle(); 1542} 1543 1544// Returns whether all active notifications have an associated process ID. 1545bool AreActiveNotificationProcessesReady() { 1546 NotificationUIManager* manager = g_browser_process->notification_ui_manager(); 1547 const BalloonCollection::Balloons& balloons = 1548 manager->balloon_collection()->GetActiveBalloons(); 1549 BalloonCollection::Balloons::const_iterator iter; 1550 for (iter = balloons.begin(); iter != balloons.end(); ++iter) { 1551 if (!IsNotificationProcessReady(*iter)) 1552 return false; 1553 } 1554 return true; 1555} 1556 1557} // namespace 1558 1559GetActiveNotificationsObserver::GetActiveNotificationsObserver( 1560 AutomationProvider* automation, 1561 IPC::Message* reply_message) 1562 : reply_(automation, reply_message) { 1563 if (AreActiveNotificationProcessesReady()) { 1564 SendMessage(); 1565 } else { 1566 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED, 1567 NotificationService::AllSources()); 1568 } 1569} 1570 1571void GetActiveNotificationsObserver::Observe( 1572 NotificationType type, 1573 const NotificationSource& source, 1574 const NotificationDetails& details) { 1575 if (AreActiveNotificationProcessesReady()) 1576 SendMessage(); 1577} 1578 1579void GetActiveNotificationsObserver::SendMessage() { 1580 NotificationUIManager* manager = 1581 g_browser_process->notification_ui_manager(); 1582 const BalloonCollection::Balloons& balloons = 1583 manager->balloon_collection()->GetActiveBalloons(); 1584 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1585 ListValue* list = new ListValue; 1586 return_value->Set("notifications", list); 1587 BalloonCollection::Balloons::const_iterator iter; 1588 for (iter = balloons.begin(); iter != balloons.end(); ++iter) { 1589 const Notification& notification = (*iter)->notification(); 1590 DictionaryValue* balloon = new DictionaryValue; 1591 balloon->SetString("content_url", notification.content_url().spec()); 1592 balloon->SetString("origin_url", notification.origin_url().spec()); 1593 balloon->SetString("display_source", notification.display_source()); 1594 BalloonView* view = (*iter)->view(); 1595 balloon->SetInteger("pid", base::GetProcId( 1596 view->GetHost()->render_view_host()->process()->GetHandle())); 1597 list->Append(balloon); 1598 } 1599 reply_.SendSuccess(return_value.get()); 1600 delete this; 1601} 1602 1603OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver( 1604 AutomationProvider* provider, 1605 IPC::Message* reply_message, 1606 BalloonCollection* collection, 1607 int count) 1608 : reply_(provider, reply_message), 1609 collection_(collection), 1610 count_(count) { 1611 collection->set_on_collection_changed_callback(NewCallback( 1612 this, &OnNotificationBalloonCountObserver::OnBalloonCollectionChanged)); 1613} 1614 1615void OnNotificationBalloonCountObserver::OnBalloonCollectionChanged() { 1616 if (static_cast<int>(collection_->GetActiveBalloons().size()) == count_) { 1617 collection_->set_on_collection_changed_callback(NULL); 1618 reply_.SendSuccess(NULL); 1619 delete this; 1620 } 1621} 1622 1623RendererProcessClosedObserver::RendererProcessClosedObserver( 1624 AutomationProvider* automation, 1625 IPC::Message* reply_message) 1626 : automation_(automation), 1627 reply_message_(reply_message) { 1628 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, 1629 NotificationService::AllSources()); 1630} 1631 1632void RendererProcessClosedObserver::Observe( 1633 NotificationType type, 1634 const NotificationSource& source, 1635 const NotificationDetails& details) { 1636 AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); 1637 delete this; 1638} 1639