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.
5 #include "chrome/browser/automation/automation_provider_observers.h"
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_tab_util.h"
37 #include "chrome/browser/history/history_types.h"
38 #include "chrome/browser/history/top_sites.h"
39 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
40 #include "chrome/browser/infobars/infobar_service.h"
41 #include "chrome/browser/metrics/metric_event_duration_details.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
44 #include "chrome/browser/search_engines/template_url_service.h"
45 #include "chrome/browser/search_engines/template_url_service_factory.h"
46 #include "chrome/browser/sessions/session_tab_helper.h"
47 #include "chrome/browser/sessions/tab_restore_service.h"
48 #include "chrome/browser/sessions/tab_restore_service_factory.h"
49 #include "chrome/browser/ui/browser.h"
50 #include "chrome/browser/ui/browser_iterator.h"
51 #include "chrome/browser/ui/browser_list.h"
52 #include "chrome/browser/ui/browser_window.h"
53 #include "chrome/browser/ui/find_bar/find_notification_details.h"
54 #include "chrome/browser/ui/host_desktop.h"
55 #include "chrome/browser/ui/login/login_prompt.h"
56 #include "chrome/browser/ui/tabs/tab_strip_model.h"
57 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
58 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
59 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
60 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
61 #include "chrome/common/automation_constants.h"
62 #include "chrome/common/automation_messages.h"
63 #include "chrome/common/content_settings_types.h"
64 #include "chrome/common/extensions/extension_constants.h"
65 #include "components/password_manager/core/browser/password_store_change.h"
66 #include "content/public/browser/dom_operation_notification_details.h"
67 #include "content/public/browser/navigation_controller.h"
68 #include "content/public/browser/notification_service.h"
69 #include "content/public/browser/render_process_host.h"
70 #include "content/public/browser/render_view_host.h"
71 #include "content/public/browser/web_contents.h"
72 #include "content/public/common/process_type.h"
73 #include "extensions/browser/extension_registry.h"
74 #include "extensions/browser/extension_system.h"
75 #include "extensions/browser/process_manager.h"
76 #include "extensions/browser/runtime_data.h"
77 #include "extensions/common/extension.h"
78 #include "extensions/common/extension_set.h"
79 #include "extensions/common/manifest.h"
80 #include "extensions/common/view_type.h"
81 #include "ui/gfx/codec/png_codec.h"
82 #include "ui/gfx/rect.h"
85 #if !defined(OS_CHROMEOS)
86 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
89 using content::BrowserThread;
90 using content::DomOperationNotificationDetails;
91 using content::DownloadItem;
92 using content::DownloadManager;
93 using content::NavigationController;
94 using content::RenderViewHost;
95 using content::WebContents;
97 // Holds onto start and stop timestamps for a particular tab
98 class InitialLoadObserver::TabTime {
100 explicit TabTime(base::TimeTicks started)
101 : load_start_time_(started) {
103 void set_stop_time(base::TimeTicks stopped) {
104 load_stop_time_ = stopped;
106 base::TimeTicks stop_time() const {
107 return load_stop_time_;
109 base::TimeTicks start_time() const {
110 return load_start_time_;
113 base::TimeTicks load_start_time_;
114 base::TimeTicks load_stop_time_;
117 InitialLoadObserver::InitialLoadObserver(size_t tab_count,
118 AutomationProvider* automation)
119 : automation_(automation->AsWeakPtr()),
120 crashed_tab_count_(0),
121 outstanding_tab_count_(tab_count),
122 init_time_(base::TimeTicks::Now()) {
123 if (outstanding_tab_count_ > 0) {
124 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
125 content::NotificationService::AllSources());
126 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
127 content::NotificationService::AllSources());
128 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
129 content::NotificationService::AllSources());
133 InitialLoadObserver::~InitialLoadObserver() {
136 void InitialLoadObserver::Observe(int type,
137 const content::NotificationSource& source,
138 const content::NotificationDetails& details) {
139 if (type == content::NOTIFICATION_LOAD_START) {
140 if (outstanding_tab_count_ > loading_tabs_.size())
141 loading_tabs_.insert(TabTimeMap::value_type(
143 TabTime(base::TimeTicks::Now())));
144 } else if (type == content::NOTIFICATION_LOAD_STOP) {
145 if (outstanding_tab_count_ > finished_tabs_.size()) {
146 TabTimeMap::iterator iter = loading_tabs_.find(source.map_key());
147 if (iter != loading_tabs_.end()) {
148 finished_tabs_.insert(source.map_key());
149 iter->second.set_stop_time(base::TimeTicks::Now());
152 } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
153 base::TerminationStatus status =
154 content::Details<content::RenderProcessHost::RendererClosedDetails>(
157 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
160 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
161 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
162 case base::TERMINATION_STATUS_PROCESS_CRASHED:
163 crashed_tab_count_++;
166 case base::TERMINATION_STATUS_STILL_RUNNING:
167 LOG(ERROR) << "Got RENDERER_PROCESS_CLOSED notification, "
168 << "but the process is still running. We may miss further "
169 << "crash notification, resulting in hangs.";
173 LOG(ERROR) << "Unhandled termination status " << status;
181 if (finished_tabs_.size() + crashed_tab_count_ >= outstanding_tab_count_)
185 base::DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
186 base::ListValue* items = new base::ListValue;
187 for (TabTimeMap::const_iterator it = loading_tabs_.begin();
188 it != loading_tabs_.end();
190 base::DictionaryValue* item = new base::DictionaryValue;
191 base::TimeDelta delta_start = it->second.start_time() - init_time_;
193 item->SetDouble("load_start_ms", delta_start.InMillisecondsF());
194 if (it->second.stop_time().is_null()) {
195 item->Set("load_stop_ms", base::Value::CreateNullValue());
197 base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
198 item->SetDouble("load_stop_ms", delta_stop.InMillisecondsF());
202 base::DictionaryValue* return_value = new base::DictionaryValue;
203 return_value->Set("tabs", items);
207 void InitialLoadObserver::ConditionMet() {
208 registrar_.RemoveAll();
209 if (automation_.get())
210 automation_->OnInitialTabLoadsComplete();
213 NavigationControllerRestoredObserver::NavigationControllerRestoredObserver(
214 AutomationProvider* automation,
215 NavigationController* controller,
216 IPC::Message* reply_message)
217 : automation_(automation->AsWeakPtr()),
218 controller_(controller),
219 reply_message_(reply_message) {
220 if (FinishedRestoring()) {
223 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
224 content::NotificationService::AllSources());
228 NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() {
231 void NavigationControllerRestoredObserver::Observe(
232 int type, const content::NotificationSource& source,
233 const content::NotificationDetails& details) {
234 if (FinishedRestoring()) {
235 registrar_.RemoveAll();
240 bool NavigationControllerRestoredObserver::FinishedRestoring() {
241 return (!controller_->NeedsReload() && !controller_->GetPendingEntry() &&
242 !controller_->GetWebContents()->IsLoading());
245 void NavigationControllerRestoredObserver::SendDone() {
246 if (automation_.get()) {
247 AutomationJSONReply(automation_.get(), reply_message_.release())
253 NavigationNotificationObserver::NavigationNotificationObserver(
254 NavigationController* controller,
255 AutomationProvider* automation,
256 IPC::Message* reply_message,
257 int number_of_navigations,
258 bool include_current_navigation,
259 bool use_json_interface)
260 : automation_(automation->AsWeakPtr()),
261 reply_message_(reply_message),
262 controller_(controller),
263 navigations_remaining_(number_of_navigations),
264 navigation_started_(false),
265 use_json_interface_(use_json_interface) {
266 if (number_of_navigations == 0) {
267 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
270 DCHECK_LT(0, navigations_remaining_);
271 content::Source<NavigationController> source(controller_);
272 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source);
273 registrar_.Add(this, content::NOTIFICATION_LOAD_START, source);
274 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
275 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
276 registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source);
277 registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source);
278 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
279 content::NotificationService::AllSources());
281 if (include_current_navigation && controller->GetWebContents()->IsLoading())
282 navigation_started_ = true;
285 NavigationNotificationObserver::~NavigationNotificationObserver() {
288 void NavigationNotificationObserver::Observe(
289 int type, const content::NotificationSource& source,
290 const content::NotificationDetails& details) {
291 if (!automation_.get()) {
296 // We listen for 2 events to determine when the navigation started because:
297 // - when this is used by the WaitForNavigation method, we might be invoked
298 // afer the load has started (but not after the entry was committed, as
299 // WaitForNavigation compares times of the last navigation).
300 // - when this is used with a page requiring authentication, we will not get
301 // a chrome::NAV_ENTRY_COMMITTED until after we authenticate, so
302 // we need the chrome::LOAD_START.
303 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED ||
304 type == content::NOTIFICATION_LOAD_START) {
305 navigation_started_ = true;
306 } else if (type == content::NOTIFICATION_LOAD_STOP) {
307 if (navigation_started_) {
308 navigation_started_ = false;
309 if (--navigations_remaining_ == 0)
310 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
312 } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED ||
313 type == chrome::NOTIFICATION_AUTH_CANCELLED) {
314 // Treat this as if navigation started again, since load start/stop don't
315 // occur while authentication is ongoing.
316 navigation_started_ = true;
317 } else if (type == chrome::NOTIFICATION_AUTH_NEEDED) {
318 // Respond that authentication is needed.
319 navigation_started_ = false;
320 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
321 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
322 ConditionMet(AUTOMATION_MSG_NAVIGATION_BLOCKED_BY_MODAL_DIALOG);
328 void NavigationNotificationObserver::ConditionMet(
329 AutomationMsg_NavigationResponseValues navigation_result) {
330 if (automation_.get()) {
331 if (use_json_interface_) {
332 if (navigation_result == AUTOMATION_MSG_NAVIGATION_SUCCESS) {
333 base::DictionaryValue dict;
334 dict.SetInteger("result", navigation_result);
335 AutomationJSONReply(automation_.get(), reply_message_.release())
338 AutomationJSONReply(automation_.get(), reply_message_.release())
339 .SendError(base::StringPrintf(
340 "Navigation failed with error code=%d.", navigation_result));
343 IPC::ParamTraits<int>::Write(
344 reply_message_.get(), navigation_result);
345 automation_->Send(reply_message_.release());
352 TabStripNotificationObserver::TabStripNotificationObserver(
353 int notification, AutomationProvider* automation)
354 : automation_(automation->AsWeakPtr()),
355 notification_(notification) {
356 registrar_.Add(this, notification_,
357 content::NotificationService::AllSources());
360 TabStripNotificationObserver::~TabStripNotificationObserver() {
363 void TabStripNotificationObserver::Observe(
365 const content::NotificationSource& source,
366 const content::NotificationDetails& details) {
367 DCHECK_EQ(notification_, type);
368 if (type == chrome::NOTIFICATION_TAB_PARENTED) {
369 ObserveTab(&content::Source<content::WebContents>(source)->GetController());
370 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
371 ObserveTab(&content::Source<content::WebContents>(source)->GetController());
373 ObserveTab(content::Source<NavigationController>(source).ptr());
378 TabAppendedNotificationObserver::TabAppendedNotificationObserver(
380 AutomationProvider* automation,
381 IPC::Message* reply_message,
382 bool use_json_interface)
383 : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED,
386 reply_message_(reply_message),
387 use_json_interface_(use_json_interface) {
390 TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {}
392 void TabAppendedNotificationObserver::ObserveTab(
393 NavigationController* controller) {
394 if (!automation_.get() || !reply_message_.get())
397 if (automation_->GetIndexForNavigationController(controller, parent_) ==
398 TabStripModel::kNoTab) {
399 // This tab notification doesn't belong to the parent_.
403 new NavigationNotificationObserver(controller,
405 reply_message_.release(),
408 use_json_interface_);
411 IPC::Message* TabAppendedNotificationObserver::ReleaseReply() {
412 return reply_message_.release();
415 TabClosedNotificationObserver::TabClosedNotificationObserver(
416 AutomationProvider* automation,
417 bool wait_until_closed,
418 IPC::Message* reply_message,
419 bool use_json_interface)
420 : TabStripNotificationObserver((wait_until_closed ?
421 static_cast<int>(content::NOTIFICATION_WEB_CONTENTS_DESTROYED) :
422 static_cast<int>(chrome::NOTIFICATION_TAB_CLOSING)), automation),
423 reply_message_(reply_message),
424 use_json_interface_(use_json_interface),
425 for_browser_command_(false) {
428 TabClosedNotificationObserver::~TabClosedNotificationObserver() {}
430 void TabClosedNotificationObserver::ObserveTab(
431 NavigationController* controller) {
432 if (!automation_.get())
435 if (use_json_interface_) {
436 AutomationJSONReply(automation_.get(), reply_message_.release())
439 if (for_browser_command_) {
440 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
443 AutomationMsg_CloseTab::WriteReplyParams(reply_message_.get(), true);
445 automation_->Send(reply_message_.release());
449 void TabClosedNotificationObserver::set_for_browser_command(
450 bool for_browser_command) {
451 for_browser_command_ = for_browser_command;
454 TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation,
456 IPC::Message* reply_message,
457 int target_tab_count)
458 : automation_(automation->AsWeakPtr()),
459 reply_message_(reply_message),
460 tab_strip_model_(browser->tab_strip_model()),
461 target_tab_count_(target_tab_count) {
462 tab_strip_model_->AddObserver(this);
466 TabCountChangeObserver::~TabCountChangeObserver() {
467 tab_strip_model_->RemoveObserver(this);
470 void TabCountChangeObserver::TabInsertedAt(WebContents* contents,
476 void TabCountChangeObserver::TabDetachedAt(WebContents* contents,
481 void TabCountChangeObserver::TabStripModelDeleted() {
482 if (automation_.get()) {
483 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
484 reply_message_.get(), false);
485 automation_->Send(reply_message_.release());
491 void TabCountChangeObserver::CheckTabCount() {
492 if (tab_strip_model_->count() != target_tab_count_)
495 if (automation_.get()) {
496 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
497 reply_message_.get(), true);
498 automation_->Send(reply_message_.release());
504 bool DidExtensionViewsStopLoading(extensions::ProcessManager* manager) {
505 extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
506 for (extensions::ProcessManager::ViewSet::const_iterator iter =
508 iter != all_views.end(); ++iter) {
509 if ((*iter)->IsLoading())
515 ExtensionUninstallObserver::ExtensionUninstallObserver(
516 AutomationProvider* automation,
517 IPC::Message* reply_message,
518 const std::string& id)
519 : automation_(automation->AsWeakPtr()),
520 reply_message_(reply_message),
522 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
523 content::NotificationService::AllSources());
524 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
525 content::NotificationService::AllSources());
528 ExtensionUninstallObserver::~ExtensionUninstallObserver() {
531 void ExtensionUninstallObserver::Observe(
533 const content::NotificationSource& source,
534 const content::NotificationDetails& details) {
535 if (!automation_.get()) {
541 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
542 if (id_ == content::Details<extensions::Extension>(details).ptr()->id()) {
543 scoped_ptr<base::DictionaryValue> return_value(
544 new base::DictionaryValue);
545 return_value->SetBoolean("success", true);
546 AutomationJSONReply(automation_.get(), reply_message_.release())
547 .SendSuccess(return_value.get());
554 case chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED: {
555 const extensions::Extension* extension =
556 content::Details<extensions::Extension>(details).ptr();
557 if (id_ == extension->id()) {
558 scoped_ptr<base::DictionaryValue> return_value(
559 new base::DictionaryValue);
560 return_value->SetBoolean("success", false);
561 AutomationJSONReply(automation_.get(), reply_message_.release())
562 .SendSuccess(return_value.get());
574 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
575 extensions::ExtensionSystem* extension_system,
576 AutomationProvider* automation,
577 IPC::Message* reply_message)
578 : extension_system_(extension_system),
579 automation_(automation->AsWeakPtr()),
580 reply_message_(reply_message),
585 ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() {
588 void ExtensionReadyNotificationObserver::Init() {
589 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
590 content::NotificationService::AllSources());
591 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
592 content::NotificationService::AllSources());
593 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
594 content::NotificationService::AllSources());
595 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
596 content::NotificationService::AllSources());
597 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
598 content::NotificationService::AllSources());
601 void ExtensionReadyNotificationObserver::Observe(
602 int type, const content::NotificationSource& source,
603 const content::NotificationDetails& details) {
604 if (!automation_.get()) {
610 case content::NOTIFICATION_LOAD_STOP:
611 // Only continue on with this method if our extension has been loaded
612 // and all the extension views have stopped loading.
614 !DidExtensionViewsStopLoading(extension_system_->process_manager()))
617 case chrome::NOTIFICATION_EXTENSION_LOADED: {
618 const extensions::Extension* loaded_extension =
619 content::Details<const extensions::Extension>(details).ptr();
620 // Only track an internal or unpacked extension load.
621 extensions::Manifest::Location location = loaded_extension->location();
622 if (location != extensions::Manifest::INTERNAL &&
623 !extensions::Manifest::IsUnpackedLocation(location))
625 extension_ = loaded_extension;
626 if (!DidExtensionViewsStopLoading(extension_system_->process_manager()))
628 // For some reason, the background extension view is not yet
629 // created at this point so just checking whether all extension views
630 // are loaded is not sufficient. If background page is not ready,
631 // we wait for NOTIFICATION_LOAD_STOP.
632 if (!extension_system_->runtime_data()->IsBackgroundPageReady(extension_))
636 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
637 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
638 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
645 AutomationJSONReply reply(automation_.get(), reply_message_.release());
647 base::DictionaryValue dict;
648 dict.SetString("id", extension_->id());
649 reply.SendSuccess(&dict);
651 reply.SendError("Extension could not be installed");
656 ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
657 : did_receive_unload_notification_(false) {
658 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
659 content::NotificationService::AllSources());
662 ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
665 void ExtensionUnloadNotificationObserver::Observe(
666 int type, const content::NotificationSource& source,
667 const content::NotificationDetails& details) {
668 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
669 did_receive_unload_notification_ = true;
675 ExtensionsUpdatedObserver::ExtensionsUpdatedObserver(
676 extensions::ProcessManager* manager, AutomationProvider* automation,
677 IPC::Message* reply_message)
678 : manager_(manager), automation_(automation->AsWeakPtr()),
679 reply_message_(reply_message), updater_finished_(false) {
680 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
681 content::NotificationService::AllSources());
684 ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() {
687 void ExtensionsUpdatedObserver::Observe(
688 int type, const content::NotificationSource& source,
689 const content::NotificationDetails& details) {
690 if (!automation_.get()) {
695 DCHECK(type == content::NOTIFICATION_LOAD_STOP);
699 void ExtensionsUpdatedObserver::UpdateCheckFinished() {
700 if (!automation_.get()) {
705 // Extension updater has completed updating all extensions.
706 updater_finished_ = true;
710 void ExtensionsUpdatedObserver::MaybeReply() {
711 // Send the reply if (1) the extension updater has finished updating all
712 // extensions; and (2) all extension views have stopped loading.
713 if (updater_finished_ && DidExtensionViewsStopLoading(manager_)) {
714 AutomationJSONReply reply(automation_.get(), reply_message_.release());
715 reply.SendSuccess(NULL);
720 BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver(
721 AutomationProvider* automation,
722 IPC::Message* reply_message,
723 bool use_json_interface)
724 : automation_(automation->AsWeakPtr()),
725 reply_message_(reply_message),
726 new_window_id_(extension_misc::kUnknownWindowId),
727 use_json_interface_(use_json_interface),
728 for_browser_command_(false) {
729 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
730 content::NotificationService::AllBrowserContextsAndSources());
731 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
732 content::NotificationService::AllBrowserContextsAndSources());
735 BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() {
738 void BrowserOpenedNotificationObserver::Observe(
740 const content::NotificationSource& source,
741 const content::NotificationDetails& details) {
742 if (!automation_.get()) {
747 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
748 // Store the new browser ID and continue waiting for a new tab within it
750 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
751 content::Source<Browser>(source).ptr());
753 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
754 // Only send the result if the loaded tab is in the new window.
755 NavigationController* controller =
756 content::Source<NavigationController>(source).ptr();
757 SessionTabHelper* session_tab_helper =
758 SessionTabHelper::FromWebContents(controller->GetWebContents());
759 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
761 if (window_id == new_window_id_) {
762 if (use_json_interface_) {
763 AutomationJSONReply(automation_.get(), reply_message_.release())
766 if (for_browser_command_) {
767 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
768 reply_message_.get(), true);
770 automation_->Send(reply_message_.release());
778 void BrowserOpenedNotificationObserver::set_for_browser_command(
779 bool for_browser_command) {
780 for_browser_command_ = for_browser_command;
783 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
785 AutomationProvider* automation,
786 IPC::Message* reply_message,
787 bool use_json_interface)
788 : automation_(automation->AsWeakPtr()),
789 reply_message_(reply_message),
790 use_json_interface_(use_json_interface),
791 for_browser_command_(false) {
792 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
793 content::Source<Browser>(browser));
796 BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {}
798 void BrowserClosedNotificationObserver::Observe(
799 int type, const content::NotificationSource& source,
800 const content::NotificationDetails& details) {
801 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSED, type);
803 if (!automation_.get()) {
808 // The automation layer doesn't support non-native desktops.
809 int browser_count = static_cast<int>(BrowserList::GetInstance(
810 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
811 // We get the notification before the browser is removed from the BrowserList.
812 bool app_closing = browser_count == 1;
814 if (use_json_interface_) {
815 AutomationJSONReply(automation_.get(), reply_message_.release())
818 if (for_browser_command_) {
819 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
822 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true,
825 automation_->Send(reply_message_.release());
830 void BrowserClosedNotificationObserver::set_for_browser_command(
831 bool for_browser_command) {
832 for_browser_command_ = for_browser_command;
835 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
837 AutomationProvider* automation,
838 IPC::Message* reply_message)
839 : target_count_(target_count),
840 automation_(automation->AsWeakPtr()),
841 reply_message_(reply_message) {
842 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
843 content::NotificationService::AllBrowserContextsAndSources());
844 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
845 content::NotificationService::AllBrowserContextsAndSources());
848 BrowserCountChangeNotificationObserver::
849 ~BrowserCountChangeNotificationObserver() {}
851 void BrowserCountChangeNotificationObserver::Observe(
853 const content::NotificationSource& source,
854 const content::NotificationDetails& details) {
855 DCHECK(type == chrome::NOTIFICATION_BROWSER_OPENED ||
856 type == chrome::NOTIFICATION_BROWSER_CLOSED);
858 // The automation layer doesn't support non-native desktops.
859 int current_count = static_cast<int>(BrowserList::GetInstance(
860 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
861 if (type == chrome::NOTIFICATION_BROWSER_CLOSED) {
862 // At the time of the notification the browser being closed is not removed
863 // from the list. The real count is one less than the reported count.
864 DCHECK_LT(0, current_count);
868 if (!automation_.get()) {
873 if (current_count == target_count_) {
874 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
875 reply_message_.get(), true);
876 automation_->Send(reply_message_.release());
883 // Define mapping from command to notification
884 struct CommandNotification {
886 int notification_type;
889 const struct CommandNotification command_notifications[] = {
890 {IDC_DUPLICATE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
892 // Returns as soon as the restored tab is created. To further wait until
893 // the content page is loaded, use WaitForTabToBeRestored.
894 {IDC_RESTORE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
896 // For the following commands, we need to wait for a new tab to be created,
897 // load to finish, and title to change.
898 {IDC_MANAGE_EXTENSIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
899 {IDC_OPTIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
900 {IDC_PRINT, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
901 {IDC_SHOW_DOWNLOADS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
902 {IDC_SHOW_HISTORY, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
907 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
911 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
912 AutomationProvider* automation,
915 IPC::Message* reply_message,
916 bool use_json_interface) {
920 new NewTabObserver(automation, reply_message, use_json_interface);
924 case IDC_NEW_INCOGNITO_WINDOW: {
925 BrowserOpenedNotificationObserver* observer =
926 new BrowserOpenedNotificationObserver(automation, reply_message,
928 observer->set_for_browser_command(true);
931 case IDC_CLOSE_WINDOW: {
932 BrowserClosedNotificationObserver* observer =
933 new BrowserClosedNotificationObserver(browser, automation,
936 observer->set_for_browser_command(true);
939 case IDC_CLOSE_TAB: {
940 TabClosedNotificationObserver* observer =
941 new TabClosedNotificationObserver(automation, true, reply_message,
943 observer->set_for_browser_command(true);
949 new NavigationNotificationObserver(
950 &browser->tab_strip_model()->GetActiveWebContents()->GetController(),
951 automation, reply_message, 1, false, use_json_interface);
955 ExecuteBrowserCommandObserver* observer =
956 new ExecuteBrowserCommandObserver(automation, reply_message,
958 if (!observer->Register(command)) {
959 observer->ReleaseReply();
969 void ExecuteBrowserCommandObserver::Observe(
970 int type, const content::NotificationSource& source,
971 const content::NotificationDetails& details) {
972 if (type == notification_type_) {
973 if (automation_.get()) {
974 if (use_json_interface_) {
975 AutomationJSONReply(automation_.get(), reply_message_.release())
978 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
979 reply_message_.get(), true);
980 automation_->Send(reply_message_.release());
989 ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
990 AutomationProvider* automation,
991 IPC::Message* reply_message,
992 bool use_json_interface)
993 : automation_(automation->AsWeakPtr()),
994 notification_type_(content::NOTIFICATION_ALL),
995 reply_message_(reply_message),
996 use_json_interface_(use_json_interface) {
999 bool ExecuteBrowserCommandObserver::Register(int command) {
1000 if (!Getint(command, ¬ification_type_))
1002 registrar_.Add(this, notification_type_,
1003 content::NotificationService::AllSources());
1007 bool ExecuteBrowserCommandObserver::Getint(
1008 int command, int* type) {
1012 for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
1013 if (command_notifications[i].command == command) {
1014 *type = command_notifications[i].notification_type;
1022 IPC::Message* ExecuteBrowserCommandObserver::ReleaseReply() {
1023 return reply_message_.release();
1026 FindInPageNotificationObserver::FindInPageNotificationObserver(
1027 AutomationProvider* automation, WebContents* parent_tab,
1028 bool reply_with_json, IPC::Message* reply_message)
1029 : automation_(automation->AsWeakPtr()),
1030 active_match_ordinal_(-1),
1031 reply_with_json_(reply_with_json),
1032 reply_message_(reply_message) {
1033 registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
1034 content::Source<WebContents>(parent_tab));
1037 FindInPageNotificationObserver::~FindInPageNotificationObserver() {
1040 void FindInPageNotificationObserver::Observe(
1041 int type, const content::NotificationSource& source,
1042 const content::NotificationDetails& details) {
1043 content::Details<FindNotificationDetails> find_details(details);
1044 if (!(find_details->final_update() && reply_message_ != NULL)) {
1045 DVLOG(1) << "Ignoring, since we only care about the final message";
1049 if (!automation_.get()) {
1054 // We get multiple responses and one of those will contain the ordinal.
1055 // This message comes to us before the final update is sent.
1056 if (find_details->request_id() == kFindInPageRequestId) {
1057 if (reply_with_json_) {
1058 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1059 return_value->SetInteger("match_count",
1060 find_details->number_of_matches());
1061 gfx::Rect rect = find_details->selection_rect();
1062 // If MatchCount is > 0, then rect should not be Empty.
1063 // We dont guard it here because we want to let the test
1064 // code catch this invalid case if needed.
1065 if (!rect.IsEmpty()) {
1066 return_value->SetInteger("match_left", rect.x());
1067 return_value->SetInteger("match_top", rect.y());
1068 return_value->SetInteger("match_right", rect.right());
1069 return_value->SetInteger("match_bottom", rect.bottom());
1071 AutomationJSONReply(automation_.get(), reply_message_.release())
1072 .SendSuccess(return_value.get());
1075 if (find_details->active_match_ordinal() > -1) {
1076 active_match_ordinal_ = find_details->active_match_ordinal();
1077 AutomationMsg_Find::WriteReplyParams(reply_message_.get(),
1078 active_match_ordinal_, find_details->number_of_matches());
1079 automation_->Send(reply_message_.release());
1086 const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
1088 DomOperationObserver::DomOperationObserver(int automation_id)
1089 : automation_id_(automation_id) {
1090 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
1091 content::NotificationService::AllSources());
1092 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
1093 content::NotificationService::AllSources());
1094 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1095 content::NotificationService::AllSources());
1098 DomOperationObserver::~DomOperationObserver() {}
1100 void DomOperationObserver::Observe(
1101 int type, const content::NotificationSource& source,
1102 const content::NotificationDetails& details) {
1103 if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) {
1104 content::Details<DomOperationNotificationDetails> dom_op_details(details);
1105 if (dom_op_details->automation_id == automation_id_)
1106 OnDomOperationCompleted(dom_op_details->json);
1107 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
1108 OnJavascriptBlocked();
1110 DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type);
1111 WebContents* web_contents = content::Source<WebContents>(source).ptr();
1113 TabSpecificContentSettings* tab_content_settings =
1114 TabSpecificContentSettings::FromWebContents(web_contents);
1115 if (tab_content_settings &&
1116 tab_content_settings->IsContentBlocked(
1117 CONTENT_SETTINGS_TYPE_JAVASCRIPT))
1118 OnJavascriptBlocked();
1123 DomOperationMessageSender::DomOperationMessageSender(
1124 AutomationProvider* automation,
1125 IPC::Message* reply_message,
1126 bool use_json_interface)
1127 : DomOperationObserver(0),
1128 automation_(automation->AsWeakPtr()),
1129 reply_message_(reply_message),
1130 use_json_interface_(use_json_interface) {
1133 DomOperationMessageSender::~DomOperationMessageSender() {}
1135 void DomOperationMessageSender::OnDomOperationCompleted(
1136 const std::string& json) {
1137 if (automation_.get()) {
1138 if (use_json_interface_) {
1139 base::DictionaryValue dict;
1140 dict.SetString("result", json);
1141 AutomationJSONReply(automation_.get(), reply_message_.release())
1142 .SendSuccess(&dict);
1144 AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json);
1145 automation_->Send(reply_message_.release());
1151 void DomOperationMessageSender::OnJavascriptBlocked() {
1152 if (automation_.get() && use_json_interface_) {
1153 AutomationJSONReply(automation_.get(), reply_message_.release())
1154 .SendError("Javascript execution was blocked");
1159 MetricEventDurationObserver::MetricEventDurationObserver() {
1160 registrar_.Add(this, chrome::NOTIFICATION_METRIC_EVENT_DURATION,
1161 content::NotificationService::AllSources());
1164 MetricEventDurationObserver::~MetricEventDurationObserver() {}
1166 int MetricEventDurationObserver::GetEventDurationMs(
1167 const std::string& event_name) {
1168 EventDurationMap::const_iterator it = durations_.find(event_name);
1169 if (it == durations_.end())
1174 void MetricEventDurationObserver::Observe(
1176 const content::NotificationSource& source,
1177 const content::NotificationDetails& details) {
1178 if (type != chrome::NOTIFICATION_METRIC_EVENT_DURATION) {
1182 MetricEventDurationDetails* metric_event_duration =
1183 content::Details<MetricEventDurationDetails>(details).ptr();
1184 durations_[metric_event_duration->event_name] =
1185 metric_event_duration->duration_ms;
1188 InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
1189 IPC::Message* reply_message,
1190 WebContents* web_contents,
1191 size_t target_count)
1192 : automation_(automation->AsWeakPtr()),
1193 reply_message_(reply_message),
1194 web_contents_(web_contents),
1195 target_count_(target_count) {
1196 content::Source<InfoBarService> source(
1197 InfoBarService::FromWebContents(web_contents));
1198 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
1200 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
1205 InfoBarCountObserver::~InfoBarCountObserver() {}
1207 void InfoBarCountObserver::Observe(
1209 const content::NotificationSource& source,
1210 const content::NotificationDetails& details) {
1211 DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED ||
1212 type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
1216 void InfoBarCountObserver::CheckCount() {
1217 if (InfoBarService::FromWebContents(web_contents_)->infobar_count() !=
1221 if (automation_.get()) {
1222 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(),
1224 automation_->Send(reply_message_.release());
1229 AutomationProviderBookmarkModelObserver::
1230 AutomationProviderBookmarkModelObserver(
1231 AutomationProvider* provider,
1232 IPC::Message* reply_message,
1233 BookmarkModel* model,
1234 bool use_json_interface)
1235 : automation_provider_(provider->AsWeakPtr()),
1236 reply_message_(reply_message),
1238 use_json_interface_(use_json_interface) {
1239 model_->AddObserver(this);
1242 AutomationProviderBookmarkModelObserver::
1243 ~AutomationProviderBookmarkModelObserver() {
1244 model_->RemoveObserver(this);
1247 void AutomationProviderBookmarkModelObserver::BookmarkModelLoaded(
1248 BookmarkModel* model,
1249 bool ids_reassigned) {
1250 ReplyAndDelete(true);
1253 void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted(
1254 BookmarkModel* model) {
1255 ReplyAndDelete(false);
1258 IPC::Message* AutomationProviderBookmarkModelObserver::ReleaseReply() {
1259 return reply_message_.release();
1262 void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
1263 if (automation_provider_.get()) {
1264 if (use_json_interface_) {
1265 AutomationJSONReply(automation_provider_.get(), reply_message_.release())
1268 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1269 reply_message_.get(), success);
1270 automation_provider_->Send(reply_message_.release());
1276 AutomationProviderDownloadUpdatedObserver::
1277 AutomationProviderDownloadUpdatedObserver(
1278 AutomationProvider* provider,
1279 IPC::Message* reply_message,
1282 : provider_(provider->AsWeakPtr()),
1283 reply_message_(reply_message),
1284 wait_for_open_(wait_for_open),
1285 incognito_(incognito) {
1288 AutomationProviderDownloadUpdatedObserver::
1289 ~AutomationProviderDownloadUpdatedObserver() {}
1291 void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
1292 DownloadItem* download) {
1293 // If this observer is watching for open, only send the reply if the download
1294 // has been auto-opened.
1295 if (wait_for_open_ && !download->GetAutoOpened())
1298 download->RemoveObserver(this);
1300 if (provider_.get()) {
1301 scoped_ptr<base::DictionaryValue> return_value(
1302 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1303 AutomationJSONReply(provider_.get(), reply_message_.release())
1304 .SendSuccess(return_value.get());
1309 void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
1310 DownloadItem* download) {
1311 download->RemoveObserver(this);
1313 if (provider_.get()) {
1314 scoped_ptr<base::DictionaryValue> return_value(
1315 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1316 AutomationJSONReply(provider_.get(), reply_message_.release())
1317 .SendSuccess(return_value.get());
1322 AutomationProviderDownloadModelChangedObserver::
1323 AutomationProviderDownloadModelChangedObserver(
1324 AutomationProvider* provider,
1325 IPC::Message* reply_message,
1326 DownloadManager* download_manager)
1327 : provider_(provider->AsWeakPtr()),
1328 reply_message_(reply_message),
1329 notifier_(download_manager, this) {
1332 AutomationProviderDownloadModelChangedObserver::
1333 ~AutomationProviderDownloadModelChangedObserver() {}
1335 void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
1336 if (provider_.get())
1337 AutomationJSONReply(provider_.get(), reply_message_.release())
1342 void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated(
1343 DownloadManager* manager, DownloadItem* item) {
1347 void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved(
1348 DownloadManager* manager, DownloadItem* item) {
1352 AllDownloadsCompleteObserver::AllDownloadsCompleteObserver(
1353 AutomationProvider* provider,
1354 IPC::Message* reply_message,
1355 DownloadManager* download_manager,
1356 base::ListValue* pre_download_ids)
1357 : provider_(provider->AsWeakPtr()),
1358 reply_message_(reply_message),
1359 download_manager_(download_manager) {
1360 for (base::ListValue::iterator it = pre_download_ids->begin();
1361 it != pre_download_ids->end(); ++it) {
1363 if ((*it)->GetAsInteger(&val)) {
1364 pre_download_ids_.insert(val);
1366 AutomationJSONReply(provider_.get(), reply_message_.release())
1367 .SendError("Cannot convert ID of prior download to integer.");
1372 download_manager_->AddObserver(this);
1373 DownloadManager::DownloadVector all_items;
1374 download_manager->GetAllDownloads(&all_items);
1375 for (DownloadManager::DownloadVector::const_iterator
1376 it = all_items.begin(); it != all_items.end(); ++it) {
1377 OnDownloadCreated(download_manager_, *it);
1382 AllDownloadsCompleteObserver::~AllDownloadsCompleteObserver() {
1383 if (download_manager_) {
1384 download_manager_->RemoveObserver(this);
1385 download_manager_ = NULL;
1387 for (std::set<DownloadItem*>::const_iterator it = pending_downloads_.begin();
1388 it != pending_downloads_.end(); ++it) {
1389 (*it)->RemoveObserver(this);
1391 pending_downloads_.clear();
1394 void AllDownloadsCompleteObserver::ManagerGoingDown(DownloadManager* manager) {
1395 DCHECK_EQ(manager, download_manager_);
1396 download_manager_->RemoveObserver(this);
1397 download_manager_ = NULL;
1400 void AllDownloadsCompleteObserver::OnDownloadCreated(
1401 DownloadManager* manager, DownloadItem* item) {
1402 // This method is also called in the c-tor for previously existing items.
1403 if (pre_download_ids_.find(item->GetId()) == pre_download_ids_.end() &&
1404 item->GetState() == DownloadItem::IN_PROGRESS) {
1405 item->AddObserver(this);
1406 pending_downloads_.insert(item);
1410 void AllDownloadsCompleteObserver::OnDownloadUpdated(DownloadItem* download) {
1411 // If the current download's status has changed to a final state (not state
1412 // "in progress"), remove it from the pending list.
1413 if (download->GetState() != DownloadItem::IN_PROGRESS) {
1414 download->RemoveObserver(this);
1415 pending_downloads_.erase(download);
1420 void AllDownloadsCompleteObserver::ReplyIfNecessary() {
1421 if (!pending_downloads_.empty())
1424 download_manager_->RemoveObserver(this);
1425 if (provider_.get())
1426 AutomationJSONReply(provider_.get(), reply_message_.release())
1431 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver(
1432 AutomationProvider* provider,
1434 IPC::Message* reply_message)
1435 : provider_(provider->AsWeakPtr()),
1437 reply_message_(reply_message) {
1440 AutomationProviderSearchEngineObserver::
1441 ~AutomationProviderSearchEngineObserver() {}
1443 void AutomationProviderSearchEngineObserver::OnTemplateURLServiceChanged() {
1444 if (provider_.get()) {
1445 TemplateURLService* url_service =
1446 TemplateURLServiceFactory::GetForProfile(profile_);
1447 url_service->RemoveObserver(this);
1448 AutomationJSONReply(provider_.get(), reply_message_.release())
1454 AutomationProviderHistoryObserver::AutomationProviderHistoryObserver(
1455 AutomationProvider* provider,
1456 IPC::Message* reply_message)
1457 : provider_(provider->AsWeakPtr()),
1458 reply_message_(reply_message) {
1461 AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {}
1463 void AutomationProviderHistoryObserver::HistoryQueryComplete(
1464 HistoryService::Handle request_handle,
1465 history::QueryResults* results) {
1466 if (!provider_.get()) {
1471 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1473 base::ListValue* history_list = new base::ListValue;
1474 for (size_t i = 0; i < results->size(); ++i) {
1475 base::DictionaryValue* page_value = new base::DictionaryValue;
1476 history::URLResult const &page = (*results)[i];
1477 page_value->SetString("title", page.title());
1478 page_value->SetString("url", page.url().spec());
1479 page_value->SetDouble("time",
1480 static_cast<double>(page.visit_time().ToDoubleT()));
1481 page_value->SetString("snippet", page.snippet().text());
1482 page_value->SetBoolean(
1484 BookmarkModelFactory::GetForProfile(
1485 provider_->profile())->IsBookmarked(page.url()));
1486 history_list->Append(page_value);
1489 return_value->Set("history", history_list);
1490 // Return history info.
1491 AutomationJSONReply reply(provider_.get(), reply_message_.release());
1492 reply.SendSuccess(return_value.get());
1496 AutomationProviderImportSettingsObserver::
1497 AutomationProviderImportSettingsObserver(
1498 AutomationProvider* provider,
1499 IPC::Message* reply_message)
1500 : provider_(provider->AsWeakPtr()),
1501 reply_message_(reply_message) {
1504 AutomationProviderImportSettingsObserver::
1505 ~AutomationProviderImportSettingsObserver() {}
1507 void AutomationProviderImportSettingsObserver::ImportStarted() {
1510 void AutomationProviderImportSettingsObserver::ImportItemStarted(
1511 importer::ImportItem item) {
1514 void AutomationProviderImportSettingsObserver::ImportItemEnded(
1515 importer::ImportItem item) {
1518 void AutomationProviderImportSettingsObserver::ImportEnded() {
1519 if (provider_.get())
1520 AutomationJSONReply(provider_.get(), reply_message_.release())
1525 AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver(
1526 AutomationProvider* provider,
1527 IPC::Message* reply_message)
1528 : provider_(provider->AsWeakPtr()),
1529 reply_message_(reply_message) {
1532 AutomationProviderGetPasswordsObserver::
1533 ~AutomationProviderGetPasswordsObserver() {}
1535 void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults(
1536 const std::vector<autofill::PasswordForm*>& results) {
1537 if (!provider_.get()) {
1542 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1544 base::ListValue* passwords = new base::ListValue;
1545 for (std::vector<autofill::PasswordForm*>::const_iterator it =
1546 results.begin(); it != results.end(); ++it) {
1547 base::DictionaryValue* password_val = new base::DictionaryValue;
1548 autofill::PasswordForm* password_form = *it;
1549 password_val->SetString("username_value", password_form->username_value);
1550 password_val->SetString("password_value", password_form->password_value);
1551 password_val->SetString("signon_realm", password_form->signon_realm);
1552 password_val->SetDouble(
1553 "time", static_cast<double>(password_form->date_created.ToDoubleT()));
1554 password_val->SetString("origin_url", password_form->origin.spec());
1555 password_val->SetString("username_element",
1556 password_form->username_element);
1557 password_val->SetString("password_element",
1558 password_form->password_element);
1559 password_val->SetString("submit_element", password_form->submit_element);
1560 password_val->SetString("action_target", password_form->action.spec());
1561 password_val->SetBoolean("blacklist", password_form->blacklisted_by_user);
1562 passwords->Append(password_val);
1565 return_value->Set("passwords", passwords);
1566 AutomationJSONReply(provider_.get(), reply_message_.release())
1567 .SendSuccess(return_value.get());
1571 OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver(
1572 NavigationController* controller,
1573 AutomationProvider* automation,
1574 IPC::Message* reply_message)
1575 : automation_(automation->AsWeakPtr()),
1576 reply_message_(reply_message),
1577 controller_(controller) {
1578 content::Source<NavigationController> source(controller_);
1579 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1580 // Pages requiring auth don't send LOAD_STOP.
1581 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
1584 OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() {
1587 void OmniboxAcceptNotificationObserver::Observe(
1589 const content::NotificationSource& source,
1590 const content::NotificationDetails& details) {
1591 if (type == content::NOTIFICATION_LOAD_STOP ||
1592 type == chrome::NOTIFICATION_AUTH_NEEDED) {
1593 if (automation_.get()) {
1594 AutomationJSONReply(automation_.get(), reply_message_.release())
1603 SavePackageNotificationObserver::SavePackageNotificationObserver(
1604 content::DownloadManager* download_manager,
1605 AutomationProvider* automation,
1606 IPC::Message* reply_message)
1607 : download_manager_(download_manager),
1608 automation_(automation->AsWeakPtr()),
1609 reply_message_(reply_message) {
1610 download_manager_->AddObserver(this);
1613 SavePackageNotificationObserver::~SavePackageNotificationObserver() {
1614 download_manager_->RemoveObserver(this);
1617 void SavePackageNotificationObserver::OnSavePackageSuccessfullyFinished(
1618 content::DownloadManager* manager, content::DownloadItem* item) {
1619 if (automation_.get()) {
1620 AutomationJSONReply(automation_.get(), reply_message_.release())
1626 void SavePackageNotificationObserver::ManagerGoingDown(
1627 content::DownloadManager* manager) {
1633 // Returns a vector of dictionaries containing information about installed apps,
1634 // as identified from a given list of extensions. The caller takes ownership
1635 // of the created vector.
1636 std::vector<base::DictionaryValue*>* GetAppInfoFromExtensions(
1637 const extensions::ExtensionSet* extensions,
1638 ExtensionService* ext_service) {
1639 std::vector<base::DictionaryValue*>* apps_list =
1640 new std::vector<base::DictionaryValue*>();
1641 for (extensions::ExtensionSet::const_iterator ext = extensions->begin();
1642 ext != extensions->end(); ++ext) {
1643 // Only return information about extensions that are actually apps.
1644 if ((*ext)->is_app()) {
1645 base::DictionaryValue* app_info = new base::DictionaryValue();
1646 AppLauncherHandler::CreateAppInfo(ext->get(), ext_service, app_info);
1647 app_info->SetBoolean(
1648 "is_component_extension",
1649 (*ext)->location() == extensions::Manifest::COMPONENT);
1651 // Convert the launch_type integer into a more descriptive string.
1653 const char* kLaunchType = "launch_type";
1654 if (!app_info->GetInteger(kLaunchType, &launch_type)) {
1655 NOTREACHED() << "Can't get integer from key " << kLaunchType;
1658 if (launch_type == extensions::LAUNCH_TYPE_PINNED) {
1659 app_info->SetString(kLaunchType, "pinned");
1660 } else if (launch_type == extensions::LAUNCH_TYPE_REGULAR) {
1661 app_info->SetString(kLaunchType, "regular");
1662 } else if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN) {
1663 app_info->SetString(kLaunchType, "fullscreen");
1664 } else if (launch_type == extensions::LAUNCH_TYPE_WINDOW) {
1665 app_info->SetString(kLaunchType, "window");
1667 app_info->SetString(kLaunchType, "unknown");
1670 apps_list->push_back(app_info);
1678 NTPInfoObserver::NTPInfoObserver(AutomationProvider* automation,
1679 IPC::Message* reply_message)
1680 : automation_(automation->AsWeakPtr()),
1681 reply_message_(reply_message),
1683 ntp_info_(new base::DictionaryValue) {
1684 top_sites_ = automation_->profile()->GetTopSites();
1686 AutomationJSONReply(automation_.get(), reply_message_.release())
1687 .SendError("Profile does not have service for querying the top sites.");
1690 TabRestoreService* service =
1691 TabRestoreServiceFactory::GetForProfile(automation_->profile());
1693 AutomationJSONReply(automation_.get(), reply_message_.release())
1694 .SendError("No TabRestoreService.");
1698 // Collect information about the apps in the new tab page.
1699 ExtensionService* ext_service = extensions::ExtensionSystem::Get(
1700 automation_->profile())->extension_service();
1702 AutomationJSONReply(automation_.get(), reply_message_.release())
1703 .SendError("No ExtensionService.");
1706 // Process enabled extensions.
1707 extensions::ExtensionRegistry* extension_registry =
1708 extensions::ExtensionRegistry::Get(automation_->profile());
1709 base::ListValue* apps_list = new base::ListValue();
1710 const extensions::ExtensionSet& enabled_extensions =
1711 extension_registry->enabled_extensions();
1712 std::vector<base::DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions(
1713 &enabled_extensions, ext_service);
1714 for (std::vector<base::DictionaryValue*>::const_iterator app =
1715 enabled_apps->begin(); app != enabled_apps->end(); ++app) {
1716 (*app)->SetBoolean("is_disabled", false);
1717 apps_list->Append(*app);
1719 delete enabled_apps;
1720 // Process disabled extensions.
1721 const extensions::ExtensionSet& disabled_extensions =
1722 extension_registry->disabled_extensions();
1723 std::vector<base::DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions(
1724 &disabled_extensions, ext_service);
1725 for (std::vector<base::DictionaryValue*>::const_iterator app =
1726 disabled_apps->begin(); app != disabled_apps->end(); ++app) {
1727 (*app)->SetBoolean("is_disabled", true);
1728 apps_list->Append(*app);
1730 delete disabled_apps;
1731 // Process terminated extensions.
1732 const extensions::ExtensionSet& terminated_extensions =
1733 extension_registry->terminated_extensions();
1734 std::vector<base::DictionaryValue*>* terminated_apps =
1735 GetAppInfoFromExtensions(&terminated_extensions, ext_service);
1736 for (std::vector<base::DictionaryValue*>::const_iterator app =
1737 terminated_apps->begin(); app != terminated_apps->end(); ++app) {
1738 (*app)->SetBoolean("is_disabled", true);
1739 apps_list->Append(*app);
1741 delete terminated_apps;
1742 ntp_info_->Set("apps", apps_list);
1744 // Get the info that would be displayed in the recently closed section.
1745 base::ListValue* recently_closed_list = new base::ListValue;
1746 RecentlyClosedTabsHandler::CreateRecentlyClosedValues(service->entries(),
1747 recently_closed_list);
1748 ntp_info_->Set("recently_closed", recently_closed_list);
1750 // Add default site URLs.
1751 base::ListValue* default_sites_list = new base::ListValue;
1752 history::MostVisitedURLList urls = top_sites_->GetPrepopulatePages();
1753 for (size_t i = 0; i < urls.size(); ++i) {
1754 default_sites_list->Append(base::Value::CreateStringValue(
1755 urls[i].url.possibly_invalid_spec()));
1757 ntp_info_->Set("default_sites", default_sites_list);
1759 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_UPDATED,
1760 content::Source<history::TopSites>(top_sites_));
1761 if (top_sites_->loaded()) {
1764 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_LOADED,
1765 content::Source<Profile>(automation_->profile()));
1769 NTPInfoObserver::~NTPInfoObserver() {}
1771 void NTPInfoObserver::Observe(int type,
1772 const content::NotificationSource& source,
1773 const content::NotificationDetails& details) {
1774 if (type == chrome::NOTIFICATION_TOP_SITES_LOADED) {
1776 } else if (type == chrome::NOTIFICATION_TOP_SITES_UPDATED) {
1777 content::Details<CancelableRequestProvider::Handle> request_details(
1779 if (request_ == *request_details.ptr()) {
1780 top_sites_->GetMostVisitedURLs(
1781 base::Bind(&NTPInfoObserver::OnTopSitesReceived,
1782 base::Unretained(this)), false);
1787 void NTPInfoObserver::OnTopSitesLoaded() {
1788 request_ = top_sites_->StartQueryForMostVisited();
1791 void NTPInfoObserver::OnTopSitesReceived(
1792 const history::MostVisitedURLList& visited_list) {
1793 if (!automation_.get()) {
1798 base::ListValue* list_value = new base::ListValue;
1799 for (size_t i = 0; i < visited_list.size(); ++i) {
1800 const history::MostVisitedURL& visited = visited_list[i];
1801 if (visited.url.spec().empty())
1802 break; // This is the signal that there are no more real visited sites.
1803 base::DictionaryValue* dict = new base::DictionaryValue;
1804 dict->SetString("url", visited.url.spec());
1805 dict->SetString("title", visited.title);
1806 list_value->Append(dict);
1808 ntp_info_->Set("most_visited", list_value);
1809 AutomationJSONReply(automation_.get(), reply_message_.release())
1810 .SendSuccess(ntp_info_.get());
1814 AppLaunchObserver::AppLaunchObserver(
1815 NavigationController* controller,
1816 AutomationProvider* automation,
1817 IPC::Message* reply_message,
1818 extensions::LaunchContainer launch_container)
1819 : controller_(controller),
1820 automation_(automation->AsWeakPtr()),
1821 reply_message_(reply_message),
1822 launch_container_(launch_container),
1823 new_window_id_(extension_misc::kUnknownWindowId) {
1824 if (launch_container_ == extensions::LAUNCH_CONTAINER_TAB) {
1825 // Need to wait for the currently-active tab to reload.
1826 content::Source<NavigationController> source(controller_);
1827 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1829 // Need to wait for a new tab in a new window to load.
1830 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
1831 content::NotificationService::AllSources());
1832 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
1833 content::NotificationService::AllSources());
1837 AppLaunchObserver::~AppLaunchObserver() {}
1839 void AppLaunchObserver::Observe(int type,
1840 const content::NotificationSource& source,
1841 const content::NotificationDetails& details) {
1842 if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) {
1843 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
1844 content::Source<Browser>(source).ptr());
1848 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
1849 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(
1850 content::Source<NavigationController>(source)->GetWebContents());
1851 if ((launch_container_ == extensions::LAUNCH_CONTAINER_TAB) ||
1852 (session_tab_helper &&
1853 (session_tab_helper->window_id().id() == new_window_id_))) {
1854 if (automation_.get()) {
1855 AutomationJSONReply(automation_.get(), reply_message_.release())
1862 RendererProcessClosedObserver::RendererProcessClosedObserver(
1863 AutomationProvider* automation,
1864 IPC::Message* reply_message)
1865 : automation_(automation->AsWeakPtr()),
1866 reply_message_(reply_message) {
1867 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
1868 content::NotificationService::AllSources());
1871 RendererProcessClosedObserver::~RendererProcessClosedObserver() {}
1873 void RendererProcessClosedObserver::Observe(
1875 const content::NotificationSource& source,
1876 const content::NotificationDetails& details) {
1877 if (automation_.get()) {
1878 AutomationJSONReply(automation_.get(), reply_message_.release())
1884 InputEventAckNotificationObserver::InputEventAckNotificationObserver(
1885 AutomationProvider* automation,
1886 IPC::Message* reply_message,
1889 : automation_(automation->AsWeakPtr()),
1890 reply_message_(reply_message),
1891 event_type_(event_type),
1896 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
1897 content::NotificationService::AllSources());
1900 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
1901 content::NotificationService::AllSources());
1904 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {}
1906 void InputEventAckNotificationObserver::Observe(
1908 const content::NotificationSource& source,
1909 const content::NotificationDetails& details) {
1910 if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
1911 AutomationJSONReply(automation_.get(), reply_message_.release())
1917 content::Details<int> request_details(details);
1918 // If the event type matches for |count_| times, replies with a JSON message.
1919 if (event_type_ == *request_details.ptr()) {
1920 if (--count_ == 0 && automation_.get()) {
1921 AutomationJSONReply(automation_.get(), reply_message_.release())
1926 LOG(WARNING) << "Ignoring unexpected event type: "
1927 << *request_details.ptr() << " (expected: " << event_type_
1932 NewTabObserver::NewTabObserver(AutomationProvider* automation,
1933 IPC::Message* reply_message,
1934 bool use_json_interface)
1935 : automation_(automation->AsWeakPtr()),
1936 reply_message_(reply_message),
1937 use_json_interface_(use_json_interface) {
1938 // Use TAB_PARENTED to detect the new tab.
1939 registrar_.Add(this,
1940 chrome::NOTIFICATION_TAB_PARENTED,
1941 content::NotificationService::AllSources());
1944 void NewTabObserver::Observe(int type,
1945 const content::NotificationSource& source,
1946 const content::NotificationDetails& details) {
1947 DCHECK_EQ(chrome::NOTIFICATION_TAB_PARENTED, type);
1948 NavigationController* controller =
1949 &(content::Source<content::WebContents>(source).ptr()->GetController());
1950 if (automation_.get()) {
1951 // TODO(phajdan.jr): Clean up this hack. We write the correct return type
1952 // here, but don't send the message. NavigationNotificationObserver
1953 // will wait properly for the load to finish, and send the message,
1954 // but it will also append its own return value at the end of the reply.
1955 if (!use_json_interface_)
1956 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
1958 new NavigationNotificationObserver(controller,
1960 reply_message_.release(),
1963 use_json_interface_);
1968 NewTabObserver::~NewTabObserver() {
1971 WaitForProcessLauncherThreadToGoIdleObserver::
1972 WaitForProcessLauncherThreadToGoIdleObserver(
1973 AutomationProvider* automation, IPC::Message* reply_message)
1974 : automation_(automation->AsWeakPtr()),
1975 reply_message_(reply_message) {
1976 // Balanced in RunOnUIThread.
1978 BrowserThread::PostTask(
1979 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
1981 &WaitForProcessLauncherThreadToGoIdleObserver::
1982 RunOnProcessLauncherThread,
1986 WaitForProcessLauncherThreadToGoIdleObserver::
1987 ~WaitForProcessLauncherThreadToGoIdleObserver() {
1990 void WaitForProcessLauncherThreadToGoIdleObserver::
1991 RunOnProcessLauncherThread() {
1992 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
1993 BrowserThread::PostTask(
1994 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
1996 &WaitForProcessLauncherThreadToGoIdleObserver::
1997 RunOnProcessLauncherThread2,
2001 void WaitForProcessLauncherThreadToGoIdleObserver::
2002 RunOnProcessLauncherThread2() {
2003 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2004 BrowserThread::PostTask(
2005 BrowserThread::UI, FROM_HERE,
2006 base::Bind(&WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread,
2010 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() {
2011 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2012 if (automation_.get())
2013 automation_->Send(reply_message_.release());
2017 DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver(
2018 AutomationProvider* automation,
2019 IPC::Message* reply_message)
2020 : automation_(automation->AsWeakPtr()),
2021 reply_message_(reply_message) {
2024 content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK,
2025 content::NotificationService::AllSources());
2028 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
2029 content::NotificationService::AllSources());
2032 DragTargetDropAckNotificationObserver::
2033 ~DragTargetDropAckNotificationObserver() {}
2035 void DragTargetDropAckNotificationObserver::Observe(
2037 const content::NotificationSource& source,
2038 const content::NotificationDetails& details) {
2039 if (automation_.get()) {
2040 AutomationJSONReply(automation_.get(), reply_message_.release())
2046 ProcessInfoObserver::ProcessInfoObserver(
2047 AutomationProvider* automation,
2048 IPC::Message* reply_message)
2049 : automation_(automation->AsWeakPtr()),
2050 reply_message_(reply_message) {}
2052 ProcessInfoObserver::~ProcessInfoObserver() {}
2054 void ProcessInfoObserver::OnDetailsAvailable() {
2055 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2056 base::ListValue* browser_proc_list = new base::ListValue();
2057 const std::vector<ProcessData>& all_processes = processes();
2058 for (size_t index = 0; index < all_processes.size(); ++index) {
2059 base::DictionaryValue* browser_data = new base::DictionaryValue();
2060 browser_data->SetString("name", all_processes[index].name);
2061 browser_data->SetString("process_name", all_processes[index].process_name);
2063 base::ListValue* proc_list = new base::ListValue();
2064 for (ProcessMemoryInformationList::const_iterator iterator =
2065 all_processes[index].processes.begin();
2066 iterator != all_processes[index].processes.end(); ++iterator) {
2067 base::DictionaryValue* proc_data = new base::DictionaryValue();
2069 proc_data->SetInteger("pid", iterator->pid);
2071 // Working set (resident) memory usage, in KBytes.
2072 base::DictionaryValue* working_set = new base::DictionaryValue();
2073 working_set->SetInteger("priv", iterator->working_set.priv);
2074 working_set->SetInteger("shareable", iterator->working_set.shareable);
2075 working_set->SetInteger("shared", iterator->working_set.shared);
2076 proc_data->Set("working_set_mem", working_set);
2078 // Committed (resident + paged) memory usage, in KBytes.
2079 base::DictionaryValue* committed = new base::DictionaryValue();
2080 committed->SetInteger("priv", iterator->committed.priv);
2081 committed->SetInteger("mapped", iterator->committed.mapped);
2082 committed->SetInteger("image", iterator->committed.image);
2083 proc_data->Set("committed_mem", committed);
2085 proc_data->SetString("version", iterator->version);
2086 proc_data->SetString("product_name", iterator->product_name);
2087 proc_data->SetInteger("num_processes", iterator->num_processes);
2088 proc_data->SetBoolean("is_diagnostics", iterator->is_diagnostics);
2090 // Process type, if this is a child process of Chrome (e.g., 'plugin').
2091 std::string process_type = "Unknown";
2092 // The following condition avoids a DCHECK in debug builds when the
2093 // process type passed to |GetTypeNameInEnglish| is unknown.
2094 if (iterator->process_type != content::PROCESS_TYPE_UNKNOWN) {
2096 content::GetProcessTypeNameInEnglish(iterator->process_type);
2098 proc_data->SetString("child_process_type", process_type);
2100 // Renderer type, if this is a renderer process.
2101 std::string renderer_type = "Unknown";
2102 if (iterator->renderer_type !=
2103 ProcessMemoryInformation::RENDERER_UNKNOWN) {
2104 renderer_type = ProcessMemoryInformation::GetRendererTypeNameInEnglish(
2105 iterator->renderer_type);
2107 proc_data->SetString("renderer_type", renderer_type);
2109 // Titles associated with this process.
2110 base::ListValue* titles = new base::ListValue();
2111 for (size_t title_index = 0; title_index < iterator->titles.size();
2114 base::Value::CreateStringValue(iterator->titles[title_index]));
2116 proc_data->Set("titles", titles);
2118 proc_list->Append(proc_data);
2120 browser_data->Set("processes", proc_list);
2122 browser_proc_list->Append(browser_data);
2124 return_value->Set("browsers", browser_proc_list);
2126 if (automation_.get()) {
2127 AutomationJSONReply(automation_.get(), reply_message_.release())
2128 .SendSuccess(return_value.get());
2132 V8HeapStatsObserver::V8HeapStatsObserver(
2133 AutomationProvider* automation,
2134 IPC::Message* reply_message,
2135 base::ProcessId renderer_id)
2136 : automation_(automation->AsWeakPtr()),
2137 reply_message_(reply_message),
2138 renderer_id_(renderer_id) {
2141 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
2142 content::NotificationService::AllSources());
2145 V8HeapStatsObserver::~V8HeapStatsObserver() {}
2147 void V8HeapStatsObserver::Observe(
2149 const content::NotificationSource& source,
2150 const content::NotificationDetails& details) {
2151 DCHECK(type == chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED);
2153 base::ProcessId updated_renderer_id =
2154 *(content::Source<base::ProcessId>(source).ptr());
2155 // Only return information for the renderer ID we're interested in.
2156 if (renderer_id_ != updated_renderer_id)
2159 ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap_details =
2160 content::Details<ChromeRenderMessageFilter::V8HeapStatsDetails>(details)
2162 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2163 return_value->SetInteger("renderer_id", updated_renderer_id);
2164 return_value->SetInteger("v8_memory_allocated",
2165 v8_heap_details->v8_memory_allocated());
2166 return_value->SetInteger("v8_memory_used",
2167 v8_heap_details->v8_memory_used());
2169 if (automation_.get()) {
2170 AutomationJSONReply(automation_.get(), reply_message_.release())
2171 .SendSuccess(return_value.get());
2176 FPSObserver::FPSObserver(
2177 AutomationProvider* automation,
2178 IPC::Message* reply_message,
2179 base::ProcessId renderer_id,
2181 : automation_(automation->AsWeakPtr()),
2182 reply_message_(reply_message),
2183 renderer_id_(renderer_id),
2184 routing_id_(routing_id) {
2187 chrome::NOTIFICATION_RENDERER_FPS_COMPUTED,
2188 content::NotificationService::AllSources());
2191 FPSObserver::~FPSObserver() {}
2193 void FPSObserver::Observe(
2195 const content::NotificationSource& source,
2196 const content::NotificationDetails& details) {
2197 DCHECK(type == chrome::NOTIFICATION_RENDERER_FPS_COMPUTED);
2199 base::ProcessId updated_renderer_id =
2200 *(content::Source<base::ProcessId>(source).ptr());
2201 // Only return information for the renderer ID we're interested in.
2202 if (renderer_id_ != updated_renderer_id)
2205 ChromeRenderMessageFilter::FPSDetails* fps_details =
2206 content::Details<ChromeRenderMessageFilter::FPSDetails>(details).ptr();
2207 // Only return information for the routing id of the host render view we're
2209 if (routing_id_ != fps_details->routing_id())
2212 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2213 return_value->SetInteger("renderer_id", updated_renderer_id);
2214 return_value->SetInteger("routing_id", fps_details->routing_id());
2215 return_value->SetDouble("fps", fps_details->fps());
2216 if (automation_.get()) {
2217 AutomationJSONReply(automation_.get(), reply_message_.release())
2218 .SendSuccess(return_value.get());
2223 BrowserOpenedWithNewProfileNotificationObserver::
2224 BrowserOpenedWithNewProfileNotificationObserver(
2225 AutomationProvider* automation,
2226 IPC::Message* reply_message)
2227 : automation_(automation->AsWeakPtr()),
2228 reply_message_(reply_message),
2229 new_window_id_(extension_misc::kUnknownWindowId) {
2230 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
2231 content::NotificationService::AllBrowserContextsAndSources());
2232 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2233 content::NotificationService::AllBrowserContextsAndSources());
2234 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2235 content::NotificationService::AllBrowserContextsAndSources());
2238 BrowserOpenedWithNewProfileNotificationObserver::
2239 ~BrowserOpenedWithNewProfileNotificationObserver() {
2242 void BrowserOpenedWithNewProfileNotificationObserver::Observe(
2244 const content::NotificationSource& source,
2245 const content::NotificationDetails& details) {
2246 if (!automation_.get()) {
2251 if (type == chrome::NOTIFICATION_PROFILE_CREATED) {
2252 // As part of multi-profile creation, a new browser window will
2253 // automatically be opened.
2254 Profile* profile = content::Source<Profile>(source).ptr();
2256 AutomationJSONReply(automation_.get(), reply_message_.release())
2257 .SendError("Profile could not be created.");
2260 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2261 // Store the new browser ID and continue waiting for a new tab within it
2263 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
2264 content::Source<Browser>(source).ptr());
2266 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
2267 // Only send the result if the loaded tab is in the new window.
2268 NavigationController* controller =
2269 content::Source<NavigationController>(source).ptr();
2270 SessionTabHelper* session_tab_helper =
2271 SessionTabHelper::FromWebContents(controller->GetWebContents());
2272 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2274 if (window_id == new_window_id_) {
2275 if (automation_.get()) {
2276 AutomationJSONReply(automation_.get(), reply_message_.release())
2284 ExtensionPopupObserver::ExtensionPopupObserver(
2285 AutomationProvider* automation,
2286 IPC::Message* reply_message,
2287 const std::string& extension_id)
2288 : automation_(automation->AsWeakPtr()),
2289 reply_message_(reply_message),
2290 extension_id_(extension_id) {
2291 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
2292 content::NotificationService::AllSources());
2295 ExtensionPopupObserver::~ExtensionPopupObserver() {
2298 void ExtensionPopupObserver::Observe(
2300 const content::NotificationSource& source,
2301 const content::NotificationDetails& details) {
2302 if (!automation_.get()) {
2307 extensions::ExtensionHost* host =
2308 content::Details<extensions::ExtensionHost>(details).ptr();
2309 if (host->extension_id() == extension_id_ &&
2310 host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) {
2311 AutomationJSONReply(automation_.get(), reply_message_.release())
2317 #if defined(OS_LINUX)
2318 WindowMaximizedObserver::WindowMaximizedObserver(
2319 AutomationProvider* automation,
2320 IPC::Message* reply_message)
2321 : automation_(automation->AsWeakPtr()),
2322 reply_message_(reply_message) {
2323 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
2324 content::NotificationService::AllSources());
2327 WindowMaximizedObserver::~WindowMaximizedObserver() {}
2329 void WindowMaximizedObserver::Observe(
2331 const content::NotificationSource& source,
2332 const content::NotificationDetails& details) {
2333 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, type);
2335 if (automation_.get()) {
2336 AutomationJSONReply(automation_.get(), reply_message_.release())
2341 #endif // defined(OS_LINUX)
2343 BrowserOpenedWithExistingProfileNotificationObserver::
2344 BrowserOpenedWithExistingProfileNotificationObserver(
2345 AutomationProvider* automation,
2346 IPC::Message* reply_message,
2348 : automation_(automation->AsWeakPtr()),
2349 reply_message_(reply_message),
2350 new_window_id_(extension_misc::kUnknownWindowId),
2351 num_loads_(num_loads) {
2352 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2353 content::NotificationService::AllBrowserContextsAndSources());
2354 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2355 content::NotificationService::AllBrowserContextsAndSources());
2358 BrowserOpenedWithExistingProfileNotificationObserver::
2359 ~BrowserOpenedWithExistingProfileNotificationObserver() {
2362 void BrowserOpenedWithExistingProfileNotificationObserver::Observe(
2364 const content::NotificationSource& source,
2365 const content::NotificationDetails& details) {
2366 if (!automation_.get()) {
2371 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2372 // Store the new browser ID and continue waiting for NOTIFICATION_LOAD_STOP.
2373 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
2374 content::Source<Browser>(source).ptr());
2375 } else if (type == content::NOTIFICATION_LOAD_STOP) {
2376 // Only consider if the loaded tab is in the new window.
2377 NavigationController* controller =
2378 content::Source<NavigationController>(source).ptr();
2379 SessionTabHelper* session_tab_helper =
2380 SessionTabHelper::FromWebContents(controller->GetWebContents());
2381 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2383 if (window_id == new_window_id_ && --num_loads_ == 0) {
2384 if (automation_.get()) {
2385 AutomationJSONReply(automation_.get(), reply_message_.release())