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