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