1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/automation/automation_provider_observers.h" 6 7 #include <deque> 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/bind_helpers.h" 14 #include "base/callback.h" 15 #include "base/file_util.h" 16 #include "base/json/json_writer.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/stl_util.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/stringprintf.h" 22 #include "base/strings/utf_string_conversions.h" 23 #include "base/threading/thread_restrictions.h" 24 #include "base/values.h" 25 #include "chrome/app/chrome_command_ids.h" 26 #include "chrome/browser/automation/automation_provider.h" 27 #include "chrome/browser/automation/automation_provider_json.h" 28 #include "chrome/browser/bookmarks/bookmark_model.h" 29 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 30 #include "chrome/browser/browser_process.h" 31 #include "chrome/browser/chrome_notification_types.h" 32 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 33 #include "chrome/browser/extensions/crx_installer.h" 34 #include "chrome/browser/extensions/extension_host.h" 35 #include "chrome/browser/extensions/extension_service.h" 36 #include "chrome/browser/extensions/extension_system.h" 37 #include "chrome/browser/extensions/extension_tab_util.h" 38 #include "chrome/browser/history/history_types.h" 39 #include "chrome/browser/history/top_sites.h" 40 #include "chrome/browser/infobars/confirm_infobar_delegate.h" 41 #include "chrome/browser/infobars/infobar_service.h" 42 #include "chrome/browser/metrics/metric_event_duration_details.h" 43 #include "chrome/browser/notifications/balloon.h" 44 #include "chrome/browser/notifications/balloon_collection.h" 45 #include "chrome/browser/notifications/balloon_host.h" 46 #include "chrome/browser/notifications/balloon_notification_ui_manager.h" 47 #include "chrome/browser/notifications/notification.h" 48 #include "chrome/browser/password_manager/password_store_change.h" 49 #include "chrome/browser/profiles/profile.h" 50 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" 51 #include "chrome/browser/search_engines/template_url_service.h" 52 #include "chrome/browser/search_engines/template_url_service_factory.h" 53 #include "chrome/browser/sessions/session_tab_helper.h" 54 #include "chrome/browser/sessions/tab_restore_service.h" 55 #include "chrome/browser/sessions/tab_restore_service_factory.h" 56 #include "chrome/browser/ui/browser.h" 57 #include "chrome/browser/ui/browser_iterator.h" 58 #include "chrome/browser/ui/browser_list.h" 59 #include "chrome/browser/ui/browser_window.h" 60 #include "chrome/browser/ui/find_bar/find_notification_details.h" 61 #include "chrome/browser/ui/host_desktop.h" 62 #include "chrome/browser/ui/login/login_prompt.h" 63 #include "chrome/browser/ui/tabs/tab_strip_model.h" 64 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" 65 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h" 66 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 67 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h" 68 #include "chrome/common/automation_constants.h" 69 #include "chrome/common/automation_messages.h" 70 #include "chrome/common/content_settings_types.h" 71 #include "chrome/common/extensions/extension_constants.h" 72 #include "content/public/browser/dom_operation_notification_details.h" 73 #include "content/public/browser/navigation_controller.h" 74 #include "content/public/browser/notification_service.h" 75 #include "content/public/browser/render_process_host.h" 76 #include "content/public/browser/render_view_host.h" 77 #include "content/public/browser/web_contents.h" 78 #include "content/public/common/process_type.h" 79 #include "extensions/browser/process_manager.h" 80 #include "extensions/common/extension.h" 81 #include "extensions/common/manifest.h" 82 #include "extensions/common/view_type.h" 83 #include "ui/gfx/codec/png_codec.h" 84 #include "ui/gfx/rect.h" 85 #include "url/gurl.h" 86 87 using content::BrowserThread; 88 using content::DomOperationNotificationDetails; 89 using content::DownloadItem; 90 using content::DownloadManager; 91 using content::NavigationController; 92 using content::RenderViewHost; 93 using content::WebContents; 94 95 // Holds onto start and stop timestamps for a particular tab 96 class InitialLoadObserver::TabTime { 97 public: 98 explicit TabTime(base::TimeTicks started) 99 : load_start_time_(started) { 100 } 101 void set_stop_time(base::TimeTicks stopped) { 102 load_stop_time_ = stopped; 103 } 104 base::TimeTicks stop_time() const { 105 return load_stop_time_; 106 } 107 base::TimeTicks start_time() const { 108 return load_start_time_; 109 } 110 private: 111 base::TimeTicks load_start_time_; 112 base::TimeTicks load_stop_time_; 113 }; 114 115 InitialLoadObserver::InitialLoadObserver(size_t tab_count, 116 AutomationProvider* automation) 117 : automation_(automation->AsWeakPtr()), 118 crashed_tab_count_(0), 119 outstanding_tab_count_(tab_count), 120 init_time_(base::TimeTicks::Now()) { 121 if (outstanding_tab_count_ > 0) { 122 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 123 content::NotificationService::AllSources()); 124 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 125 content::NotificationService::AllSources()); 126 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 127 content::NotificationService::AllSources()); 128 } 129 } 130 131 InitialLoadObserver::~InitialLoadObserver() { 132 } 133 134 void InitialLoadObserver::Observe(int type, 135 const content::NotificationSource& source, 136 const content::NotificationDetails& details) { 137 if (type == content::NOTIFICATION_LOAD_START) { 138 if (outstanding_tab_count_ > loading_tabs_.size()) 139 loading_tabs_.insert(TabTimeMap::value_type( 140 source.map_key(), 141 TabTime(base::TimeTicks::Now()))); 142 } else if (type == content::NOTIFICATION_LOAD_STOP) { 143 if (outstanding_tab_count_ > finished_tabs_.size()) { 144 TabTimeMap::iterator iter = loading_tabs_.find(source.map_key()); 145 if (iter != loading_tabs_.end()) { 146 finished_tabs_.insert(source.map_key()); 147 iter->second.set_stop_time(base::TimeTicks::Now()); 148 } 149 } 150 } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) { 151 base::TerminationStatus status = 152 content::Details<content::RenderProcessHost::RendererClosedDetails>( 153 details)->status; 154 switch (status) { 155 case base::TERMINATION_STATUS_NORMAL_TERMINATION: 156 break; 157 158 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: 159 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 160 case base::TERMINATION_STATUS_PROCESS_CRASHED: 161 crashed_tab_count_++; 162 break; 163 164 case base::TERMINATION_STATUS_STILL_RUNNING: 165 LOG(ERROR) << "Got RENDERER_PROCESS_CLOSED notification, " 166 << "but the process is still running. We may miss further " 167 << "crash notification, resulting in hangs."; 168 break; 169 170 default: 171 LOG(ERROR) << "Unhandled termination status " << status; 172 NOTREACHED(); 173 break; 174 } 175 } else { 176 NOTREACHED(); 177 } 178 179 if (finished_tabs_.size() + crashed_tab_count_ >= outstanding_tab_count_) 180 ConditionMet(); 181 } 182 183 DictionaryValue* InitialLoadObserver::GetTimingInformation() const { 184 ListValue* items = new ListValue; 185 for (TabTimeMap::const_iterator it = loading_tabs_.begin(); 186 it != loading_tabs_.end(); 187 ++it) { 188 DictionaryValue* item = new DictionaryValue; 189 base::TimeDelta delta_start = it->second.start_time() - init_time_; 190 191 item->SetDouble("load_start_ms", delta_start.InMillisecondsF()); 192 if (it->second.stop_time().is_null()) { 193 item->Set("load_stop_ms", Value::CreateNullValue()); 194 } else { 195 base::TimeDelta delta_stop = it->second.stop_time() - init_time_; 196 item->SetDouble("load_stop_ms", delta_stop.InMillisecondsF()); 197 } 198 items->Append(item); 199 } 200 DictionaryValue* return_value = new DictionaryValue; 201 return_value->Set("tabs", items); 202 return return_value; 203 } 204 205 void InitialLoadObserver::ConditionMet() { 206 registrar_.RemoveAll(); 207 if (automation_.get()) 208 automation_->OnInitialTabLoadsComplete(); 209 } 210 211 NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation, 212 Profile* profile) 213 : automation_(automation->AsWeakPtr()) { 214 registrar_.Add(this, chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD, 215 content::Source<Profile>(profile)); 216 } 217 218 NewTabUILoadObserver::~NewTabUILoadObserver() { 219 } 220 221 void NewTabUILoadObserver::Observe(int type, 222 const content::NotificationSource& source, 223 const content::NotificationDetails& details) { 224 if (type == chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD) { 225 content::Details<int> load_time(details); 226 if (automation_.get()) { 227 automation_->Send( 228 new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr())); 229 } 230 } else { 231 NOTREACHED(); 232 } 233 } 234 235 NavigationControllerRestoredObserver::NavigationControllerRestoredObserver( 236 AutomationProvider* automation, 237 NavigationController* controller, 238 IPC::Message* reply_message) 239 : automation_(automation->AsWeakPtr()), 240 controller_(controller), 241 reply_message_(reply_message) { 242 if (FinishedRestoring()) { 243 SendDone(); 244 } else { 245 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 246 content::NotificationService::AllSources()); 247 } 248 } 249 250 NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() { 251 } 252 253 void NavigationControllerRestoredObserver::Observe( 254 int type, const content::NotificationSource& source, 255 const content::NotificationDetails& details) { 256 if (FinishedRestoring()) { 257 registrar_.RemoveAll(); 258 SendDone(); 259 } 260 } 261 262 bool NavigationControllerRestoredObserver::FinishedRestoring() { 263 return (!controller_->NeedsReload() && !controller_->GetPendingEntry() && 264 !controller_->GetWebContents()->IsLoading()); 265 } 266 267 void NavigationControllerRestoredObserver::SendDone() { 268 if (automation_.get()) { 269 AutomationJSONReply(automation_.get(), reply_message_.release()) 270 .SendSuccess(NULL); 271 } 272 delete this; 273 } 274 275 NavigationNotificationObserver::NavigationNotificationObserver( 276 NavigationController* controller, 277 AutomationProvider* automation, 278 IPC::Message* reply_message, 279 int number_of_navigations, 280 bool include_current_navigation, 281 bool use_json_interface) 282 : automation_(automation->AsWeakPtr()), 283 reply_message_(reply_message), 284 controller_(controller), 285 navigations_remaining_(number_of_navigations), 286 navigation_started_(false), 287 use_json_interface_(use_json_interface) { 288 if (number_of_navigations == 0) { 289 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); 290 return; 291 } 292 DCHECK_LT(0, navigations_remaining_); 293 content::Source<NavigationController> source(controller_); 294 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); 295 registrar_.Add(this, content::NOTIFICATION_LOAD_START, source); 296 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); 297 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source); 298 registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source); 299 registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source); 300 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 301 content::NotificationService::AllSources()); 302 303 if (include_current_navigation && controller->GetWebContents()->IsLoading()) 304 navigation_started_ = true; 305 } 306 307 NavigationNotificationObserver::~NavigationNotificationObserver() { 308 } 309 310 void NavigationNotificationObserver::Observe( 311 int type, const content::NotificationSource& source, 312 const content::NotificationDetails& details) { 313 if (!automation_.get()) { 314 delete this; 315 return; 316 } 317 318 // We listen for 2 events to determine when the navigation started because: 319 // - when this is used by the WaitForNavigation method, we might be invoked 320 // afer the load has started (but not after the entry was committed, as 321 // WaitForNavigation compares times of the last navigation). 322 // - when this is used with a page requiring authentication, we will not get 323 // a chrome::NAV_ENTRY_COMMITTED until after we authenticate, so 324 // we need the chrome::LOAD_START. 325 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED || 326 type == content::NOTIFICATION_LOAD_START) { 327 navigation_started_ = true; 328 } else if (type == content::NOTIFICATION_LOAD_STOP) { 329 if (navigation_started_) { 330 navigation_started_ = false; 331 if (--navigations_remaining_ == 0) 332 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); 333 } 334 } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED || 335 type == chrome::NOTIFICATION_AUTH_CANCELLED) { 336 // Treat this as if navigation started again, since load start/stop don't 337 // occur while authentication is ongoing. 338 navigation_started_ = true; 339 } else if (type == chrome::NOTIFICATION_AUTH_NEEDED) { 340 // Respond that authentication is needed. 341 navigation_started_ = false; 342 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); 343 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { 344 ConditionMet(AUTOMATION_MSG_NAVIGATION_BLOCKED_BY_MODAL_DIALOG); 345 } else { 346 NOTREACHED(); 347 } 348 } 349 350 void NavigationNotificationObserver::ConditionMet( 351 AutomationMsg_NavigationResponseValues navigation_result) { 352 if (automation_.get()) { 353 if (use_json_interface_) { 354 if (navigation_result == AUTOMATION_MSG_NAVIGATION_SUCCESS) { 355 DictionaryValue dict; 356 dict.SetInteger("result", navigation_result); 357 AutomationJSONReply(automation_.get(), reply_message_.release()) 358 .SendSuccess(&dict); 359 } else { 360 AutomationJSONReply(automation_.get(), reply_message_.release()) 361 .SendError(base::StringPrintf( 362 "Navigation failed with error code=%d.", navigation_result)); 363 } 364 } else { 365 IPC::ParamTraits<int>::Write( 366 reply_message_.get(), navigation_result); 367 automation_->Send(reply_message_.release()); 368 } 369 } 370 371 delete this; 372 } 373 374 TabStripNotificationObserver::TabStripNotificationObserver( 375 int notification, AutomationProvider* automation) 376 : automation_(automation->AsWeakPtr()), 377 notification_(notification) { 378 registrar_.Add(this, notification_, 379 content::NotificationService::AllSources()); 380 } 381 382 TabStripNotificationObserver::~TabStripNotificationObserver() { 383 } 384 385 void TabStripNotificationObserver::Observe( 386 int type, 387 const content::NotificationSource& source, 388 const content::NotificationDetails& details) { 389 DCHECK_EQ(notification_, type); 390 if (type == chrome::NOTIFICATION_TAB_PARENTED) { 391 ObserveTab(&content::Source<content::WebContents>(source)->GetController()); 392 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { 393 ObserveTab(&content::Source<content::WebContents>(source)->GetController()); 394 } else { 395 ObserveTab(content::Source<NavigationController>(source).ptr()); 396 } 397 delete this; 398 } 399 400 TabAppendedNotificationObserver::TabAppendedNotificationObserver( 401 Browser* parent, 402 AutomationProvider* automation, 403 IPC::Message* reply_message, 404 bool use_json_interface) 405 : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED, 406 automation), 407 parent_(parent), 408 reply_message_(reply_message), 409 use_json_interface_(use_json_interface) { 410 } 411 412 TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {} 413 414 void TabAppendedNotificationObserver::ObserveTab( 415 NavigationController* controller) { 416 if (!automation_.get() || !reply_message_.get()) 417 return; 418 419 if (automation_->GetIndexForNavigationController(controller, parent_) == 420 TabStripModel::kNoTab) { 421 // This tab notification doesn't belong to the parent_. 422 return; 423 } 424 425 new NavigationNotificationObserver(controller, 426 automation_.get(), 427 reply_message_.release(), 428 1, 429 false, 430 use_json_interface_); 431 } 432 433 IPC::Message* TabAppendedNotificationObserver::ReleaseReply() { 434 return reply_message_.release(); 435 } 436 437 TabClosedNotificationObserver::TabClosedNotificationObserver( 438 AutomationProvider* automation, 439 bool wait_until_closed, 440 IPC::Message* reply_message, 441 bool use_json_interface) 442 : TabStripNotificationObserver((wait_until_closed ? 443 static_cast<int>(content::NOTIFICATION_WEB_CONTENTS_DESTROYED) : 444 static_cast<int>(chrome::NOTIFICATION_TAB_CLOSING)), automation), 445 reply_message_(reply_message), 446 use_json_interface_(use_json_interface), 447 for_browser_command_(false) { 448 } 449 450 TabClosedNotificationObserver::~TabClosedNotificationObserver() {} 451 452 void TabClosedNotificationObserver::ObserveTab( 453 NavigationController* controller) { 454 if (!automation_.get()) 455 return; 456 457 if (use_json_interface_) { 458 AutomationJSONReply(automation_.get(), reply_message_.release()) 459 .SendSuccess(NULL); 460 } else { 461 if (for_browser_command_) { 462 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), 463 true); 464 } else { 465 AutomationMsg_CloseTab::WriteReplyParams(reply_message_.get(), true); 466 } 467 automation_->Send(reply_message_.release()); 468 } 469 } 470 471 void TabClosedNotificationObserver::set_for_browser_command( 472 bool for_browser_command) { 473 for_browser_command_ = for_browser_command; 474 } 475 476 TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation, 477 Browser* browser, 478 IPC::Message* reply_message, 479 int target_tab_count) 480 : automation_(automation->AsWeakPtr()), 481 reply_message_(reply_message), 482 tab_strip_model_(browser->tab_strip_model()), 483 target_tab_count_(target_tab_count) { 484 tab_strip_model_->AddObserver(this); 485 CheckTabCount(); 486 } 487 488 TabCountChangeObserver::~TabCountChangeObserver() { 489 tab_strip_model_->RemoveObserver(this); 490 } 491 492 void TabCountChangeObserver::TabInsertedAt(WebContents* contents, 493 int index, 494 bool foreground) { 495 CheckTabCount(); 496 } 497 498 void TabCountChangeObserver::TabDetachedAt(WebContents* contents, 499 int index) { 500 CheckTabCount(); 501 } 502 503 void TabCountChangeObserver::TabStripModelDeleted() { 504 if (automation_.get()) { 505 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams( 506 reply_message_.get(), false); 507 automation_->Send(reply_message_.release()); 508 } 509 510 delete this; 511 } 512 513 void TabCountChangeObserver::CheckTabCount() { 514 if (tab_strip_model_->count() != target_tab_count_) 515 return; 516 517 if (automation_.get()) { 518 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams( 519 reply_message_.get(), true); 520 automation_->Send(reply_message_.release()); 521 } 522 523 delete this; 524 } 525 526 bool DidExtensionViewsStopLoading(extensions::ProcessManager* manager) { 527 extensions::ProcessManager::ViewSet all_views = manager->GetAllViews(); 528 for (extensions::ProcessManager::ViewSet::const_iterator iter = 529 all_views.begin(); 530 iter != all_views.end(); ++iter) { 531 if ((*iter)->IsLoading()) 532 return false; 533 } 534 return true; 535 } 536 537 ExtensionUninstallObserver::ExtensionUninstallObserver( 538 AutomationProvider* automation, 539 IPC::Message* reply_message, 540 const std::string& id) 541 : automation_(automation->AsWeakPtr()), 542 reply_message_(reply_message), 543 id_(id) { 544 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 545 content::NotificationService::AllSources()); 546 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED, 547 content::NotificationService::AllSources()); 548 } 549 550 ExtensionUninstallObserver::~ExtensionUninstallObserver() { 551 } 552 553 void ExtensionUninstallObserver::Observe( 554 int type, 555 const content::NotificationSource& source, 556 const content::NotificationDetails& details) { 557 if (!automation_.get()) { 558 delete this; 559 return; 560 } 561 562 switch (type) { 563 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { 564 if (id_ == content::Details<extensions::Extension>(details).ptr()->id()) { 565 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 566 return_value->SetBoolean("success", true); 567 AutomationJSONReply(automation_.get(), reply_message_.release()) 568 .SendSuccess(return_value.get()); 569 delete this; 570 return; 571 } 572 break; 573 } 574 575 case chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED: { 576 const extensions::Extension* extension = 577 content::Details<extensions::Extension>(details).ptr(); 578 if (id_ == extension->id()) { 579 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 580 return_value->SetBoolean("success", false); 581 AutomationJSONReply(automation_.get(), reply_message_.release()) 582 .SendSuccess(return_value.get()); 583 delete this; 584 return; 585 } 586 break; 587 } 588 589 default: 590 NOTREACHED(); 591 } 592 } 593 594 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver( 595 extensions::ProcessManager* manager, ExtensionService* service, 596 AutomationProvider* automation, IPC::Message* reply_message) 597 : manager_(manager), 598 service_(service), 599 automation_(automation->AsWeakPtr()), 600 reply_message_(reply_message), 601 extension_(NULL) { 602 Init(); 603 } 604 605 ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() { 606 } 607 608 void ExtensionReadyNotificationObserver::Init() { 609 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 610 content::NotificationService::AllSources()); 611 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 612 content::NotificationService::AllSources()); 613 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, 614 content::NotificationService::AllSources()); 615 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 616 content::NotificationService::AllSources()); 617 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, 618 content::NotificationService::AllSources()); 619 } 620 621 void ExtensionReadyNotificationObserver::Observe( 622 int type, const content::NotificationSource& source, 623 const content::NotificationDetails& details) { 624 if (!automation_.get()) { 625 delete this; 626 return; 627 } 628 629 switch (type) { 630 case content::NOTIFICATION_LOAD_STOP: 631 // Only continue on with this method if our extension has been loaded 632 // and all the extension views have stopped loading. 633 if (!extension_ || !DidExtensionViewsStopLoading(manager_)) 634 return; 635 break; 636 case chrome::NOTIFICATION_EXTENSION_LOADED: { 637 const extensions::Extension* loaded_extension = 638 content::Details<const extensions::Extension>(details).ptr(); 639 // Only track an internal or unpacked extension load. 640 extensions::Manifest::Location location = loaded_extension->location(); 641 if (location != extensions::Manifest::INTERNAL && 642 !extensions::Manifest::IsUnpackedLocation(location)) 643 return; 644 extension_ = loaded_extension; 645 if (!DidExtensionViewsStopLoading(manager_)) 646 return; 647 // For some reason, the background extension view is not yet 648 // created at this point so just checking whether all extension views 649 // are loaded is not sufficient. If background page is not ready, 650 // we wait for NOTIFICATION_LOAD_STOP. 651 if (!service_->IsBackgroundPageReady(extension_)) 652 return; 653 break; 654 } 655 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: 656 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: 657 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: 658 break; 659 default: 660 NOTREACHED(); 661 break; 662 } 663 664 AutomationJSONReply reply(automation_.get(), reply_message_.release()); 665 if (extension_) { 666 DictionaryValue dict; 667 dict.SetString("id", extension_->id()); 668 reply.SendSuccess(&dict); 669 } else { 670 reply.SendError("Extension could not be installed"); 671 } 672 delete this; 673 } 674 675 ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver() 676 : did_receive_unload_notification_(false) { 677 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 678 content::NotificationService::AllSources()); 679 } 680 681 ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() { 682 } 683 684 void ExtensionUnloadNotificationObserver::Observe( 685 int type, const content::NotificationSource& source, 686 const content::NotificationDetails& details) { 687 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { 688 did_receive_unload_notification_ = true; 689 } else { 690 NOTREACHED(); 691 } 692 } 693 694 ExtensionsUpdatedObserver::ExtensionsUpdatedObserver( 695 extensions::ProcessManager* manager, AutomationProvider* automation, 696 IPC::Message* reply_message) 697 : manager_(manager), automation_(automation->AsWeakPtr()), 698 reply_message_(reply_message), updater_finished_(false) { 699 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 700 content::NotificationService::AllSources()); 701 } 702 703 ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() { 704 } 705 706 void ExtensionsUpdatedObserver::Observe( 707 int type, const content::NotificationSource& source, 708 const content::NotificationDetails& details) { 709 if (!automation_.get()) { 710 delete this; 711 return; 712 } 713 714 DCHECK(type == content::NOTIFICATION_LOAD_STOP); 715 MaybeReply(); 716 } 717 718 void ExtensionsUpdatedObserver::UpdateCheckFinished() { 719 if (!automation_.get()) { 720 delete this; 721 return; 722 } 723 724 // Extension updater has completed updating all extensions. 725 updater_finished_ = true; 726 MaybeReply(); 727 } 728 729 void ExtensionsUpdatedObserver::MaybeReply() { 730 // Send the reply if (1) the extension updater has finished updating all 731 // extensions; and (2) all extension views have stopped loading. 732 if (updater_finished_ && DidExtensionViewsStopLoading(manager_)) { 733 AutomationJSONReply reply(automation_.get(), reply_message_.release()); 734 reply.SendSuccess(NULL); 735 delete this; 736 } 737 } 738 739 BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver( 740 AutomationProvider* automation, 741 IPC::Message* reply_message, 742 bool use_json_interface) 743 : automation_(automation->AsWeakPtr()), 744 reply_message_(reply_message), 745 new_window_id_(extension_misc::kUnknownWindowId), 746 use_json_interface_(use_json_interface), 747 for_browser_command_(false) { 748 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 749 content::NotificationService::AllBrowserContextsAndSources()); 750 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 751 content::NotificationService::AllBrowserContextsAndSources()); 752 } 753 754 BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() { 755 } 756 757 void BrowserOpenedNotificationObserver::Observe( 758 int type, 759 const content::NotificationSource& source, 760 const content::NotificationDetails& details) { 761 if (!automation_.get()) { 762 delete this; 763 return; 764 } 765 766 if (type == chrome::NOTIFICATION_BROWSER_OPENED) { 767 // Store the new browser ID and continue waiting for a new tab within it 768 // to stop loading. 769 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId( 770 content::Source<Browser>(source).ptr()); 771 } else { 772 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); 773 // Only send the result if the loaded tab is in the new window. 774 NavigationController* controller = 775 content::Source<NavigationController>(source).ptr(); 776 SessionTabHelper* session_tab_helper = 777 SessionTabHelper::FromWebContents(controller->GetWebContents()); 778 int window_id = session_tab_helper ? session_tab_helper->window_id().id() 779 : -1; 780 if (window_id == new_window_id_) { 781 if (use_json_interface_) { 782 AutomationJSONReply(automation_.get(), reply_message_.release()) 783 .SendSuccess(NULL); 784 } else { 785 if (for_browser_command_) { 786 AutomationMsg_WindowExecuteCommand::WriteReplyParams( 787 reply_message_.get(), true); 788 } 789 automation_->Send(reply_message_.release()); 790 } 791 delete this; 792 return; 793 } 794 } 795 } 796 797 void BrowserOpenedNotificationObserver::set_for_browser_command( 798 bool for_browser_command) { 799 for_browser_command_ = for_browser_command; 800 } 801 802 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver( 803 Browser* browser, 804 AutomationProvider* automation, 805 IPC::Message* reply_message, 806 bool use_json_interface) 807 : automation_(automation->AsWeakPtr()), 808 reply_message_(reply_message), 809 use_json_interface_(use_json_interface), 810 for_browser_command_(false) { 811 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, 812 content::Source<Browser>(browser)); 813 } 814 815 BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {} 816 817 void BrowserClosedNotificationObserver::Observe( 818 int type, const content::NotificationSource& source, 819 const content::NotificationDetails& details) { 820 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSED, type); 821 822 if (!automation_.get()) { 823 delete this; 824 return; 825 } 826 827 // The automation layer doesn't support non-native desktops. 828 int browser_count = static_cast<int>(BrowserList::GetInstance( 829 chrome::HOST_DESKTOP_TYPE_NATIVE)->size()); 830 // We get the notification before the browser is removed from the BrowserList. 831 bool app_closing = browser_count == 1; 832 833 if (use_json_interface_) { 834 AutomationJSONReply(automation_.get(), reply_message_.release()) 835 .SendSuccess(NULL); 836 } else { 837 if (for_browser_command_) { 838 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), 839 true); 840 } else { 841 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true, 842 app_closing); 843 } 844 automation_->Send(reply_message_.release()); 845 } 846 delete this; 847 } 848 849 void BrowserClosedNotificationObserver::set_for_browser_command( 850 bool for_browser_command) { 851 for_browser_command_ = for_browser_command; 852 } 853 854 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver( 855 int target_count, 856 AutomationProvider* automation, 857 IPC::Message* reply_message) 858 : target_count_(target_count), 859 automation_(automation->AsWeakPtr()), 860 reply_message_(reply_message) { 861 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 862 content::NotificationService::AllBrowserContextsAndSources()); 863 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, 864 content::NotificationService::AllBrowserContextsAndSources()); 865 } 866 867 BrowserCountChangeNotificationObserver:: 868 ~BrowserCountChangeNotificationObserver() {} 869 870 void BrowserCountChangeNotificationObserver::Observe( 871 int type, 872 const content::NotificationSource& source, 873 const content::NotificationDetails& details) { 874 DCHECK(type == chrome::NOTIFICATION_BROWSER_OPENED || 875 type == chrome::NOTIFICATION_BROWSER_CLOSED); 876 877 // The automation layer doesn't support non-native desktops. 878 int current_count = static_cast<int>(BrowserList::GetInstance( 879 chrome::HOST_DESKTOP_TYPE_NATIVE)->size()); 880 if (type == chrome::NOTIFICATION_BROWSER_CLOSED) { 881 // At the time of the notification the browser being closed is not removed 882 // from the list. The real count is one less than the reported count. 883 DCHECK_LT(0, current_count); 884 current_count--; 885 } 886 887 if (!automation_.get()) { 888 delete this; 889 return; 890 } 891 892 if (current_count == target_count_) { 893 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams( 894 reply_message_.get(), true); 895 automation_->Send(reply_message_.release()); 896 delete this; 897 } 898 } 899 900 namespace { 901 902 // Define mapping from command to notification 903 struct CommandNotification { 904 int command; 905 int notification_type; 906 }; 907 908 const struct CommandNotification command_notifications[] = { 909 {IDC_DUPLICATE_TAB, chrome::NOTIFICATION_TAB_PARENTED}, 910 911 // Returns as soon as the restored tab is created. To further wait until 912 // the content page is loaded, use WaitForTabToBeRestored. 913 {IDC_RESTORE_TAB, chrome::NOTIFICATION_TAB_PARENTED}, 914 915 // For the following commands, we need to wait for a new tab to be created, 916 // load to finish, and title to change. 917 {IDC_MANAGE_EXTENSIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, 918 {IDC_OPTIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, 919 {IDC_PRINT, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, 920 {IDC_SHOW_DOWNLOADS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, 921 {IDC_SHOW_HISTORY, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, 922 }; 923 924 } // namespace 925 926 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() { 927 } 928 929 // static 930 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver( 931 AutomationProvider* automation, 932 Browser* browser, 933 int command, 934 IPC::Message* reply_message, 935 bool use_json_interface) { 936 bool result = true; 937 switch (command) { 938 case IDC_NEW_TAB: { 939 new NewTabObserver(automation, reply_message, use_json_interface); 940 break; 941 } 942 case IDC_NEW_WINDOW: 943 case IDC_NEW_INCOGNITO_WINDOW: { 944 BrowserOpenedNotificationObserver* observer = 945 new BrowserOpenedNotificationObserver(automation, reply_message, 946 use_json_interface); 947 observer->set_for_browser_command(true); 948 break; 949 } 950 case IDC_CLOSE_WINDOW: { 951 BrowserClosedNotificationObserver* observer = 952 new BrowserClosedNotificationObserver(browser, automation, 953 reply_message, 954 use_json_interface); 955 observer->set_for_browser_command(true); 956 break; 957 } 958 case IDC_CLOSE_TAB: { 959 TabClosedNotificationObserver* observer = 960 new TabClosedNotificationObserver(automation, true, reply_message, 961 use_json_interface); 962 observer->set_for_browser_command(true); 963 break; 964 } 965 case IDC_BACK: 966 case IDC_FORWARD: 967 case IDC_RELOAD: { 968 new NavigationNotificationObserver( 969 &browser->tab_strip_model()->GetActiveWebContents()->GetController(), 970 automation, reply_message, 1, false, use_json_interface); 971 break; 972 } 973 default: { 974 ExecuteBrowserCommandObserver* observer = 975 new ExecuteBrowserCommandObserver(automation, reply_message, 976 use_json_interface); 977 if (!observer->Register(command)) { 978 observer->ReleaseReply(); 979 delete observer; 980 result = false; 981 } 982 break; 983 } 984 } 985 return result; 986 } 987 988 void ExecuteBrowserCommandObserver::Observe( 989 int type, const content::NotificationSource& source, 990 const content::NotificationDetails& details) { 991 if (type == notification_type_) { 992 if (automation_.get()) { 993 if (use_json_interface_) { 994 AutomationJSONReply(automation_.get(), reply_message_.release()) 995 .SendSuccess(NULL); 996 } else { 997 AutomationMsg_WindowExecuteCommand::WriteReplyParams( 998 reply_message_.get(), true); 999 automation_->Send(reply_message_.release()); 1000 } 1001 } 1002 delete this; 1003 } else { 1004 NOTREACHED(); 1005 } 1006 } 1007 1008 ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver( 1009 AutomationProvider* automation, 1010 IPC::Message* reply_message, 1011 bool use_json_interface) 1012 : automation_(automation->AsWeakPtr()), 1013 notification_type_(content::NOTIFICATION_ALL), 1014 reply_message_(reply_message), 1015 use_json_interface_(use_json_interface) { 1016 } 1017 1018 bool ExecuteBrowserCommandObserver::Register(int command) { 1019 if (!Getint(command, ¬ification_type_)) 1020 return false; 1021 registrar_.Add(this, notification_type_, 1022 content::NotificationService::AllSources()); 1023 return true; 1024 } 1025 1026 bool ExecuteBrowserCommandObserver::Getint( 1027 int command, int* type) { 1028 if (!type) 1029 return false; 1030 bool found = false; 1031 for (unsigned int i = 0; i < arraysize(command_notifications); i++) { 1032 if (command_notifications[i].command == command) { 1033 *type = command_notifications[i].notification_type; 1034 found = true; 1035 break; 1036 } 1037 } 1038 return found; 1039 } 1040 1041 IPC::Message* ExecuteBrowserCommandObserver::ReleaseReply() { 1042 return reply_message_.release(); 1043 } 1044 1045 FindInPageNotificationObserver::FindInPageNotificationObserver( 1046 AutomationProvider* automation, WebContents* parent_tab, 1047 bool reply_with_json, IPC::Message* reply_message) 1048 : automation_(automation->AsWeakPtr()), 1049 active_match_ordinal_(-1), 1050 reply_with_json_(reply_with_json), 1051 reply_message_(reply_message) { 1052 registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, 1053 content::Source<WebContents>(parent_tab)); 1054 } 1055 1056 FindInPageNotificationObserver::~FindInPageNotificationObserver() { 1057 } 1058 1059 void FindInPageNotificationObserver::Observe( 1060 int type, const content::NotificationSource& source, 1061 const content::NotificationDetails& details) { 1062 content::Details<FindNotificationDetails> find_details(details); 1063 if (!(find_details->final_update() && reply_message_ != NULL)) { 1064 DVLOG(1) << "Ignoring, since we only care about the final message"; 1065 return; 1066 } 1067 1068 if (!automation_.get()) { 1069 delete this; 1070 return; 1071 } 1072 1073 // We get multiple responses and one of those will contain the ordinal. 1074 // This message comes to us before the final update is sent. 1075 if (find_details->request_id() == kFindInPageRequestId) { 1076 if (reply_with_json_) { 1077 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1078 return_value->SetInteger("match_count", 1079 find_details->number_of_matches()); 1080 gfx::Rect rect = find_details->selection_rect(); 1081 // If MatchCount is > 0, then rect should not be Empty. 1082 // We dont guard it here because we want to let the test 1083 // code catch this invalid case if needed. 1084 if (!rect.IsEmpty()) { 1085 return_value->SetInteger("match_left", rect.x()); 1086 return_value->SetInteger("match_top", rect.y()); 1087 return_value->SetInteger("match_right", rect.right()); 1088 return_value->SetInteger("match_bottom", rect.bottom()); 1089 } 1090 AutomationJSONReply(automation_.get(), reply_message_.release()) 1091 .SendSuccess(return_value.get()); 1092 delete this; 1093 } else { 1094 if (find_details->active_match_ordinal() > -1) { 1095 active_match_ordinal_ = find_details->active_match_ordinal(); 1096 AutomationMsg_Find::WriteReplyParams(reply_message_.get(), 1097 active_match_ordinal_, find_details->number_of_matches()); 1098 automation_->Send(reply_message_.release()); 1099 } 1100 } 1101 } 1102 } 1103 1104 // static 1105 const int FindInPageNotificationObserver::kFindInPageRequestId = -1; 1106 1107 DomOperationObserver::DomOperationObserver(int automation_id) 1108 : automation_id_(automation_id) { 1109 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE, 1110 content::NotificationService::AllSources()); 1111 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 1112 content::NotificationService::AllSources()); 1113 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 1114 content::NotificationService::AllSources()); 1115 } 1116 1117 DomOperationObserver::~DomOperationObserver() {} 1118 1119 void DomOperationObserver::Observe( 1120 int type, const content::NotificationSource& source, 1121 const content::NotificationDetails& details) { 1122 if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) { 1123 content::Details<DomOperationNotificationDetails> dom_op_details(details); 1124 if (dom_op_details->automation_id == automation_id_) 1125 OnDomOperationCompleted(dom_op_details->json); 1126 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { 1127 OnJavascriptBlocked(); 1128 } else { 1129 DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type); 1130 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 1131 if (web_contents) { 1132 TabSpecificContentSettings* tab_content_settings = 1133 TabSpecificContentSettings::FromWebContents(web_contents); 1134 if (tab_content_settings && 1135 tab_content_settings->IsContentBlocked( 1136 CONTENT_SETTINGS_TYPE_JAVASCRIPT)) 1137 OnJavascriptBlocked(); 1138 } 1139 } 1140 } 1141 1142 DomOperationMessageSender::DomOperationMessageSender( 1143 AutomationProvider* automation, 1144 IPC::Message* reply_message, 1145 bool use_json_interface) 1146 : DomOperationObserver(0), 1147 automation_(automation->AsWeakPtr()), 1148 reply_message_(reply_message), 1149 use_json_interface_(use_json_interface) { 1150 } 1151 1152 DomOperationMessageSender::~DomOperationMessageSender() {} 1153 1154 void DomOperationMessageSender::OnDomOperationCompleted( 1155 const std::string& json) { 1156 if (automation_.get()) { 1157 if (use_json_interface_) { 1158 DictionaryValue dict; 1159 dict.SetString("result", json); 1160 AutomationJSONReply(automation_.get(), reply_message_.release()) 1161 .SendSuccess(&dict); 1162 } else { 1163 AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json); 1164 automation_->Send(reply_message_.release()); 1165 } 1166 } 1167 delete this; 1168 } 1169 1170 void DomOperationMessageSender::OnJavascriptBlocked() { 1171 if (automation_.get() && use_json_interface_) { 1172 AutomationJSONReply(automation_.get(), reply_message_.release()) 1173 .SendError("Javascript execution was blocked"); 1174 delete this; 1175 } 1176 } 1177 1178 MetricEventDurationObserver::MetricEventDurationObserver() { 1179 registrar_.Add(this, chrome::NOTIFICATION_METRIC_EVENT_DURATION, 1180 content::NotificationService::AllSources()); 1181 } 1182 1183 MetricEventDurationObserver::~MetricEventDurationObserver() {} 1184 1185 int MetricEventDurationObserver::GetEventDurationMs( 1186 const std::string& event_name) { 1187 EventDurationMap::const_iterator it = durations_.find(event_name); 1188 if (it == durations_.end()) 1189 return -1; 1190 return it->second; 1191 } 1192 1193 void MetricEventDurationObserver::Observe( 1194 int type, 1195 const content::NotificationSource& source, 1196 const content::NotificationDetails& details) { 1197 if (type != chrome::NOTIFICATION_METRIC_EVENT_DURATION) { 1198 NOTREACHED(); 1199 return; 1200 } 1201 MetricEventDurationDetails* metric_event_duration = 1202 content::Details<MetricEventDurationDetails>(details).ptr(); 1203 durations_[metric_event_duration->event_name] = 1204 metric_event_duration->duration_ms; 1205 } 1206 1207 InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation, 1208 IPC::Message* reply_message, 1209 WebContents* web_contents, 1210 size_t target_count) 1211 : automation_(automation->AsWeakPtr()), 1212 reply_message_(reply_message), 1213 web_contents_(web_contents), 1214 target_count_(target_count) { 1215 content::Source<InfoBarService> source( 1216 InfoBarService::FromWebContents(web_contents)); 1217 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, 1218 source); 1219 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, 1220 source); 1221 CheckCount(); 1222 } 1223 1224 InfoBarCountObserver::~InfoBarCountObserver() {} 1225 1226 void InfoBarCountObserver::Observe( 1227 int type, 1228 const content::NotificationSource& source, 1229 const content::NotificationDetails& details) { 1230 DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED || 1231 type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED); 1232 CheckCount(); 1233 } 1234 1235 void InfoBarCountObserver::CheckCount() { 1236 if (InfoBarService::FromWebContents(web_contents_)->infobar_count() != 1237 target_count_) 1238 return; 1239 1240 if (automation_.get()) { 1241 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(), 1242 true); 1243 automation_->Send(reply_message_.release()); 1244 } 1245 delete this; 1246 } 1247 1248 AutomationProviderBookmarkModelObserver:: 1249 AutomationProviderBookmarkModelObserver( 1250 AutomationProvider* provider, 1251 IPC::Message* reply_message, 1252 BookmarkModel* model, 1253 bool use_json_interface) 1254 : automation_provider_(provider->AsWeakPtr()), 1255 reply_message_(reply_message), 1256 model_(model), 1257 use_json_interface_(use_json_interface) { 1258 model_->AddObserver(this); 1259 } 1260 1261 AutomationProviderBookmarkModelObserver:: 1262 ~AutomationProviderBookmarkModelObserver() { 1263 model_->RemoveObserver(this); 1264 } 1265 1266 void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model, 1267 bool ids_reassigned) { 1268 ReplyAndDelete(true); 1269 } 1270 1271 void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted( 1272 BookmarkModel* model) { 1273 ReplyAndDelete(false); 1274 } 1275 1276 IPC::Message* AutomationProviderBookmarkModelObserver::ReleaseReply() { 1277 return reply_message_.release(); 1278 } 1279 1280 void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) { 1281 if (automation_provider_.get()) { 1282 if (use_json_interface_) { 1283 AutomationJSONReply(automation_provider_.get(), reply_message_.release()) 1284 .SendSuccess(NULL); 1285 } else { 1286 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams( 1287 reply_message_.get(), success); 1288 automation_provider_->Send(reply_message_.release()); 1289 } 1290 } 1291 delete this; 1292 } 1293 1294 AutomationProviderDownloadUpdatedObserver:: 1295 AutomationProviderDownloadUpdatedObserver( 1296 AutomationProvider* provider, 1297 IPC::Message* reply_message, 1298 bool wait_for_open, 1299 bool incognito) 1300 : provider_(provider->AsWeakPtr()), 1301 reply_message_(reply_message), 1302 wait_for_open_(wait_for_open), 1303 incognito_(incognito) { 1304 } 1305 1306 AutomationProviderDownloadUpdatedObserver:: 1307 ~AutomationProviderDownloadUpdatedObserver() {} 1308 1309 void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated( 1310 DownloadItem* download) { 1311 // If this observer is watching for open, only send the reply if the download 1312 // has been auto-opened. 1313 if (wait_for_open_ && !download->GetAutoOpened()) 1314 return; 1315 1316 download->RemoveObserver(this); 1317 1318 if (provider_.get()) { 1319 scoped_ptr<DictionaryValue> return_value( 1320 provider_->GetDictionaryFromDownloadItem(download, incognito_)); 1321 AutomationJSONReply(provider_.get(), reply_message_.release()) 1322 .SendSuccess(return_value.get()); 1323 } 1324 delete this; 1325 } 1326 1327 void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened( 1328 DownloadItem* download) { 1329 download->RemoveObserver(this); 1330 1331 if (provider_.get()) { 1332 scoped_ptr<DictionaryValue> return_value( 1333 provider_->GetDictionaryFromDownloadItem(download, incognito_)); 1334 AutomationJSONReply(provider_.get(), reply_message_.release()) 1335 .SendSuccess(return_value.get()); 1336 } 1337 delete this; 1338 } 1339 1340 AutomationProviderDownloadModelChangedObserver:: 1341 AutomationProviderDownloadModelChangedObserver( 1342 AutomationProvider* provider, 1343 IPC::Message* reply_message, 1344 DownloadManager* download_manager) 1345 : provider_(provider->AsWeakPtr()), 1346 reply_message_(reply_message), 1347 notifier_(download_manager, this) { 1348 } 1349 1350 AutomationProviderDownloadModelChangedObserver:: 1351 ~AutomationProviderDownloadModelChangedObserver() {} 1352 1353 void AutomationProviderDownloadModelChangedObserver::ModelChanged() { 1354 if (provider_.get()) 1355 AutomationJSONReply(provider_.get(), reply_message_.release()) 1356 .SendSuccess(NULL); 1357 delete this; 1358 } 1359 1360 void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated( 1361 DownloadManager* manager, DownloadItem* item) { 1362 ModelChanged(); 1363 } 1364 1365 void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved( 1366 DownloadManager* manager, DownloadItem* item) { 1367 ModelChanged(); 1368 } 1369 1370 AllDownloadsCompleteObserver::AllDownloadsCompleteObserver( 1371 AutomationProvider* provider, 1372 IPC::Message* reply_message, 1373 DownloadManager* download_manager, 1374 ListValue* pre_download_ids) 1375 : provider_(provider->AsWeakPtr()), 1376 reply_message_(reply_message), 1377 download_manager_(download_manager) { 1378 for (ListValue::iterator it = pre_download_ids->begin(); 1379 it != pre_download_ids->end(); ++it) { 1380 int val = 0; 1381 if ((*it)->GetAsInteger(&val)) { 1382 pre_download_ids_.insert(val); 1383 } else { 1384 AutomationJSONReply(provider_.get(), reply_message_.release()) 1385 .SendError("Cannot convert ID of prior download to integer."); 1386 delete this; 1387 return; 1388 } 1389 } 1390 download_manager_->AddObserver(this); 1391 DownloadManager::DownloadVector all_items; 1392 download_manager->GetAllDownloads(&all_items); 1393 for (DownloadManager::DownloadVector::const_iterator 1394 it = all_items.begin(); it != all_items.end(); ++it) { 1395 OnDownloadCreated(download_manager_, *it); 1396 } 1397 ReplyIfNecessary(); 1398 } 1399 1400 AllDownloadsCompleteObserver::~AllDownloadsCompleteObserver() { 1401 if (download_manager_) { 1402 download_manager_->RemoveObserver(this); 1403 download_manager_ = NULL; 1404 } 1405 for (std::set<DownloadItem*>::const_iterator it = pending_downloads_.begin(); 1406 it != pending_downloads_.end(); ++it) { 1407 (*it)->RemoveObserver(this); 1408 } 1409 pending_downloads_.clear(); 1410 } 1411 1412 void AllDownloadsCompleteObserver::ManagerGoingDown(DownloadManager* manager) { 1413 DCHECK_EQ(manager, download_manager_); 1414 download_manager_->RemoveObserver(this); 1415 download_manager_ = NULL; 1416 } 1417 1418 void AllDownloadsCompleteObserver::OnDownloadCreated( 1419 DownloadManager* manager, DownloadItem* item) { 1420 // This method is also called in the c-tor for previously existing items. 1421 if (pre_download_ids_.find(item->GetId()) == pre_download_ids_.end() && 1422 item->GetState() == DownloadItem::IN_PROGRESS) { 1423 item->AddObserver(this); 1424 pending_downloads_.insert(item); 1425 } 1426 } 1427 1428 void AllDownloadsCompleteObserver::OnDownloadUpdated(DownloadItem* download) { 1429 // If the current download's status has changed to a final state (not state 1430 // "in progress"), remove it from the pending list. 1431 if (download->GetState() != DownloadItem::IN_PROGRESS) { 1432 download->RemoveObserver(this); 1433 pending_downloads_.erase(download); 1434 ReplyIfNecessary(); 1435 } 1436 } 1437 1438 void AllDownloadsCompleteObserver::ReplyIfNecessary() { 1439 if (!pending_downloads_.empty()) 1440 return; 1441 1442 download_manager_->RemoveObserver(this); 1443 if (provider_.get()) 1444 AutomationJSONReply(provider_.get(), reply_message_.release()) 1445 .SendSuccess(NULL); 1446 delete this; 1447 } 1448 1449 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver( 1450 AutomationProvider* provider, 1451 Profile* profile, 1452 IPC::Message* reply_message) 1453 : provider_(provider->AsWeakPtr()), 1454 profile_(profile), 1455 reply_message_(reply_message) { 1456 } 1457 1458 AutomationProviderSearchEngineObserver:: 1459 ~AutomationProviderSearchEngineObserver() {} 1460 1461 void AutomationProviderSearchEngineObserver::OnTemplateURLServiceChanged() { 1462 if (provider_.get()) { 1463 TemplateURLService* url_service = 1464 TemplateURLServiceFactory::GetForProfile(profile_); 1465 url_service->RemoveObserver(this); 1466 AutomationJSONReply(provider_.get(), reply_message_.release()) 1467 .SendSuccess(NULL); 1468 } 1469 delete this; 1470 } 1471 1472 AutomationProviderHistoryObserver::AutomationProviderHistoryObserver( 1473 AutomationProvider* provider, 1474 IPC::Message* reply_message) 1475 : provider_(provider->AsWeakPtr()), 1476 reply_message_(reply_message) { 1477 } 1478 1479 AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {} 1480 1481 void AutomationProviderHistoryObserver::HistoryQueryComplete( 1482 HistoryService::Handle request_handle, 1483 history::QueryResults* results) { 1484 if (!provider_.get()) { 1485 delete this; 1486 return; 1487 } 1488 1489 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1490 1491 ListValue* history_list = new ListValue; 1492 for (size_t i = 0; i < results->size(); ++i) { 1493 DictionaryValue* page_value = new DictionaryValue; 1494 history::URLResult const &page = (*results)[i]; 1495 page_value->SetString("title", page.title()); 1496 page_value->SetString("url", page.url().spec()); 1497 page_value->SetDouble("time", 1498 static_cast<double>(page.visit_time().ToDoubleT())); 1499 page_value->SetString("snippet", page.snippet().text()); 1500 page_value->SetBoolean( 1501 "starred", 1502 BookmarkModelFactory::GetForProfile( 1503 provider_->profile())->IsBookmarked(page.url())); 1504 history_list->Append(page_value); 1505 } 1506 1507 return_value->Set("history", history_list); 1508 // Return history info. 1509 AutomationJSONReply reply(provider_.get(), reply_message_.release()); 1510 reply.SendSuccess(return_value.get()); 1511 delete this; 1512 } 1513 1514 AutomationProviderImportSettingsObserver:: 1515 AutomationProviderImportSettingsObserver( 1516 AutomationProvider* provider, 1517 IPC::Message* reply_message) 1518 : provider_(provider->AsWeakPtr()), 1519 reply_message_(reply_message) { 1520 } 1521 1522 AutomationProviderImportSettingsObserver:: 1523 ~AutomationProviderImportSettingsObserver() {} 1524 1525 void AutomationProviderImportSettingsObserver::ImportStarted() { 1526 } 1527 1528 void AutomationProviderImportSettingsObserver::ImportItemStarted( 1529 importer::ImportItem item) { 1530 } 1531 1532 void AutomationProviderImportSettingsObserver::ImportItemEnded( 1533 importer::ImportItem item) { 1534 } 1535 1536 void AutomationProviderImportSettingsObserver::ImportEnded() { 1537 if (provider_.get()) 1538 AutomationJSONReply(provider_.get(), reply_message_.release()) 1539 .SendSuccess(NULL); 1540 delete this; 1541 } 1542 1543 AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver( 1544 AutomationProvider* provider, 1545 IPC::Message* reply_message) 1546 : provider_(provider->AsWeakPtr()), 1547 reply_message_(reply_message) { 1548 } 1549 1550 AutomationProviderGetPasswordsObserver:: 1551 ~AutomationProviderGetPasswordsObserver() {} 1552 1553 void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone( 1554 CancelableRequestProvider::Handle handle, 1555 const std::vector<autofill::PasswordForm*>& result) { 1556 if (!provider_.get()) { 1557 delete this; 1558 return; 1559 } 1560 1561 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1562 1563 ListValue* passwords = new ListValue; 1564 for (std::vector<autofill::PasswordForm*>::const_iterator it = 1565 result.begin(); it != result.end(); ++it) { 1566 DictionaryValue* password_val = new DictionaryValue; 1567 autofill::PasswordForm* password_form = *it; 1568 password_val->SetString("username_value", password_form->username_value); 1569 password_val->SetString("password_value", password_form->password_value); 1570 password_val->SetString("signon_realm", password_form->signon_realm); 1571 password_val->SetDouble( 1572 "time", static_cast<double>(password_form->date_created.ToDoubleT())); 1573 password_val->SetString("origin_url", password_form->origin.spec()); 1574 password_val->SetString("username_element", 1575 password_form->username_element); 1576 password_val->SetString("password_element", 1577 password_form->password_element); 1578 password_val->SetString("submit_element", password_form->submit_element); 1579 password_val->SetString("action_target", password_form->action.spec()); 1580 password_val->SetBoolean("blacklist", password_form->blacklisted_by_user); 1581 passwords->Append(password_val); 1582 } 1583 1584 return_value->Set("passwords", passwords); 1585 AutomationJSONReply(provider_.get(), reply_message_.release()) 1586 .SendSuccess(return_value.get()); 1587 delete this; 1588 } 1589 1590 void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults( 1591 const std::vector<autofill::PasswordForm*>& results) { 1592 // TODO(kaiwang): Implement when I refactor 1593 // PasswordManager::GetAutofillableLogins. 1594 NOTIMPLEMENTED(); 1595 } 1596 1597 PasswordStoreLoginsChangedObserver::PasswordStoreLoginsChangedObserver( 1598 AutomationProvider* automation, 1599 IPC::Message* reply_message, 1600 PasswordStoreChange::Type expected_type, 1601 const std::string& result_key) 1602 : automation_(automation->AsWeakPtr()), 1603 reply_message_(reply_message), 1604 expected_type_(expected_type), 1605 result_key_(result_key), 1606 done_event_(false, false) { 1607 AddRef(); 1608 } 1609 1610 PasswordStoreLoginsChangedObserver::~PasswordStoreLoginsChangedObserver() { 1611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1612 } 1613 1614 void PasswordStoreLoginsChangedObserver::Init() { 1615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1616 BrowserThread::PostTask( 1617 BrowserThread::DB, 1618 FROM_HERE, 1619 base::Bind(&PasswordStoreLoginsChangedObserver::RegisterObserversTask, 1620 this)); 1621 done_event_.Wait(); 1622 } 1623 1624 void PasswordStoreLoginsChangedObserver::RegisterObserversTask() { 1625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1626 registrar_.reset(new content::NotificationRegistrar); 1627 registrar_->Add(this, chrome::NOTIFICATION_LOGINS_CHANGED, 1628 content::NotificationService::AllSources()); 1629 done_event_.Signal(); 1630 } 1631 1632 void PasswordStoreLoginsChangedObserver::Observe( 1633 int type, 1634 const content::NotificationSource& source, 1635 const content::NotificationDetails& details) { 1636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1637 DCHECK(type == chrome::NOTIFICATION_LOGINS_CHANGED); 1638 registrar_.reset(); // Must be done from the DB thread. 1639 PasswordStoreChangeList* change_details = 1640 content::Details<PasswordStoreChangeList>(details).ptr(); 1641 if (change_details->size() != 1 || 1642 change_details->front().type() != expected_type_) { 1643 // Notify the UI thread that there's an error. 1644 std::string error = "Unexpected password store login change details."; 1645 BrowserThread::PostTask( 1646 BrowserThread::UI, 1647 FROM_HERE, 1648 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateError, this, 1649 error)); 1650 return; 1651 } 1652 1653 // Notify the UI thread that we're done listening. 1654 BrowserThread::PostTask( 1655 BrowserThread::UI, 1656 FROM_HERE, 1657 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateDone, this)); 1658 } 1659 1660 void PasswordStoreLoginsChangedObserver::IndicateDone() { 1661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1662 if (automation_.get()) { 1663 if (result_key_.empty()) { 1664 AutomationJSONReply(automation_.get(), reply_message_.release()) 1665 .SendSuccess(NULL); 1666 } else { 1667 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 1668 return_value->SetBoolean(result_key_, true); 1669 AutomationJSONReply(automation_.get(), reply_message_.release()) 1670 .SendSuccess(return_value.get()); 1671 } 1672 } 1673 Release(); 1674 } 1675 1676 void PasswordStoreLoginsChangedObserver::IndicateError( 1677 const std::string& error) { 1678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1679 if (automation_.get()) 1680 AutomationJSONReply(automation_.get(), reply_message_.release()) 1681 .SendError(error); 1682 Release(); 1683 } 1684 1685 OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver( 1686 NavigationController* controller, 1687 AutomationProvider* automation, 1688 IPC::Message* reply_message) 1689 : automation_(automation->AsWeakPtr()), 1690 reply_message_(reply_message), 1691 controller_(controller) { 1692 content::Source<NavigationController> source(controller_); 1693 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); 1694 // Pages requiring auth don't send LOAD_STOP. 1695 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source); 1696 } 1697 1698 OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() { 1699 } 1700 1701 void OmniboxAcceptNotificationObserver::Observe( 1702 int type, 1703 const content::NotificationSource& source, 1704 const content::NotificationDetails& details) { 1705 if (type == content::NOTIFICATION_LOAD_STOP || 1706 type == chrome::NOTIFICATION_AUTH_NEEDED) { 1707 if (automation_.get()) { 1708 AutomationJSONReply(automation_.get(), reply_message_.release()) 1709 .SendSuccess(NULL); 1710 } 1711 delete this; 1712 } else { 1713 NOTREACHED(); 1714 } 1715 } 1716 1717 SavePackageNotificationObserver::SavePackageNotificationObserver( 1718 content::DownloadManager* download_manager, 1719 AutomationProvider* automation, 1720 IPC::Message* reply_message) 1721 : download_manager_(download_manager), 1722 automation_(automation->AsWeakPtr()), 1723 reply_message_(reply_message) { 1724 download_manager_->AddObserver(this); 1725 } 1726 1727 SavePackageNotificationObserver::~SavePackageNotificationObserver() { 1728 download_manager_->RemoveObserver(this); 1729 } 1730 1731 void SavePackageNotificationObserver::OnSavePackageSuccessfullyFinished( 1732 content::DownloadManager* manager, content::DownloadItem* item) { 1733 if (automation_.get()) { 1734 AutomationJSONReply(automation_.get(), reply_message_.release()) 1735 .SendSuccess(NULL); 1736 } 1737 delete this; 1738 } 1739 1740 void SavePackageNotificationObserver::ManagerGoingDown( 1741 content::DownloadManager* manager) { 1742 delete this; 1743 } 1744 1745 namespace { 1746 1747 // Returns a vector of dictionaries containing information about installed apps, 1748 // as identified from a given list of extensions. The caller takes ownership 1749 // of the created vector. 1750 std::vector<DictionaryValue*>* GetAppInfoFromExtensions( 1751 const ExtensionSet* extensions, 1752 ExtensionService* ext_service) { 1753 std::vector<DictionaryValue*>* apps_list = 1754 new std::vector<DictionaryValue*>(); 1755 for (ExtensionSet::const_iterator ext = extensions->begin(); 1756 ext != extensions->end(); ++ext) { 1757 // Only return information about extensions that are actually apps. 1758 if ((*ext)->is_app()) { 1759 DictionaryValue* app_info = new DictionaryValue(); 1760 AppLauncherHandler::CreateAppInfo(ext->get(), ext_service, app_info); 1761 app_info->SetBoolean( 1762 "is_component_extension", 1763 (*ext)->location() == extensions::Manifest::COMPONENT); 1764 1765 // Convert the launch_type integer into a more descriptive string. 1766 int launch_type; 1767 const char* kLaunchType = "launch_type"; 1768 if (!app_info->GetInteger(kLaunchType, &launch_type)) { 1769 NOTREACHED() << "Can't get integer from key " << kLaunchType; 1770 continue; 1771 } 1772 if (launch_type == extensions::LAUNCH_TYPE_PINNED) { 1773 app_info->SetString(kLaunchType, "pinned"); 1774 } else if (launch_type == extensions::LAUNCH_TYPE_REGULAR) { 1775 app_info->SetString(kLaunchType, "regular"); 1776 } else if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN) { 1777 app_info->SetString(kLaunchType, "fullscreen"); 1778 } else if (launch_type == extensions::LAUNCH_TYPE_WINDOW) { 1779 app_info->SetString(kLaunchType, "window"); 1780 } else { 1781 app_info->SetString(kLaunchType, "unknown"); 1782 } 1783 1784 apps_list->push_back(app_info); 1785 } 1786 } 1787 return apps_list; 1788 } 1789 1790 } // namespace 1791 1792 NTPInfoObserver::NTPInfoObserver(AutomationProvider* automation, 1793 IPC::Message* reply_message) 1794 : automation_(automation->AsWeakPtr()), 1795 reply_message_(reply_message), 1796 request_(0), 1797 ntp_info_(new DictionaryValue) { 1798 top_sites_ = automation_->profile()->GetTopSites(); 1799 if (!top_sites_) { 1800 AutomationJSONReply(automation_.get(), reply_message_.release()) 1801 .SendError("Profile does not have service for querying the top sites."); 1802 return; 1803 } 1804 TabRestoreService* service = 1805 TabRestoreServiceFactory::GetForProfile(automation_->profile()); 1806 if (!service) { 1807 AutomationJSONReply(automation_.get(), reply_message_.release()) 1808 .SendError("No TabRestoreService."); 1809 return; 1810 } 1811 1812 // Collect information about the apps in the new tab page. 1813 ExtensionService* ext_service = extensions::ExtensionSystem::Get( 1814 automation_->profile())->extension_service(); 1815 if (!ext_service) { 1816 AutomationJSONReply(automation_.get(), reply_message_.release()) 1817 .SendError("No ExtensionService."); 1818 return; 1819 } 1820 // Process enabled extensions. 1821 ListValue* apps_list = new ListValue(); 1822 const ExtensionSet* extensions = ext_service->extensions(); 1823 std::vector<DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions( 1824 extensions, ext_service); 1825 for (std::vector<DictionaryValue*>::const_iterator app = 1826 enabled_apps->begin(); app != enabled_apps->end(); ++app) { 1827 (*app)->SetBoolean("is_disabled", false); 1828 apps_list->Append(*app); 1829 } 1830 delete enabled_apps; 1831 // Process disabled extensions. 1832 const ExtensionSet* disabled_extensions = ext_service->disabled_extensions(); 1833 std::vector<DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions( 1834 disabled_extensions, ext_service); 1835 for (std::vector<DictionaryValue*>::const_iterator app = 1836 disabled_apps->begin(); app != disabled_apps->end(); ++app) { 1837 (*app)->SetBoolean("is_disabled", true); 1838 apps_list->Append(*app); 1839 } 1840 delete disabled_apps; 1841 // Process terminated extensions. 1842 const ExtensionSet* terminated_extensions = 1843 ext_service->terminated_extensions(); 1844 std::vector<DictionaryValue*>* terminated_apps = GetAppInfoFromExtensions( 1845 terminated_extensions, ext_service); 1846 for (std::vector<DictionaryValue*>::const_iterator app = 1847 terminated_apps->begin(); app != terminated_apps->end(); ++app) { 1848 (*app)->SetBoolean("is_disabled", true); 1849 apps_list->Append(*app); 1850 } 1851 delete terminated_apps; 1852 ntp_info_->Set("apps", apps_list); 1853 1854 // Get the info that would be displayed in the recently closed section. 1855 ListValue* recently_closed_list = new ListValue; 1856 RecentlyClosedTabsHandler::CreateRecentlyClosedValues(service->entries(), 1857 recently_closed_list); 1858 ntp_info_->Set("recently_closed", recently_closed_list); 1859 1860 // Add default site URLs. 1861 ListValue* default_sites_list = new ListValue; 1862 history::MostVisitedURLList urls = top_sites_->GetPrepopulatePages(); 1863 for (size_t i = 0; i < urls.size(); ++i) { 1864 default_sites_list->Append(Value::CreateStringValue( 1865 urls[i].url.possibly_invalid_spec())); 1866 } 1867 ntp_info_->Set("default_sites", default_sites_list); 1868 1869 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_UPDATED, 1870 content::Source<history::TopSites>(top_sites_)); 1871 if (top_sites_->loaded()) { 1872 OnTopSitesLoaded(); 1873 } else { 1874 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_LOADED, 1875 content::Source<Profile>(automation_->profile())); 1876 } 1877 } 1878 1879 NTPInfoObserver::~NTPInfoObserver() {} 1880 1881 void NTPInfoObserver::Observe(int type, 1882 const content::NotificationSource& source, 1883 const content::NotificationDetails& details) { 1884 if (type == chrome::NOTIFICATION_TOP_SITES_LOADED) { 1885 OnTopSitesLoaded(); 1886 } else if (type == chrome::NOTIFICATION_TOP_SITES_UPDATED) { 1887 content::Details<CancelableRequestProvider::Handle> request_details( 1888 details); 1889 if (request_ == *request_details.ptr()) { 1890 top_sites_->GetMostVisitedURLs( 1891 base::Bind(&NTPInfoObserver::OnTopSitesReceived, 1892 base::Unretained(this)), false); 1893 } 1894 } 1895 } 1896 1897 void NTPInfoObserver::OnTopSitesLoaded() { 1898 request_ = top_sites_->StartQueryForMostVisited(); 1899 } 1900 1901 void NTPInfoObserver::OnTopSitesReceived( 1902 const history::MostVisitedURLList& visited_list) { 1903 if (!automation_.get()) { 1904 delete this; 1905 return; 1906 } 1907 1908 ListValue* list_value = new ListValue; 1909 for (size_t i = 0; i < visited_list.size(); ++i) { 1910 const history::MostVisitedURL& visited = visited_list[i]; 1911 if (visited.url.spec().empty()) 1912 break; // This is the signal that there are no more real visited sites. 1913 DictionaryValue* dict = new DictionaryValue; 1914 dict->SetString("url", visited.url.spec()); 1915 dict->SetString("title", visited.title); 1916 list_value->Append(dict); 1917 } 1918 ntp_info_->Set("most_visited", list_value); 1919 AutomationJSONReply(automation_.get(), reply_message_.release()) 1920 .SendSuccess(ntp_info_.get()); 1921 delete this; 1922 } 1923 1924 AppLaunchObserver::AppLaunchObserver( 1925 NavigationController* controller, 1926 AutomationProvider* automation, 1927 IPC::Message* reply_message, 1928 extensions::LaunchContainer launch_container) 1929 : controller_(controller), 1930 automation_(automation->AsWeakPtr()), 1931 reply_message_(reply_message), 1932 launch_container_(launch_container), 1933 new_window_id_(extension_misc::kUnknownWindowId) { 1934 if (launch_container_ == extensions::LAUNCH_CONTAINER_TAB) { 1935 // Need to wait for the currently-active tab to reload. 1936 content::Source<NavigationController> source(controller_); 1937 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); 1938 } else { 1939 // Need to wait for a new tab in a new window to load. 1940 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 1941 content::NotificationService::AllSources()); 1942 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, 1943 content::NotificationService::AllSources()); 1944 } 1945 } 1946 1947 AppLaunchObserver::~AppLaunchObserver() {} 1948 1949 void AppLaunchObserver::Observe(int type, 1950 const content::NotificationSource& source, 1951 const content::NotificationDetails& details) { 1952 if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { 1953 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId( 1954 content::Source<Browser>(source).ptr()); 1955 return; 1956 } 1957 1958 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); 1959 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents( 1960 content::Source<NavigationController>(source)->GetWebContents()); 1961 if ((launch_container_ == extensions::LAUNCH_CONTAINER_TAB) || 1962 (session_tab_helper && 1963 (session_tab_helper->window_id().id() == new_window_id_))) { 1964 if (automation_.get()) { 1965 AutomationJSONReply(automation_.get(), reply_message_.release()) 1966 .SendSuccess(NULL); 1967 } 1968 delete this; 1969 } 1970 } 1971 1972 namespace { 1973 1974 // Returns whether all active notifications have an associated process ID. 1975 bool AreActiveNotificationProcessesReady() { 1976 BalloonNotificationUIManager* manager = 1977 BalloonNotificationUIManager::GetInstanceForTesting(); 1978 const BalloonCollection::Balloons& balloons = 1979 manager->balloon_collection()->GetActiveBalloons(); 1980 BalloonCollection::Balloons::const_iterator iter; 1981 for (iter = balloons.begin(); iter != balloons.end(); ++iter) { 1982 BalloonHost* balloon_host = (*iter)->balloon_view()->GetHost(); 1983 if (balloon_host && !balloon_host->IsRenderViewReady()) 1984 return false; 1985 } 1986 return true; 1987 } 1988 1989 } // namespace 1990 1991 GetAllNotificationsObserver::GetAllNotificationsObserver( 1992 AutomationProvider* automation, 1993 IPC::Message* reply_message) 1994 : automation_(automation->AsWeakPtr()), 1995 reply_message_(reply_message) { 1996 if (AreActiveNotificationProcessesReady()) { 1997 SendMessage(); 1998 } else { 1999 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, 2000 content::NotificationService::AllSources()); 2001 } 2002 } 2003 2004 GetAllNotificationsObserver::~GetAllNotificationsObserver() {} 2005 2006 void GetAllNotificationsObserver::Observe( 2007 int type, 2008 const content::NotificationSource& source, 2009 const content::NotificationDetails& details) { 2010 if (!automation_.get()) { 2011 delete this; 2012 return; 2013 } 2014 if (AreActiveNotificationProcessesReady()) 2015 SendMessage(); 2016 } 2017 2018 base::DictionaryValue* GetAllNotificationsObserver::NotificationToJson( 2019 const Notification* note) { 2020 DictionaryValue* dict = new base::DictionaryValue(); 2021 dict->SetString("content_url", note->content_url().spec()); 2022 dict->SetString("origin_url", note->origin_url().spec()); 2023 dict->SetString("display_source", note->display_source()); 2024 dict->SetString("id", note->notification_id()); 2025 return dict; 2026 } 2027 2028 void GetAllNotificationsObserver::SendMessage() { 2029 BalloonNotificationUIManager* manager = 2030 BalloonNotificationUIManager::GetInstanceForTesting(); 2031 const BalloonCollection::Balloons& balloons = 2032 manager->balloon_collection()->GetActiveBalloons(); 2033 DictionaryValue return_value; 2034 ListValue* list = new ListValue; 2035 return_value.Set("notifications", list); 2036 BalloonCollection::Balloons::const_iterator balloon_iter; 2037 for (balloon_iter = balloons.begin(); balloon_iter != balloons.end(); 2038 ++balloon_iter) { 2039 base::DictionaryValue* note = NotificationToJson( 2040 &(*balloon_iter)->notification()); 2041 BalloonHost* balloon_host = (*balloon_iter)->balloon_view()->GetHost(); 2042 if (balloon_host) { 2043 int pid = base::GetProcId(balloon_host->web_contents()-> 2044 GetRenderViewHost()->GetProcess()->GetHandle()); 2045 note->SetInteger("pid", pid); 2046 } 2047 list->Append(note); 2048 } 2049 std::vector<const Notification*> queued_notes; 2050 manager->GetQueuedNotificationsForTesting(&queued_notes); 2051 std::vector<const Notification*>::const_iterator queued_iter; 2052 for (queued_iter = queued_notes.begin(); queued_iter != queued_notes.end(); 2053 ++queued_iter) { 2054 list->Append(NotificationToJson(*queued_iter)); 2055 } 2056 AutomationJSONReply(automation_.get(), reply_message_.release()) 2057 .SendSuccess(&return_value); 2058 delete this; 2059 } 2060 2061 NewNotificationBalloonObserver::NewNotificationBalloonObserver( 2062 AutomationProvider* provider, 2063 IPC::Message* reply_message) 2064 : automation_(provider->AsWeakPtr()), 2065 reply_message_(reply_message) { 2066 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, 2067 content::NotificationService::AllSources()); 2068 } 2069 2070 NewNotificationBalloonObserver::~NewNotificationBalloonObserver() { } 2071 2072 void NewNotificationBalloonObserver::Observe( 2073 int type, 2074 const content::NotificationSource& source, 2075 const content::NotificationDetails& details) { 2076 if (automation_.get()) { 2077 AutomationJSONReply(automation_.get(), reply_message_.release()) 2078 .SendSuccess(NULL); 2079 } 2080 delete this; 2081 } 2082 2083 OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver( 2084 AutomationProvider* provider, 2085 IPC::Message* reply_message, 2086 int count) 2087 : automation_(provider->AsWeakPtr()), 2088 reply_message_(reply_message), 2089 collection_(BalloonNotificationUIManager::GetInstanceForTesting()-> 2090 balloon_collection()), 2091 count_(count) { 2092 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, 2093 content::NotificationService::AllSources()); 2094 collection_->set_on_collection_changed_callback( 2095 base::Bind(&OnNotificationBalloonCountObserver::CheckBalloonCount, 2096 base::Unretained(this))); 2097 CheckBalloonCount(); 2098 } 2099 2100 OnNotificationBalloonCountObserver::~OnNotificationBalloonCountObserver() { 2101 } 2102 2103 void OnNotificationBalloonCountObserver::Observe( 2104 int type, 2105 const content::NotificationSource& source, 2106 const content::NotificationDetails& details) { 2107 CheckBalloonCount(); 2108 } 2109 2110 void OnNotificationBalloonCountObserver::CheckBalloonCount() { 2111 bool balloon_count_met = AreActiveNotificationProcessesReady() && 2112 static_cast<int>(collection_->GetActiveBalloons().size()) == count_; 2113 2114 if (balloon_count_met && automation_.get()) { 2115 AutomationJSONReply(automation_.get(), reply_message_.release()) 2116 .SendSuccess(NULL); 2117 } 2118 2119 if (balloon_count_met || !automation_.get()) { 2120 collection_->set_on_collection_changed_callback(base::Closure()); 2121 delete this; 2122 } 2123 } 2124 2125 RendererProcessClosedObserver::RendererProcessClosedObserver( 2126 AutomationProvider* automation, 2127 IPC::Message* reply_message) 2128 : automation_(automation->AsWeakPtr()), 2129 reply_message_(reply_message) { 2130 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 2131 content::NotificationService::AllSources()); 2132 } 2133 2134 RendererProcessClosedObserver::~RendererProcessClosedObserver() {} 2135 2136 void RendererProcessClosedObserver::Observe( 2137 int type, 2138 const content::NotificationSource& source, 2139 const content::NotificationDetails& details) { 2140 if (automation_.get()) { 2141 AutomationJSONReply(automation_.get(), reply_message_.release()) 2142 .SendSuccess(NULL); 2143 } 2144 delete this; 2145 } 2146 2147 InputEventAckNotificationObserver::InputEventAckNotificationObserver( 2148 AutomationProvider* automation, 2149 IPC::Message* reply_message, 2150 int event_type, 2151 int count) 2152 : automation_(automation->AsWeakPtr()), 2153 reply_message_(reply_message), 2154 event_type_(event_type), 2155 count_(count) { 2156 DCHECK(1 <= count); 2157 registrar_.Add( 2158 this, 2159 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, 2160 content::NotificationService::AllSources()); 2161 registrar_.Add( 2162 this, 2163 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 2164 content::NotificationService::AllSources()); 2165 } 2166 2167 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {} 2168 2169 void InputEventAckNotificationObserver::Observe( 2170 int type, 2171 const content::NotificationSource& source, 2172 const content::NotificationDetails& details) { 2173 if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { 2174 AutomationJSONReply(automation_.get(), reply_message_.release()) 2175 .SendSuccess(NULL); 2176 delete this; 2177 return; 2178 } 2179 2180 content::Details<int> request_details(details); 2181 // If the event type matches for |count_| times, replies with a JSON message. 2182 if (event_type_ == *request_details.ptr()) { 2183 if (--count_ == 0 && automation_.get()) { 2184 AutomationJSONReply(automation_.get(), reply_message_.release()) 2185 .SendSuccess(NULL); 2186 delete this; 2187 } 2188 } else { 2189 LOG(WARNING) << "Ignoring unexpected event type: " 2190 << *request_details.ptr() << " (expected: " << event_type_ 2191 << ")"; 2192 } 2193 } 2194 2195 NewTabObserver::NewTabObserver(AutomationProvider* automation, 2196 IPC::Message* reply_message, 2197 bool use_json_interface) 2198 : automation_(automation->AsWeakPtr()), 2199 reply_message_(reply_message), 2200 use_json_interface_(use_json_interface) { 2201 // Use TAB_PARENTED to detect the new tab. 2202 registrar_.Add(this, 2203 chrome::NOTIFICATION_TAB_PARENTED, 2204 content::NotificationService::AllSources()); 2205 } 2206 2207 void NewTabObserver::Observe(int type, 2208 const content::NotificationSource& source, 2209 const content::NotificationDetails& details) { 2210 DCHECK_EQ(chrome::NOTIFICATION_TAB_PARENTED, type); 2211 NavigationController* controller = 2212 &(content::Source<content::WebContents>(source).ptr()->GetController()); 2213 if (automation_.get()) { 2214 // TODO(phajdan.jr): Clean up this hack. We write the correct return type 2215 // here, but don't send the message. NavigationNotificationObserver 2216 // will wait properly for the load to finish, and send the message, 2217 // but it will also append its own return value at the end of the reply. 2218 if (!use_json_interface_) 2219 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), 2220 true); 2221 new NavigationNotificationObserver(controller, 2222 automation_.get(), 2223 reply_message_.release(), 2224 1, 2225 false, 2226 use_json_interface_); 2227 } 2228 delete this; 2229 } 2230 2231 NewTabObserver::~NewTabObserver() { 2232 } 2233 2234 WaitForProcessLauncherThreadToGoIdleObserver:: 2235 WaitForProcessLauncherThreadToGoIdleObserver( 2236 AutomationProvider* automation, IPC::Message* reply_message) 2237 : automation_(automation->AsWeakPtr()), 2238 reply_message_(reply_message) { 2239 // Balanced in RunOnUIThread. 2240 AddRef(); 2241 BrowserThread::PostTask( 2242 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 2243 base::Bind( 2244 &WaitForProcessLauncherThreadToGoIdleObserver:: 2245 RunOnProcessLauncherThread, 2246 this)); 2247 } 2248 2249 WaitForProcessLauncherThreadToGoIdleObserver:: 2250 ~WaitForProcessLauncherThreadToGoIdleObserver() { 2251 } 2252 2253 void WaitForProcessLauncherThreadToGoIdleObserver:: 2254 RunOnProcessLauncherThread() { 2255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); 2256 BrowserThread::PostTask( 2257 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 2258 base::Bind( 2259 &WaitForProcessLauncherThreadToGoIdleObserver:: 2260 RunOnProcessLauncherThread2, 2261 this)); 2262 } 2263 2264 void WaitForProcessLauncherThreadToGoIdleObserver:: 2265 RunOnProcessLauncherThread2() { 2266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); 2267 BrowserThread::PostTask( 2268 BrowserThread::UI, FROM_HERE, 2269 base::Bind(&WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread, 2270 this)); 2271 } 2272 2273 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() { 2274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2275 if (automation_.get()) 2276 automation_->Send(reply_message_.release()); 2277 Release(); 2278 } 2279 2280 DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver( 2281 AutomationProvider* automation, 2282 IPC::Message* reply_message) 2283 : automation_(automation->AsWeakPtr()), 2284 reply_message_(reply_message) { 2285 registrar_.Add( 2286 this, 2287 content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK, 2288 content::NotificationService::AllSources()); 2289 registrar_.Add( 2290 this, 2291 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 2292 content::NotificationService::AllSources()); 2293 } 2294 2295 DragTargetDropAckNotificationObserver:: 2296 ~DragTargetDropAckNotificationObserver() {} 2297 2298 void DragTargetDropAckNotificationObserver::Observe( 2299 int type, 2300 const content::NotificationSource& source, 2301 const content::NotificationDetails& details) { 2302 if (automation_.get()) { 2303 AutomationJSONReply(automation_.get(), reply_message_.release()) 2304 .SendSuccess(NULL); 2305 } 2306 delete this; 2307 } 2308 2309 ProcessInfoObserver::ProcessInfoObserver( 2310 AutomationProvider* automation, 2311 IPC::Message* reply_message) 2312 : automation_(automation->AsWeakPtr()), 2313 reply_message_(reply_message) {} 2314 2315 ProcessInfoObserver::~ProcessInfoObserver() {} 2316 2317 void ProcessInfoObserver::OnDetailsAvailable() { 2318 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 2319 ListValue* browser_proc_list = new ListValue(); 2320 const std::vector<ProcessData>& all_processes = processes(); 2321 for (size_t index = 0; index < all_processes.size(); ++index) { 2322 DictionaryValue* browser_data = new DictionaryValue(); 2323 browser_data->SetString("name", all_processes[index].name); 2324 browser_data->SetString("process_name", all_processes[index].process_name); 2325 2326 ListValue* proc_list = new ListValue(); 2327 for (ProcessMemoryInformationList::const_iterator iterator = 2328 all_processes[index].processes.begin(); 2329 iterator != all_processes[index].processes.end(); ++iterator) { 2330 DictionaryValue* proc_data = new DictionaryValue(); 2331 2332 proc_data->SetInteger("pid", iterator->pid); 2333 2334 // Working set (resident) memory usage, in KBytes. 2335 DictionaryValue* working_set = new DictionaryValue(); 2336 working_set->SetInteger("priv", iterator->working_set.priv); 2337 working_set->SetInteger("shareable", iterator->working_set.shareable); 2338 working_set->SetInteger("shared", iterator->working_set.shared); 2339 proc_data->Set("working_set_mem", working_set); 2340 2341 // Committed (resident + paged) memory usage, in KBytes. 2342 DictionaryValue* committed = new DictionaryValue(); 2343 committed->SetInteger("priv", iterator->committed.priv); 2344 committed->SetInteger("mapped", iterator->committed.mapped); 2345 committed->SetInteger("image", iterator->committed.image); 2346 proc_data->Set("committed_mem", committed); 2347 2348 proc_data->SetString("version", iterator->version); 2349 proc_data->SetString("product_name", iterator->product_name); 2350 proc_data->SetInteger("num_processes", iterator->num_processes); 2351 proc_data->SetBoolean("is_diagnostics", iterator->is_diagnostics); 2352 2353 // Process type, if this is a child process of Chrome (e.g., 'plugin'). 2354 std::string process_type = "Unknown"; 2355 // The following condition avoids a DCHECK in debug builds when the 2356 // process type passed to |GetTypeNameInEnglish| is unknown. 2357 if (iterator->process_type != content::PROCESS_TYPE_UNKNOWN) { 2358 process_type = 2359 content::GetProcessTypeNameInEnglish(iterator->process_type); 2360 } 2361 proc_data->SetString("child_process_type", process_type); 2362 2363 // Renderer type, if this is a renderer process. 2364 std::string renderer_type = "Unknown"; 2365 if (iterator->renderer_type != 2366 ProcessMemoryInformation::RENDERER_UNKNOWN) { 2367 renderer_type = ProcessMemoryInformation::GetRendererTypeNameInEnglish( 2368 iterator->renderer_type); 2369 } 2370 proc_data->SetString("renderer_type", renderer_type); 2371 2372 // Titles associated with this process. 2373 ListValue* titles = new ListValue(); 2374 for (size_t title_index = 0; title_index < iterator->titles.size(); 2375 ++title_index) 2376 titles->Append(Value::CreateStringValue(iterator->titles[title_index])); 2377 proc_data->Set("titles", titles); 2378 2379 proc_list->Append(proc_data); 2380 } 2381 browser_data->Set("processes", proc_list); 2382 2383 browser_proc_list->Append(browser_data); 2384 } 2385 return_value->Set("browsers", browser_proc_list); 2386 2387 if (automation_.get()) { 2388 AutomationJSONReply(automation_.get(), reply_message_.release()) 2389 .SendSuccess(return_value.get()); 2390 } 2391 } 2392 2393 V8HeapStatsObserver::V8HeapStatsObserver( 2394 AutomationProvider* automation, 2395 IPC::Message* reply_message, 2396 base::ProcessId renderer_id) 2397 : automation_(automation->AsWeakPtr()), 2398 reply_message_(reply_message), 2399 renderer_id_(renderer_id) { 2400 registrar_.Add( 2401 this, 2402 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED, 2403 content::NotificationService::AllSources()); 2404 } 2405 2406 V8HeapStatsObserver::~V8HeapStatsObserver() {} 2407 2408 void V8HeapStatsObserver::Observe( 2409 int type, 2410 const content::NotificationSource& source, 2411 const content::NotificationDetails& details) { 2412 DCHECK(type == chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED); 2413 2414 base::ProcessId updated_renderer_id = 2415 *(content::Source<base::ProcessId>(source).ptr()); 2416 // Only return information for the renderer ID we're interested in. 2417 if (renderer_id_ != updated_renderer_id) 2418 return; 2419 2420 ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap_details = 2421 content::Details<ChromeRenderMessageFilter::V8HeapStatsDetails>(details) 2422 .ptr(); 2423 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 2424 return_value->SetInteger("renderer_id", updated_renderer_id); 2425 return_value->SetInteger("v8_memory_allocated", 2426 v8_heap_details->v8_memory_allocated()); 2427 return_value->SetInteger("v8_memory_used", 2428 v8_heap_details->v8_memory_used()); 2429 2430 if (automation_.get()) { 2431 AutomationJSONReply(automation_.get(), reply_message_.release()) 2432 .SendSuccess(return_value.get()); 2433 } 2434 delete this; 2435 } 2436 2437 FPSObserver::FPSObserver( 2438 AutomationProvider* automation, 2439 IPC::Message* reply_message, 2440 base::ProcessId renderer_id, 2441 int routing_id) 2442 : automation_(automation->AsWeakPtr()), 2443 reply_message_(reply_message), 2444 renderer_id_(renderer_id), 2445 routing_id_(routing_id) { 2446 registrar_.Add( 2447 this, 2448 chrome::NOTIFICATION_RENDERER_FPS_COMPUTED, 2449 content::NotificationService::AllSources()); 2450 } 2451 2452 FPSObserver::~FPSObserver() {} 2453 2454 void FPSObserver::Observe( 2455 int type, 2456 const content::NotificationSource& source, 2457 const content::NotificationDetails& details) { 2458 DCHECK(type == chrome::NOTIFICATION_RENDERER_FPS_COMPUTED); 2459 2460 base::ProcessId updated_renderer_id = 2461 *(content::Source<base::ProcessId>(source).ptr()); 2462 // Only return information for the renderer ID we're interested in. 2463 if (renderer_id_ != updated_renderer_id) 2464 return; 2465 2466 ChromeRenderMessageFilter::FPSDetails* fps_details = 2467 content::Details<ChromeRenderMessageFilter::FPSDetails>(details).ptr(); 2468 // Only return information for the routing id of the host render view we're 2469 // interested in. 2470 if (routing_id_ != fps_details->routing_id()) 2471 return; 2472 2473 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 2474 return_value->SetInteger("renderer_id", updated_renderer_id); 2475 return_value->SetInteger("routing_id", fps_details->routing_id()); 2476 return_value->SetDouble("fps", fps_details->fps()); 2477 if (automation_.get()) { 2478 AutomationJSONReply(automation_.get(), reply_message_.release()) 2479 .SendSuccess(return_value.get()); 2480 } 2481 delete this; 2482 } 2483 2484 BrowserOpenedWithNewProfileNotificationObserver:: 2485 BrowserOpenedWithNewProfileNotificationObserver( 2486 AutomationProvider* automation, 2487 IPC::Message* reply_message) 2488 : automation_(automation->AsWeakPtr()), 2489 reply_message_(reply_message), 2490 new_window_id_(extension_misc::kUnknownWindowId) { 2491 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, 2492 content::NotificationService::AllBrowserContextsAndSources()); 2493 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 2494 content::NotificationService::AllBrowserContextsAndSources()); 2495 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 2496 content::NotificationService::AllBrowserContextsAndSources()); 2497 } 2498 2499 BrowserOpenedWithNewProfileNotificationObserver:: 2500 ~BrowserOpenedWithNewProfileNotificationObserver() { 2501 } 2502 2503 void BrowserOpenedWithNewProfileNotificationObserver::Observe( 2504 int type, 2505 const content::NotificationSource& source, 2506 const content::NotificationDetails& details) { 2507 if (!automation_.get()) { 2508 delete this; 2509 return; 2510 } 2511 2512 if (type == chrome::NOTIFICATION_PROFILE_CREATED) { 2513 // As part of multi-profile creation, a new browser window will 2514 // automatically be opened. 2515 Profile* profile = content::Source<Profile>(source).ptr(); 2516 if (!profile) { 2517 AutomationJSONReply(automation_.get(), reply_message_.release()) 2518 .SendError("Profile could not be created."); 2519 return; 2520 } 2521 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) { 2522 // Store the new browser ID and continue waiting for a new tab within it 2523 // to stop loading. 2524 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId( 2525 content::Source<Browser>(source).ptr()); 2526 } else { 2527 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); 2528 // Only send the result if the loaded tab is in the new window. 2529 NavigationController* controller = 2530 content::Source<NavigationController>(source).ptr(); 2531 SessionTabHelper* session_tab_helper = 2532 SessionTabHelper::FromWebContents(controller->GetWebContents()); 2533 int window_id = session_tab_helper ? session_tab_helper->window_id().id() 2534 : -1; 2535 if (window_id == new_window_id_) { 2536 if (automation_.get()) { 2537 AutomationJSONReply(automation_.get(), reply_message_.release()) 2538 .SendSuccess(NULL); 2539 } 2540 delete this; 2541 } 2542 } 2543 } 2544 2545 ExtensionPopupObserver::ExtensionPopupObserver( 2546 AutomationProvider* automation, 2547 IPC::Message* reply_message, 2548 const std::string& extension_id) 2549 : automation_(automation->AsWeakPtr()), 2550 reply_message_(reply_message), 2551 extension_id_(extension_id) { 2552 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, 2553 content::NotificationService::AllSources()); 2554 } 2555 2556 ExtensionPopupObserver::~ExtensionPopupObserver() { 2557 } 2558 2559 void ExtensionPopupObserver::Observe( 2560 int type, 2561 const content::NotificationSource& source, 2562 const content::NotificationDetails& details) { 2563 if (!automation_.get()) { 2564 delete this; 2565 return; 2566 } 2567 2568 extensions::ExtensionHost* host = 2569 content::Details<extensions::ExtensionHost>(details).ptr(); 2570 if (host->extension_id() == extension_id_ && 2571 host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) { 2572 AutomationJSONReply(automation_.get(), reply_message_.release()) 2573 .SendSuccess(NULL); 2574 delete this; 2575 } 2576 } 2577 2578 #if defined(OS_LINUX) 2579 WindowMaximizedObserver::WindowMaximizedObserver( 2580 AutomationProvider* automation, 2581 IPC::Message* reply_message) 2582 : automation_(automation->AsWeakPtr()), 2583 reply_message_(reply_message) { 2584 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, 2585 content::NotificationService::AllSources()); 2586 } 2587 2588 WindowMaximizedObserver::~WindowMaximizedObserver() {} 2589 2590 void WindowMaximizedObserver::Observe( 2591 int type, 2592 const content::NotificationSource& source, 2593 const content::NotificationDetails& details) { 2594 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, type); 2595 2596 if (automation_.get()) { 2597 AutomationJSONReply(automation_.get(), reply_message_.release()) 2598 .SendSuccess(NULL); 2599 } 2600 delete this; 2601 } 2602 #endif // defined(OS_LINUX) 2603 2604 BrowserOpenedWithExistingProfileNotificationObserver:: 2605 BrowserOpenedWithExistingProfileNotificationObserver( 2606 AutomationProvider* automation, 2607 IPC::Message* reply_message, 2608 int num_loads) 2609 : automation_(automation->AsWeakPtr()), 2610 reply_message_(reply_message), 2611 new_window_id_(extension_misc::kUnknownWindowId), 2612 num_loads_(num_loads) { 2613 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 2614 content::NotificationService::AllBrowserContextsAndSources()); 2615 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 2616 content::NotificationService::AllBrowserContextsAndSources()); 2617 } 2618 2619 BrowserOpenedWithExistingProfileNotificationObserver:: 2620 ~BrowserOpenedWithExistingProfileNotificationObserver() { 2621 } 2622 2623 void BrowserOpenedWithExistingProfileNotificationObserver::Observe( 2624 int type, 2625 const content::NotificationSource& source, 2626 const content::NotificationDetails& details) { 2627 if (!automation_.get()) { 2628 delete this; 2629 return; 2630 } 2631 2632 if (type == chrome::NOTIFICATION_BROWSER_OPENED) { 2633 // Store the new browser ID and continue waiting for NOTIFICATION_LOAD_STOP. 2634 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId( 2635 content::Source<Browser>(source).ptr()); 2636 } else if (type == content::NOTIFICATION_LOAD_STOP) { 2637 // Only consider if the loaded tab is in the new window. 2638 NavigationController* controller = 2639 content::Source<NavigationController>(source).ptr(); 2640 SessionTabHelper* session_tab_helper = 2641 SessionTabHelper::FromWebContents(controller->GetWebContents()); 2642 int window_id = session_tab_helper ? session_tab_helper->window_id().id() 2643 : -1; 2644 if (window_id == new_window_id_ && --num_loads_ == 0) { 2645 if (automation_.get()) { 2646 AutomationJSONReply(automation_.get(), reply_message_.release()) 2647 .SendSuccess(NULL); 2648 } 2649 delete this; 2650 } 2651 } else { 2652 NOTREACHED(); 2653 } 2654 } 2655