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