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_process_manager.h"
36 #include "chrome/browser/extensions/extension_service.h"
37 #include "chrome/browser/extensions/extension_system.h"
38 #include "chrome/browser/extensions/extension_tab_util.h"
39 #include "chrome/browser/history/history_types.h"
40 #include "chrome/browser/history/top_sites.h"
41 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
42 #include "chrome/browser/infobars/infobar_service.h"
43 #include "chrome/browser/metrics/metric_event_duration_details.h"
44 #include "chrome/browser/notifications/balloon.h"
45 #include "chrome/browser/notifications/balloon_collection.h"
46 #include "chrome/browser/notifications/balloon_host.h"
47 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
48 #include "chrome/browser/notifications/notification.h"
49 #include "chrome/browser/password_manager/password_store_change.h"
50 #include "chrome/browser/profiles/profile.h"
51 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
52 #include "chrome/browser/search_engines/template_url_service.h"
53 #include "chrome/browser/search_engines/template_url_service_factory.h"
54 #include "chrome/browser/sessions/session_tab_helper.h"
55 #include "chrome/browser/sessions/tab_restore_service.h"
56 #include "chrome/browser/sessions/tab_restore_service_factory.h"
57 #include "chrome/browser/ui/browser.h"
58 #include "chrome/browser/ui/browser_iterator.h"
59 #include "chrome/browser/ui/browser_list.h"
60 #include "chrome/browser/ui/browser_window.h"
61 #include "chrome/browser/ui/find_bar/find_notification_details.h"
62 #include "chrome/browser/ui/host_desktop.h"
63 #include "chrome/browser/ui/login/login_prompt.h"
64 #include "chrome/browser/ui/tabs/tab_strip_model.h"
65 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
66 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
67 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
68 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
69 #include "chrome/common/automation_constants.h"
70 #include "chrome/common/automation_messages.h"
71 #include "chrome/common/content_settings_types.h"
72 #include "chrome/common/extensions/extension.h"
73 #include "content/public/browser/dom_operation_notification_details.h"
74 #include "content/public/browser/navigation_controller.h"
75 #include "content/public/browser/notification_service.h"
76 #include "content/public/browser/render_process_host.h"
77 #include "content/public/browser/render_view_host.h"
78 #include "content/public/browser/web_contents.h"
79 #include "content/public/common/process_type.h"
80 #include "extensions/common/manifest.h"
81 #include "extensions/common/view_type.h"
82 #include "ui/gfx/codec/png_codec.h"
83 #include "ui/gfx/rect.h"
86 using content::BrowserThread;
87 using content::DomOperationNotificationDetails;
88 using content::DownloadItem;
89 using content::DownloadManager;
90 using content::NavigationController;
91 using content::RenderViewHost;
92 using content::WebContents;
94 // Holds onto start and stop timestamps for a particular tab
95 class InitialLoadObserver::TabTime {
97 explicit TabTime(base::TimeTicks started)
98 : load_start_time_(started) {
100 void set_stop_time(base::TimeTicks stopped) {
101 load_stop_time_ = stopped;
103 base::TimeTicks stop_time() const {
104 return load_stop_time_;
106 base::TimeTicks start_time() const {
107 return load_start_time_;
110 base::TimeTicks load_start_time_;
111 base::TimeTicks load_stop_time_;
114 InitialLoadObserver::InitialLoadObserver(size_t tab_count,
115 AutomationProvider* automation)
116 : automation_(automation->AsWeakPtr()),
117 crashed_tab_count_(0),
118 outstanding_tab_count_(tab_count),
119 init_time_(base::TimeTicks::Now()) {
120 if (outstanding_tab_count_ > 0) {
121 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
122 content::NotificationService::AllSources());
123 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
124 content::NotificationService::AllSources());
125 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
126 content::NotificationService::AllSources());
130 InitialLoadObserver::~InitialLoadObserver() {
133 void InitialLoadObserver::Observe(int type,
134 const content::NotificationSource& source,
135 const content::NotificationDetails& details) {
136 if (type == content::NOTIFICATION_LOAD_START) {
137 if (outstanding_tab_count_ > loading_tabs_.size())
138 loading_tabs_.insert(TabTimeMap::value_type(
140 TabTime(base::TimeTicks::Now())));
141 } else if (type == content::NOTIFICATION_LOAD_STOP) {
142 if (outstanding_tab_count_ > finished_tabs_.size()) {
143 TabTimeMap::iterator iter = loading_tabs_.find(source.map_key());
144 if (iter != loading_tabs_.end()) {
145 finished_tabs_.insert(source.map_key());
146 iter->second.set_stop_time(base::TimeTicks::Now());
149 } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
150 base::TerminationStatus status =
151 content::Details<content::RenderProcessHost::RendererClosedDetails>(
154 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
157 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
158 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
159 case base::TERMINATION_STATUS_PROCESS_CRASHED:
160 crashed_tab_count_++;
163 case base::TERMINATION_STATUS_STILL_RUNNING:
164 LOG(ERROR) << "Got RENDERER_PROCESS_CLOSED notification, "
165 << "but the process is still running. We may miss further "
166 << "crash notification, resulting in hangs.";
170 LOG(ERROR) << "Unhandled termination status " << status;
178 if (finished_tabs_.size() + crashed_tab_count_ >= outstanding_tab_count_)
182 DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
183 ListValue* items = new ListValue;
184 for (TabTimeMap::const_iterator it = loading_tabs_.begin();
185 it != loading_tabs_.end();
187 DictionaryValue* item = new DictionaryValue;
188 base::TimeDelta delta_start = it->second.start_time() - init_time_;
190 item->SetDouble("load_start_ms", delta_start.InMillisecondsF());
191 if (it->second.stop_time().is_null()) {
192 item->Set("load_stop_ms", Value::CreateNullValue());
194 base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
195 item->SetDouble("load_stop_ms", delta_stop.InMillisecondsF());
199 DictionaryValue* return_value = new DictionaryValue;
200 return_value->Set("tabs", items);
204 void InitialLoadObserver::ConditionMet() {
205 registrar_.RemoveAll();
206 if (automation_.get())
207 automation_->OnInitialTabLoadsComplete();
210 NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation,
212 : automation_(automation->AsWeakPtr()) {
213 registrar_.Add(this, chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD,
214 content::Source<Profile>(profile));
217 NewTabUILoadObserver::~NewTabUILoadObserver() {
220 void NewTabUILoadObserver::Observe(int type,
221 const content::NotificationSource& source,
222 const content::NotificationDetails& details) {
223 if (type == chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD) {
224 content::Details<int> load_time(details);
225 if (automation_.get()) {
227 new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr()));
234 NavigationControllerRestoredObserver::NavigationControllerRestoredObserver(
235 AutomationProvider* automation,
236 NavigationController* controller,
237 IPC::Message* reply_message)
238 : automation_(automation->AsWeakPtr()),
239 controller_(controller),
240 reply_message_(reply_message) {
241 if (FinishedRestoring()) {
244 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
245 content::NotificationService::AllSources());
249 NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() {
252 void NavigationControllerRestoredObserver::Observe(
253 int type, const content::NotificationSource& source,
254 const content::NotificationDetails& details) {
255 if (FinishedRestoring()) {
256 registrar_.RemoveAll();
261 bool NavigationControllerRestoredObserver::FinishedRestoring() {
262 return (!controller_->NeedsReload() && !controller_->GetPendingEntry() &&
263 !controller_->GetWebContents()->IsLoading());
266 void NavigationControllerRestoredObserver::SendDone() {
267 if (automation_.get()) {
268 AutomationJSONReply(automation_.get(), reply_message_.release())
274 NavigationNotificationObserver::NavigationNotificationObserver(
275 NavigationController* controller,
276 AutomationProvider* automation,
277 IPC::Message* reply_message,
278 int number_of_navigations,
279 bool include_current_navigation,
280 bool use_json_interface)
281 : automation_(automation->AsWeakPtr()),
282 reply_message_(reply_message),
283 controller_(controller),
284 navigations_remaining_(number_of_navigations),
285 navigation_started_(false),
286 use_json_interface_(use_json_interface) {
287 if (number_of_navigations == 0) {
288 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
291 DCHECK_LT(0, navigations_remaining_);
292 content::Source<NavigationController> source(controller_);
293 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source);
294 registrar_.Add(this, content::NOTIFICATION_LOAD_START, source);
295 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
296 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
297 registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source);
298 registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source);
299 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
300 content::NotificationService::AllSources());
302 if (include_current_navigation && controller->GetWebContents()->IsLoading())
303 navigation_started_ = true;
306 NavigationNotificationObserver::~NavigationNotificationObserver() {
309 void NavigationNotificationObserver::Observe(
310 int type, const content::NotificationSource& source,
311 const content::NotificationDetails& details) {
312 if (!automation_.get()) {
317 // We listen for 2 events to determine when the navigation started because:
318 // - when this is used by the WaitForNavigation method, we might be invoked
319 // afer the load has started (but not after the entry was committed, as
320 // WaitForNavigation compares times of the last navigation).
321 // - when this is used with a page requiring authentication, we will not get
322 // a chrome::NAV_ENTRY_COMMITTED until after we authenticate, so
323 // we need the chrome::LOAD_START.
324 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED ||
325 type == content::NOTIFICATION_LOAD_START) {
326 navigation_started_ = true;
327 } else if (type == content::NOTIFICATION_LOAD_STOP) {
328 if (navigation_started_) {
329 navigation_started_ = false;
330 if (--navigations_remaining_ == 0)
331 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
333 } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED ||
334 type == chrome::NOTIFICATION_AUTH_CANCELLED) {
335 // Treat this as if navigation started again, since load start/stop don't
336 // occur while authentication is ongoing.
337 navigation_started_ = true;
338 } else if (type == chrome::NOTIFICATION_AUTH_NEEDED) {
339 // Respond that authentication is needed.
340 navigation_started_ = false;
341 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
342 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
343 ConditionMet(AUTOMATION_MSG_NAVIGATION_BLOCKED_BY_MODAL_DIALOG);
349 void NavigationNotificationObserver::ConditionMet(
350 AutomationMsg_NavigationResponseValues navigation_result) {
351 if (automation_.get()) {
352 if (use_json_interface_) {
353 if (navigation_result == AUTOMATION_MSG_NAVIGATION_SUCCESS) {
354 DictionaryValue dict;
355 dict.SetInteger("result", navigation_result);
356 AutomationJSONReply(automation_.get(), reply_message_.release())
359 AutomationJSONReply(automation_.get(), reply_message_.release())
360 .SendError(base::StringPrintf(
361 "Navigation failed with error code=%d.", navigation_result));
364 IPC::ParamTraits<int>::Write(
365 reply_message_.get(), navigation_result);
366 automation_->Send(reply_message_.release());
373 TabStripNotificationObserver::TabStripNotificationObserver(
374 int notification, AutomationProvider* automation)
375 : automation_(automation->AsWeakPtr()),
376 notification_(notification) {
377 registrar_.Add(this, notification_,
378 content::NotificationService::AllSources());
381 TabStripNotificationObserver::~TabStripNotificationObserver() {
384 void TabStripNotificationObserver::Observe(
386 const content::NotificationSource& source,
387 const content::NotificationDetails& details) {
388 DCHECK_EQ(notification_, type);
389 if (type == chrome::NOTIFICATION_TAB_PARENTED) {
390 ObserveTab(&content::Source<content::WebContents>(source)->GetController());
391 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
392 ObserveTab(&content::Source<content::WebContents>(source)->GetController());
394 ObserveTab(content::Source<NavigationController>(source).ptr());
399 TabAppendedNotificationObserver::TabAppendedNotificationObserver(
401 AutomationProvider* automation,
402 IPC::Message* reply_message,
403 bool use_json_interface)
404 : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED,
407 reply_message_(reply_message),
408 use_json_interface_(use_json_interface) {
411 TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {}
413 void TabAppendedNotificationObserver::ObserveTab(
414 NavigationController* controller) {
415 if (!automation_.get() || !reply_message_.get())
418 if (automation_->GetIndexForNavigationController(controller, parent_) ==
419 TabStripModel::kNoTab) {
420 // This tab notification doesn't belong to the parent_.
424 new NavigationNotificationObserver(controller,
426 reply_message_.release(),
429 use_json_interface_);
432 IPC::Message* TabAppendedNotificationObserver::ReleaseReply() {
433 return reply_message_.release();
436 TabClosedNotificationObserver::TabClosedNotificationObserver(
437 AutomationProvider* automation,
438 bool wait_until_closed,
439 IPC::Message* reply_message,
440 bool use_json_interface)
441 : TabStripNotificationObserver((wait_until_closed ?
442 static_cast<int>(content::NOTIFICATION_WEB_CONTENTS_DESTROYED) :
443 static_cast<int>(chrome::NOTIFICATION_TAB_CLOSING)), automation),
444 reply_message_(reply_message),
445 use_json_interface_(use_json_interface),
446 for_browser_command_(false) {
449 TabClosedNotificationObserver::~TabClosedNotificationObserver() {}
451 void TabClosedNotificationObserver::ObserveTab(
452 NavigationController* controller) {
453 if (!automation_.get())
456 if (use_json_interface_) {
457 AutomationJSONReply(automation_.get(), reply_message_.release())
460 if (for_browser_command_) {
461 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
464 AutomationMsg_CloseTab::WriteReplyParams(reply_message_.get(), true);
466 automation_->Send(reply_message_.release());
470 void TabClosedNotificationObserver::set_for_browser_command(
471 bool for_browser_command) {
472 for_browser_command_ = for_browser_command;
475 TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation,
477 IPC::Message* reply_message,
478 int target_tab_count)
479 : automation_(automation->AsWeakPtr()),
480 reply_message_(reply_message),
481 tab_strip_model_(browser->tab_strip_model()),
482 target_tab_count_(target_tab_count) {
483 tab_strip_model_->AddObserver(this);
487 TabCountChangeObserver::~TabCountChangeObserver() {
488 tab_strip_model_->RemoveObserver(this);
491 void TabCountChangeObserver::TabInsertedAt(WebContents* contents,
497 void TabCountChangeObserver::TabDetachedAt(WebContents* contents,
502 void TabCountChangeObserver::TabStripModelDeleted() {
503 if (automation_.get()) {
504 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
505 reply_message_.get(), false);
506 automation_->Send(reply_message_.release());
512 void TabCountChangeObserver::CheckTabCount() {
513 if (tab_strip_model_->count() != target_tab_count_)
516 if (automation_.get()) {
517 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
518 reply_message_.get(), true);
519 automation_->Send(reply_message_.release());
525 bool DidExtensionViewsStopLoading(ExtensionProcessManager* manager) {
526 ExtensionProcessManager::ViewSet all_views = manager->GetAllViews();
527 for (ExtensionProcessManager::ViewSet::const_iterator iter =
529 iter != all_views.end(); ++iter) {
530 if ((*iter)->IsLoading())
536 ExtensionUninstallObserver::ExtensionUninstallObserver(
537 AutomationProvider* automation,
538 IPC::Message* reply_message,
539 const std::string& id)
540 : automation_(automation->AsWeakPtr()),
541 reply_message_(reply_message),
543 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
544 content::NotificationService::AllSources());
545 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
546 content::NotificationService::AllSources());
549 ExtensionUninstallObserver::~ExtensionUninstallObserver() {
552 void ExtensionUninstallObserver::Observe(
554 const content::NotificationSource& source,
555 const content::NotificationDetails& details) {
556 if (!automation_.get()) {
562 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
563 if (id_ == content::Details<extensions::Extension>(details).ptr()->id()) {
564 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
565 return_value->SetBoolean("success", true);
566 AutomationJSONReply(automation_.get(), reply_message_.release())
567 .SendSuccess(return_value.get());
574 case chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED: {
575 const extensions::Extension* extension =
576 content::Details<extensions::Extension>(details).ptr();
577 if (id_ == extension->id()) {
578 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
579 return_value->SetBoolean("success", false);
580 AutomationJSONReply(automation_.get(), reply_message_.release())
581 .SendSuccess(return_value.get());
593 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
594 ExtensionProcessManager* manager, ExtensionService* service,
595 AutomationProvider* automation, IPC::Message* reply_message)
598 automation_(automation->AsWeakPtr()),
599 reply_message_(reply_message),
604 ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() {
607 void ExtensionReadyNotificationObserver::Init() {
608 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
609 content::NotificationService::AllSources());
610 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
611 content::NotificationService::AllSources());
612 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
613 content::NotificationService::AllSources());
614 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
615 content::NotificationService::AllSources());
616 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
617 content::NotificationService::AllSources());
620 void ExtensionReadyNotificationObserver::Observe(
621 int type, const content::NotificationSource& source,
622 const content::NotificationDetails& details) {
623 if (!automation_.get()) {
629 case content::NOTIFICATION_LOAD_STOP:
630 // Only continue on with this method if our extension has been loaded
631 // and all the extension views have stopped loading.
632 if (!extension_ || !DidExtensionViewsStopLoading(manager_))
635 case chrome::NOTIFICATION_EXTENSION_LOADED: {
636 const extensions::Extension* loaded_extension =
637 content::Details<const extensions::Extension>(details).ptr();
638 // Only track an internal or unpacked extension load.
639 extensions::Manifest::Location location = loaded_extension->location();
640 if (location != extensions::Manifest::INTERNAL &&
641 !extensions::Manifest::IsUnpackedLocation(location))
643 extension_ = loaded_extension;
644 if (!DidExtensionViewsStopLoading(manager_))
646 // For some reason, the background extension view is not yet
647 // created at this point so just checking whether all extension views
648 // are loaded is not sufficient. If background page is not ready,
649 // we wait for NOTIFICATION_LOAD_STOP.
650 if (!service_->IsBackgroundPageReady(extension_))
654 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
655 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
656 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
663 AutomationJSONReply reply(automation_.get(), reply_message_.release());
665 DictionaryValue dict;
666 dict.SetString("id", extension_->id());
667 reply.SendSuccess(&dict);
669 reply.SendError("Extension could not be installed");
674 ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
675 : did_receive_unload_notification_(false) {
676 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
677 content::NotificationService::AllSources());
680 ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
683 void ExtensionUnloadNotificationObserver::Observe(
684 int type, const content::NotificationSource& source,
685 const content::NotificationDetails& details) {
686 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
687 did_receive_unload_notification_ = true;
693 ExtensionsUpdatedObserver::ExtensionsUpdatedObserver(
694 ExtensionProcessManager* manager, AutomationProvider* automation,
695 IPC::Message* reply_message)
696 : manager_(manager), automation_(automation->AsWeakPtr()),
697 reply_message_(reply_message), updater_finished_(false) {
698 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
699 content::NotificationService::AllSources());
702 ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() {
705 void ExtensionsUpdatedObserver::Observe(
706 int type, const content::NotificationSource& source,
707 const content::NotificationDetails& details) {
708 if (!automation_.get()) {
713 DCHECK(type == content::NOTIFICATION_LOAD_STOP);
717 void ExtensionsUpdatedObserver::UpdateCheckFinished() {
718 if (!automation_.get()) {
723 // Extension updater has completed updating all extensions.
724 updater_finished_ = true;
728 void ExtensionsUpdatedObserver::MaybeReply() {
729 // Send the reply if (1) the extension updater has finished updating all
730 // extensions; and (2) all extension views have stopped loading.
731 if (updater_finished_ && DidExtensionViewsStopLoading(manager_)) {
732 AutomationJSONReply reply(automation_.get(), reply_message_.release());
733 reply.SendSuccess(NULL);
738 BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver(
739 AutomationProvider* automation,
740 IPC::Message* reply_message,
741 bool use_json_interface)
742 : automation_(automation->AsWeakPtr()),
743 reply_message_(reply_message),
744 new_window_id_(extension_misc::kUnknownWindowId),
745 use_json_interface_(use_json_interface),
746 for_browser_command_(false) {
747 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
748 content::NotificationService::AllBrowserContextsAndSources());
749 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
750 content::NotificationService::AllBrowserContextsAndSources());
753 BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() {
756 void BrowserOpenedNotificationObserver::Observe(
758 const content::NotificationSource& source,
759 const content::NotificationDetails& details) {
760 if (!automation_.get()) {
765 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
766 // Store the new browser ID and continue waiting for a new tab within it
768 new_window_id_ = ExtensionTabUtil::GetWindowId(
769 content::Source<Browser>(source).ptr());
771 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
772 // Only send the result if the loaded tab is in the new window.
773 NavigationController* controller =
774 content::Source<NavigationController>(source).ptr();
775 SessionTabHelper* session_tab_helper =
776 SessionTabHelper::FromWebContents(controller->GetWebContents());
777 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
779 if (window_id == new_window_id_) {
780 if (use_json_interface_) {
781 AutomationJSONReply(automation_.get(), reply_message_.release())
784 if (for_browser_command_) {
785 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
786 reply_message_.get(), true);
788 automation_->Send(reply_message_.release());
796 void BrowserOpenedNotificationObserver::set_for_browser_command(
797 bool for_browser_command) {
798 for_browser_command_ = for_browser_command;
801 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
803 AutomationProvider* automation,
804 IPC::Message* reply_message,
805 bool use_json_interface)
806 : automation_(automation->AsWeakPtr()),
807 reply_message_(reply_message),
808 use_json_interface_(use_json_interface),
809 for_browser_command_(false) {
810 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
811 content::Source<Browser>(browser));
814 BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {}
816 void BrowserClosedNotificationObserver::Observe(
817 int type, const content::NotificationSource& source,
818 const content::NotificationDetails& details) {
819 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSED, type);
821 if (!automation_.get()) {
826 // The automation layer doesn't support non-native desktops.
827 int browser_count = static_cast<int>(BrowserList::GetInstance(
828 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
829 // We get the notification before the browser is removed from the BrowserList.
830 bool app_closing = browser_count == 1;
832 if (use_json_interface_) {
833 AutomationJSONReply(automation_.get(), reply_message_.release())
836 if (for_browser_command_) {
837 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
840 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true,
843 automation_->Send(reply_message_.release());
848 void BrowserClosedNotificationObserver::set_for_browser_command(
849 bool for_browser_command) {
850 for_browser_command_ = for_browser_command;
853 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
855 AutomationProvider* automation,
856 IPC::Message* reply_message)
857 : target_count_(target_count),
858 automation_(automation->AsWeakPtr()),
859 reply_message_(reply_message) {
860 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
861 content::NotificationService::AllBrowserContextsAndSources());
862 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
863 content::NotificationService::AllBrowserContextsAndSources());
866 BrowserCountChangeNotificationObserver::
867 ~BrowserCountChangeNotificationObserver() {}
869 void BrowserCountChangeNotificationObserver::Observe(
871 const content::NotificationSource& source,
872 const content::NotificationDetails& details) {
873 DCHECK(type == chrome::NOTIFICATION_BROWSER_OPENED ||
874 type == chrome::NOTIFICATION_BROWSER_CLOSED);
876 // The automation layer doesn't support non-native desktops.
877 int current_count = static_cast<int>(BrowserList::GetInstance(
878 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
879 if (type == chrome::NOTIFICATION_BROWSER_CLOSED) {
880 // At the time of the notification the browser being closed is not removed
881 // from the list. The real count is one less than the reported count.
882 DCHECK_LT(0, current_count);
886 if (!automation_.get()) {
891 if (current_count == target_count_) {
892 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
893 reply_message_.get(), true);
894 automation_->Send(reply_message_.release());
901 // Define mapping from command to notification
902 struct CommandNotification {
904 int notification_type;
907 const struct CommandNotification command_notifications[] = {
908 {IDC_DUPLICATE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
910 // Returns as soon as the restored tab is created. To further wait until
911 // the content page is loaded, use WaitForTabToBeRestored.
912 {IDC_RESTORE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
914 // For the following commands, we need to wait for a new tab to be created,
915 // load to finish, and title to change.
916 {IDC_MANAGE_EXTENSIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
917 {IDC_OPTIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
918 {IDC_PRINT, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
919 {IDC_SHOW_DOWNLOADS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
920 {IDC_SHOW_HISTORY, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
925 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
929 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
930 AutomationProvider* automation,
933 IPC::Message* reply_message,
934 bool use_json_interface) {
938 new NewTabObserver(automation, reply_message, use_json_interface);
942 case IDC_NEW_INCOGNITO_WINDOW: {
943 BrowserOpenedNotificationObserver* observer =
944 new BrowserOpenedNotificationObserver(automation, reply_message,
946 observer->set_for_browser_command(true);
949 case IDC_CLOSE_WINDOW: {
950 BrowserClosedNotificationObserver* observer =
951 new BrowserClosedNotificationObserver(browser, automation,
954 observer->set_for_browser_command(true);
957 case IDC_CLOSE_TAB: {
958 TabClosedNotificationObserver* observer =
959 new TabClosedNotificationObserver(automation, true, reply_message,
961 observer->set_for_browser_command(true);
967 new NavigationNotificationObserver(
968 &browser->tab_strip_model()->GetActiveWebContents()->GetController(),
969 automation, reply_message, 1, false, use_json_interface);
973 ExecuteBrowserCommandObserver* observer =
974 new ExecuteBrowserCommandObserver(automation, reply_message,
976 if (!observer->Register(command)) {
977 observer->ReleaseReply();
987 void ExecuteBrowserCommandObserver::Observe(
988 int type, const content::NotificationSource& source,
989 const content::NotificationDetails& details) {
990 if (type == notification_type_) {
991 if (automation_.get()) {
992 if (use_json_interface_) {
993 AutomationJSONReply(automation_.get(), reply_message_.release())
996 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
997 reply_message_.get(), true);
998 automation_->Send(reply_message_.release());
1007 ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
1008 AutomationProvider* automation,
1009 IPC::Message* reply_message,
1010 bool use_json_interface)
1011 : automation_(automation->AsWeakPtr()),
1012 notification_type_(content::NOTIFICATION_ALL),
1013 reply_message_(reply_message),
1014 use_json_interface_(use_json_interface) {
1017 bool ExecuteBrowserCommandObserver::Register(int command) {
1018 if (!Getint(command, ¬ification_type_))
1020 registrar_.Add(this, notification_type_,
1021 content::NotificationService::AllSources());
1025 bool ExecuteBrowserCommandObserver::Getint(
1026 int command, int* type) {
1030 for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
1031 if (command_notifications[i].command == command) {
1032 *type = command_notifications[i].notification_type;
1040 IPC::Message* ExecuteBrowserCommandObserver::ReleaseReply() {
1041 return reply_message_.release();
1044 FindInPageNotificationObserver::FindInPageNotificationObserver(
1045 AutomationProvider* automation, WebContents* parent_tab,
1046 bool reply_with_json, IPC::Message* reply_message)
1047 : automation_(automation->AsWeakPtr()),
1048 active_match_ordinal_(-1),
1049 reply_with_json_(reply_with_json),
1050 reply_message_(reply_message) {
1051 registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
1052 content::Source<WebContents>(parent_tab));
1055 FindInPageNotificationObserver::~FindInPageNotificationObserver() {
1058 void FindInPageNotificationObserver::Observe(
1059 int type, const content::NotificationSource& source,
1060 const content::NotificationDetails& details) {
1061 content::Details<FindNotificationDetails> find_details(details);
1062 if (!(find_details->final_update() && reply_message_ != NULL)) {
1063 DVLOG(1) << "Ignoring, since we only care about the final message";
1067 if (!automation_.get()) {
1072 // We get multiple responses and one of those will contain the ordinal.
1073 // This message comes to us before the final update is sent.
1074 if (find_details->request_id() == kFindInPageRequestId) {
1075 if (reply_with_json_) {
1076 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1077 return_value->SetInteger("match_count",
1078 find_details->number_of_matches());
1079 gfx::Rect rect = find_details->selection_rect();
1080 // If MatchCount is > 0, then rect should not be Empty.
1081 // We dont guard it here because we want to let the test
1082 // code catch this invalid case if needed.
1083 if (!rect.IsEmpty()) {
1084 return_value->SetInteger("match_left", rect.x());
1085 return_value->SetInteger("match_top", rect.y());
1086 return_value->SetInteger("match_right", rect.right());
1087 return_value->SetInteger("match_bottom", rect.bottom());
1089 AutomationJSONReply(automation_.get(), reply_message_.release())
1090 .SendSuccess(return_value.get());
1093 if (find_details->active_match_ordinal() > -1) {
1094 active_match_ordinal_ = find_details->active_match_ordinal();
1095 AutomationMsg_Find::WriteReplyParams(reply_message_.get(),
1096 active_match_ordinal_, find_details->number_of_matches());
1097 automation_->Send(reply_message_.release());
1104 const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
1106 DomOperationObserver::DomOperationObserver(int automation_id)
1107 : automation_id_(automation_id) {
1108 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
1109 content::NotificationService::AllSources());
1110 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
1111 content::NotificationService::AllSources());
1112 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1113 content::NotificationService::AllSources());
1116 DomOperationObserver::~DomOperationObserver() {}
1118 void DomOperationObserver::Observe(
1119 int type, const content::NotificationSource& source,
1120 const content::NotificationDetails& details) {
1121 if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) {
1122 content::Details<DomOperationNotificationDetails> dom_op_details(details);
1123 if (dom_op_details->automation_id == automation_id_)
1124 OnDomOperationCompleted(dom_op_details->json);
1125 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
1126 OnJavascriptBlocked();
1128 DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type);
1129 WebContents* web_contents = content::Source<WebContents>(source).ptr();
1131 TabSpecificContentSettings* tab_content_settings =
1132 TabSpecificContentSettings::FromWebContents(web_contents);
1133 if (tab_content_settings &&
1134 tab_content_settings->IsContentBlocked(
1135 CONTENT_SETTINGS_TYPE_JAVASCRIPT))
1136 OnJavascriptBlocked();
1141 DomOperationMessageSender::DomOperationMessageSender(
1142 AutomationProvider* automation,
1143 IPC::Message* reply_message,
1144 bool use_json_interface)
1145 : DomOperationObserver(0),
1146 automation_(automation->AsWeakPtr()),
1147 reply_message_(reply_message),
1148 use_json_interface_(use_json_interface) {
1151 DomOperationMessageSender::~DomOperationMessageSender() {}
1153 void DomOperationMessageSender::OnDomOperationCompleted(
1154 const std::string& json) {
1155 if (automation_.get()) {
1156 if (use_json_interface_) {
1157 DictionaryValue dict;
1158 dict.SetString("result", json);
1159 AutomationJSONReply(automation_.get(), reply_message_.release())
1160 .SendSuccess(&dict);
1162 AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json);
1163 automation_->Send(reply_message_.release());
1169 void DomOperationMessageSender::OnJavascriptBlocked() {
1170 if (automation_.get() && use_json_interface_) {
1171 AutomationJSONReply(automation_.get(), reply_message_.release())
1172 .SendError("Javascript execution was blocked");
1177 MetricEventDurationObserver::MetricEventDurationObserver() {
1178 registrar_.Add(this, chrome::NOTIFICATION_METRIC_EVENT_DURATION,
1179 content::NotificationService::AllSources());
1182 MetricEventDurationObserver::~MetricEventDurationObserver() {}
1184 int MetricEventDurationObserver::GetEventDurationMs(
1185 const std::string& event_name) {
1186 EventDurationMap::const_iterator it = durations_.find(event_name);
1187 if (it == durations_.end())
1192 void MetricEventDurationObserver::Observe(
1194 const content::NotificationSource& source,
1195 const content::NotificationDetails& details) {
1196 if (type != chrome::NOTIFICATION_METRIC_EVENT_DURATION) {
1200 MetricEventDurationDetails* metric_event_duration =
1201 content::Details<MetricEventDurationDetails>(details).ptr();
1202 durations_[metric_event_duration->event_name] =
1203 metric_event_duration->duration_ms;
1206 InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
1207 IPC::Message* reply_message,
1208 WebContents* web_contents,
1209 size_t target_count)
1210 : automation_(automation->AsWeakPtr()),
1211 reply_message_(reply_message),
1212 web_contents_(web_contents),
1213 target_count_(target_count) {
1214 content::Source<InfoBarService> source(
1215 InfoBarService::FromWebContents(web_contents));
1216 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
1218 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
1223 InfoBarCountObserver::~InfoBarCountObserver() {}
1225 void InfoBarCountObserver::Observe(
1227 const content::NotificationSource& source,
1228 const content::NotificationDetails& details) {
1229 DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED ||
1230 type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
1234 void InfoBarCountObserver::CheckCount() {
1235 if (InfoBarService::FromWebContents(web_contents_)->infobar_count() !=
1239 if (automation_.get()) {
1240 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(),
1242 automation_->Send(reply_message_.release());
1247 AutomationProviderBookmarkModelObserver::
1248 AutomationProviderBookmarkModelObserver(
1249 AutomationProvider* provider,
1250 IPC::Message* reply_message,
1251 BookmarkModel* model,
1252 bool use_json_interface)
1253 : automation_provider_(provider->AsWeakPtr()),
1254 reply_message_(reply_message),
1256 use_json_interface_(use_json_interface) {
1257 model_->AddObserver(this);
1260 AutomationProviderBookmarkModelObserver::
1261 ~AutomationProviderBookmarkModelObserver() {
1262 model_->RemoveObserver(this);
1265 void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model,
1266 bool ids_reassigned) {
1267 ReplyAndDelete(true);
1270 void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted(
1271 BookmarkModel* model) {
1272 ReplyAndDelete(false);
1275 IPC::Message* AutomationProviderBookmarkModelObserver::ReleaseReply() {
1276 return reply_message_.release();
1279 void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
1280 if (automation_provider_.get()) {
1281 if (use_json_interface_) {
1282 AutomationJSONReply(automation_provider_.get(), reply_message_.release())
1285 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1286 reply_message_.get(), success);
1287 automation_provider_->Send(reply_message_.release());
1293 AutomationProviderDownloadUpdatedObserver::
1294 AutomationProviderDownloadUpdatedObserver(
1295 AutomationProvider* provider,
1296 IPC::Message* reply_message,
1299 : provider_(provider->AsWeakPtr()),
1300 reply_message_(reply_message),
1301 wait_for_open_(wait_for_open),
1302 incognito_(incognito) {
1305 AutomationProviderDownloadUpdatedObserver::
1306 ~AutomationProviderDownloadUpdatedObserver() {}
1308 void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
1309 DownloadItem* download) {
1310 // If this observer is watching for open, only send the reply if the download
1311 // has been auto-opened.
1312 if (wait_for_open_ && !download->GetAutoOpened())
1315 download->RemoveObserver(this);
1317 if (provider_.get()) {
1318 scoped_ptr<DictionaryValue> return_value(
1319 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1320 AutomationJSONReply(provider_.get(), reply_message_.release())
1321 .SendSuccess(return_value.get());
1326 void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
1327 DownloadItem* download) {
1328 download->RemoveObserver(this);
1330 if (provider_.get()) {
1331 scoped_ptr<DictionaryValue> return_value(
1332 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1333 AutomationJSONReply(provider_.get(), reply_message_.release())
1334 .SendSuccess(return_value.get());
1339 AutomationProviderDownloadModelChangedObserver::
1340 AutomationProviderDownloadModelChangedObserver(
1341 AutomationProvider* provider,
1342 IPC::Message* reply_message,
1343 DownloadManager* download_manager)
1344 : provider_(provider->AsWeakPtr()),
1345 reply_message_(reply_message),
1346 notifier_(download_manager, this) {
1349 AutomationProviderDownloadModelChangedObserver::
1350 ~AutomationProviderDownloadModelChangedObserver() {}
1352 void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
1353 if (provider_.get())
1354 AutomationJSONReply(provider_.get(), reply_message_.release())
1359 void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated(
1360 DownloadManager* manager, DownloadItem* item) {
1364 void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved(
1365 DownloadManager* manager, DownloadItem* item) {
1369 AllDownloadsCompleteObserver::AllDownloadsCompleteObserver(
1370 AutomationProvider* provider,
1371 IPC::Message* reply_message,
1372 DownloadManager* download_manager,
1373 ListValue* pre_download_ids)
1374 : provider_(provider->AsWeakPtr()),
1375 reply_message_(reply_message),
1376 download_manager_(download_manager) {
1377 for (ListValue::iterator it = pre_download_ids->begin();
1378 it != pre_download_ids->end(); ++it) {
1380 if ((*it)->GetAsInteger(&val)) {
1381 pre_download_ids_.insert(val);
1383 AutomationJSONReply(provider_.get(), reply_message_.release())
1384 .SendError("Cannot convert ID of prior download to integer.");
1389 download_manager_->AddObserver(this);
1390 DownloadManager::DownloadVector all_items;
1391 download_manager->GetAllDownloads(&all_items);
1392 for (DownloadManager::DownloadVector::const_iterator
1393 it = all_items.begin(); it != all_items.end(); ++it) {
1394 OnDownloadCreated(download_manager_, *it);
1399 AllDownloadsCompleteObserver::~AllDownloadsCompleteObserver() {
1400 if (download_manager_) {
1401 download_manager_->RemoveObserver(this);
1402 download_manager_ = NULL;
1404 for (std::set<DownloadItem*>::const_iterator it = pending_downloads_.begin();
1405 it != pending_downloads_.end(); ++it) {
1406 (*it)->RemoveObserver(this);
1408 pending_downloads_.clear();
1411 void AllDownloadsCompleteObserver::ManagerGoingDown(DownloadManager* manager) {
1412 DCHECK_EQ(manager, download_manager_);
1413 download_manager_->RemoveObserver(this);
1414 download_manager_ = NULL;
1417 void AllDownloadsCompleteObserver::OnDownloadCreated(
1418 DownloadManager* manager, DownloadItem* item) {
1419 // This method is also called in the c-tor for previously existing items.
1420 if (pre_download_ids_.find(item->GetId()) == pre_download_ids_.end() &&
1421 item->GetState() == DownloadItem::IN_PROGRESS) {
1422 item->AddObserver(this);
1423 pending_downloads_.insert(item);
1427 void AllDownloadsCompleteObserver::OnDownloadUpdated(DownloadItem* download) {
1428 // If the current download's status has changed to a final state (not state
1429 // "in progress"), remove it from the pending list.
1430 if (download->GetState() != DownloadItem::IN_PROGRESS) {
1431 download->RemoveObserver(this);
1432 pending_downloads_.erase(download);
1437 void AllDownloadsCompleteObserver::ReplyIfNecessary() {
1438 if (!pending_downloads_.empty())
1441 download_manager_->RemoveObserver(this);
1442 if (provider_.get())
1443 AutomationJSONReply(provider_.get(), reply_message_.release())
1448 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver(
1449 AutomationProvider* provider,
1451 IPC::Message* reply_message)
1452 : provider_(provider->AsWeakPtr()),
1454 reply_message_(reply_message) {
1457 AutomationProviderSearchEngineObserver::
1458 ~AutomationProviderSearchEngineObserver() {}
1460 void AutomationProviderSearchEngineObserver::OnTemplateURLServiceChanged() {
1461 if (provider_.get()) {
1462 TemplateURLService* url_service =
1463 TemplateURLServiceFactory::GetForProfile(profile_);
1464 url_service->RemoveObserver(this);
1465 AutomationJSONReply(provider_.get(), reply_message_.release())
1471 AutomationProviderHistoryObserver::AutomationProviderHistoryObserver(
1472 AutomationProvider* provider,
1473 IPC::Message* reply_message)
1474 : provider_(provider->AsWeakPtr()),
1475 reply_message_(reply_message) {
1478 AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {}
1480 void AutomationProviderHistoryObserver::HistoryQueryComplete(
1481 HistoryService::Handle request_handle,
1482 history::QueryResults* results) {
1483 if (!provider_.get()) {
1488 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1490 ListValue* history_list = new ListValue;
1491 for (size_t i = 0; i < results->size(); ++i) {
1492 DictionaryValue* page_value = new DictionaryValue;
1493 history::URLResult const &page = (*results)[i];
1494 page_value->SetString("title", page.title());
1495 page_value->SetString("url", page.url().spec());
1496 page_value->SetDouble("time",
1497 static_cast<double>(page.visit_time().ToDoubleT()));
1498 page_value->SetString("snippet", page.snippet().text());
1499 page_value->SetBoolean(
1501 BookmarkModelFactory::GetForProfile(
1502 provider_->profile())->IsBookmarked(page.url()));
1503 history_list->Append(page_value);
1506 return_value->Set("history", history_list);
1507 // Return history info.
1508 AutomationJSONReply reply(provider_.get(), reply_message_.release());
1509 reply.SendSuccess(return_value.get());
1513 AutomationProviderImportSettingsObserver::
1514 AutomationProviderImportSettingsObserver(
1515 AutomationProvider* provider,
1516 IPC::Message* reply_message)
1517 : provider_(provider->AsWeakPtr()),
1518 reply_message_(reply_message) {
1521 AutomationProviderImportSettingsObserver::
1522 ~AutomationProviderImportSettingsObserver() {}
1524 void AutomationProviderImportSettingsObserver::ImportStarted() {
1527 void AutomationProviderImportSettingsObserver::ImportItemStarted(
1528 importer::ImportItem item) {
1531 void AutomationProviderImportSettingsObserver::ImportItemEnded(
1532 importer::ImportItem item) {
1535 void AutomationProviderImportSettingsObserver::ImportEnded() {
1536 if (provider_.get())
1537 AutomationJSONReply(provider_.get(), reply_message_.release())
1542 AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver(
1543 AutomationProvider* provider,
1544 IPC::Message* reply_message)
1545 : provider_(provider->AsWeakPtr()),
1546 reply_message_(reply_message) {
1549 AutomationProviderGetPasswordsObserver::
1550 ~AutomationProviderGetPasswordsObserver() {}
1552 void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone(
1553 CancelableRequestProvider::Handle handle,
1554 const std::vector<autofill::PasswordForm*>& result) {
1555 if (!provider_.get()) {
1560 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1562 ListValue* passwords = new ListValue;
1563 for (std::vector<autofill::PasswordForm*>::const_iterator it =
1564 result.begin(); it != result.end(); ++it) {
1565 DictionaryValue* password_val = new DictionaryValue;
1566 autofill::PasswordForm* password_form = *it;
1567 password_val->SetString("username_value", password_form->username_value);
1568 password_val->SetString("password_value", password_form->password_value);
1569 password_val->SetString("signon_realm", password_form->signon_realm);
1570 password_val->SetDouble(
1571 "time", static_cast<double>(password_form->date_created.ToDoubleT()));
1572 password_val->SetString("origin_url", password_form->origin.spec());
1573 password_val->SetString("username_element",
1574 password_form->username_element);
1575 password_val->SetString("password_element",
1576 password_form->password_element);
1577 password_val->SetString("submit_element", password_form->submit_element);
1578 password_val->SetString("action_target", password_form->action.spec());
1579 password_val->SetBoolean("blacklist", password_form->blacklisted_by_user);
1580 passwords->Append(password_val);
1583 return_value->Set("passwords", passwords);
1584 AutomationJSONReply(provider_.get(), reply_message_.release())
1585 .SendSuccess(return_value.get());
1589 void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults(
1590 const std::vector<autofill::PasswordForm*>& results) {
1591 // TODO(kaiwang): Implement when I refactor
1592 // PasswordManager::GetAutofillableLogins.
1596 PasswordStoreLoginsChangedObserver::PasswordStoreLoginsChangedObserver(
1597 AutomationProvider* automation,
1598 IPC::Message* reply_message,
1599 PasswordStoreChange::Type expected_type,
1600 const std::string& result_key)
1601 : automation_(automation->AsWeakPtr()),
1602 reply_message_(reply_message),
1603 expected_type_(expected_type),
1604 result_key_(result_key),
1605 done_event_(false, false) {
1609 PasswordStoreLoginsChangedObserver::~PasswordStoreLoginsChangedObserver() {
1610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1613 void PasswordStoreLoginsChangedObserver::Init() {
1614 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1615 BrowserThread::PostTask(
1618 base::Bind(&PasswordStoreLoginsChangedObserver::RegisterObserversTask,
1623 void PasswordStoreLoginsChangedObserver::RegisterObserversTask() {
1624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1625 registrar_.reset(new content::NotificationRegistrar);
1626 registrar_->Add(this, chrome::NOTIFICATION_LOGINS_CHANGED,
1627 content::NotificationService::AllSources());
1628 done_event_.Signal();
1631 void PasswordStoreLoginsChangedObserver::Observe(
1633 const content::NotificationSource& source,
1634 const content::NotificationDetails& details) {
1635 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1636 DCHECK(type == chrome::NOTIFICATION_LOGINS_CHANGED);
1637 registrar_.reset(); // Must be done from the DB thread.
1638 PasswordStoreChangeList* change_details =
1639 content::Details<PasswordStoreChangeList>(details).ptr();
1640 if (change_details->size() != 1 ||
1641 change_details->front().type() != expected_type_) {
1642 // Notify the UI thread that there's an error.
1643 std::string error = "Unexpected password store login change details.";
1644 BrowserThread::PostTask(
1647 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateError, this,
1652 // Notify the UI thread that we're done listening.
1653 BrowserThread::PostTask(
1656 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateDone, this));
1659 void PasswordStoreLoginsChangedObserver::IndicateDone() {
1660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1661 if (automation_.get()) {
1662 if (result_key_.empty()) {
1663 AutomationJSONReply(automation_.get(), reply_message_.release())
1666 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1667 return_value->SetBoolean(result_key_, true);
1668 AutomationJSONReply(automation_.get(), reply_message_.release())
1669 .SendSuccess(return_value.get());
1675 void PasswordStoreLoginsChangedObserver::IndicateError(
1676 const std::string& error) {
1677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1678 if (automation_.get())
1679 AutomationJSONReply(automation_.get(), reply_message_.release())
1684 OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver(
1685 NavigationController* controller,
1686 AutomationProvider* automation,
1687 IPC::Message* reply_message)
1688 : automation_(automation->AsWeakPtr()),
1689 reply_message_(reply_message),
1690 controller_(controller) {
1691 content::Source<NavigationController> source(controller_);
1692 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1693 // Pages requiring auth don't send LOAD_STOP.
1694 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
1697 OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() {
1700 void OmniboxAcceptNotificationObserver::Observe(
1702 const content::NotificationSource& source,
1703 const content::NotificationDetails& details) {
1704 if (type == content::NOTIFICATION_LOAD_STOP ||
1705 type == chrome::NOTIFICATION_AUTH_NEEDED) {
1706 if (automation_.get()) {
1707 AutomationJSONReply(automation_.get(), reply_message_.release())
1716 SavePackageNotificationObserver::SavePackageNotificationObserver(
1717 content::DownloadManager* download_manager,
1718 AutomationProvider* automation,
1719 IPC::Message* reply_message)
1720 : download_manager_(download_manager),
1721 automation_(automation->AsWeakPtr()),
1722 reply_message_(reply_message) {
1723 download_manager_->AddObserver(this);
1726 SavePackageNotificationObserver::~SavePackageNotificationObserver() {
1727 download_manager_->RemoveObserver(this);
1730 void SavePackageNotificationObserver::OnSavePackageSuccessfullyFinished(
1731 content::DownloadManager* manager, content::DownloadItem* item) {
1732 if (automation_.get()) {
1733 AutomationJSONReply(automation_.get(), reply_message_.release())
1739 void SavePackageNotificationObserver::ManagerGoingDown(
1740 content::DownloadManager* manager) {
1746 // Returns a vector of dictionaries containing information about installed apps,
1747 // as identified from a given list of extensions. The caller takes ownership
1748 // of the created vector.
1749 std::vector<DictionaryValue*>* GetAppInfoFromExtensions(
1750 const ExtensionSet* extensions,
1751 ExtensionService* ext_service) {
1752 std::vector<DictionaryValue*>* apps_list =
1753 new std::vector<DictionaryValue*>();
1754 for (ExtensionSet::const_iterator ext = extensions->begin();
1755 ext != extensions->end(); ++ext) {
1756 // Only return information about extensions that are actually apps.
1757 if ((*ext)->is_app()) {
1758 DictionaryValue* app_info = new DictionaryValue();
1759 AppLauncherHandler::CreateAppInfo(ext->get(), ext_service, app_info);
1760 app_info->SetBoolean(
1761 "is_component_extension",
1762 (*ext)->location() == extensions::Manifest::COMPONENT);
1764 // Convert the launch_type integer into a more descriptive string.
1766 const char* kLaunchType = "launch_type";
1767 if (!app_info->GetInteger(kLaunchType, &launch_type)) {
1768 NOTREACHED() << "Can't get integer from key " << kLaunchType;
1771 if (launch_type == extensions::ExtensionPrefs::LAUNCH_PINNED) {
1772 app_info->SetString(kLaunchType, "pinned");
1773 } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_REGULAR) {
1774 app_info->SetString(kLaunchType, "regular");
1775 } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_FULLSCREEN) {
1776 app_info->SetString(kLaunchType, "fullscreen");
1777 } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_WINDOW) {
1778 app_info->SetString(kLaunchType, "window");
1780 app_info->SetString(kLaunchType, "unknown");
1783 apps_list->push_back(app_info);
1791 NTPInfoObserver::NTPInfoObserver(AutomationProvider* automation,
1792 IPC::Message* reply_message)
1793 : automation_(automation->AsWeakPtr()),
1794 reply_message_(reply_message),
1796 ntp_info_(new DictionaryValue) {
1797 top_sites_ = automation_->profile()->GetTopSites();
1799 AutomationJSONReply(automation_.get(), reply_message_.release())
1800 .SendError("Profile does not have service for querying the top sites.");
1803 TabRestoreService* service =
1804 TabRestoreServiceFactory::GetForProfile(automation_->profile());
1806 AutomationJSONReply(automation_.get(), reply_message_.release())
1807 .SendError("No TabRestoreService.");
1811 // Collect information about the apps in the new tab page.
1812 ExtensionService* ext_service = extensions::ExtensionSystem::Get(
1813 automation_->profile())->extension_service();
1815 AutomationJSONReply(automation_.get(), reply_message_.release())
1816 .SendError("No ExtensionService.");
1819 // Process enabled extensions.
1820 ListValue* apps_list = new ListValue();
1821 const ExtensionSet* extensions = ext_service->extensions();
1822 std::vector<DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions(
1823 extensions, ext_service);
1824 for (std::vector<DictionaryValue*>::const_iterator app =
1825 enabled_apps->begin(); app != enabled_apps->end(); ++app) {
1826 (*app)->SetBoolean("is_disabled", false);
1827 apps_list->Append(*app);
1829 delete enabled_apps;
1830 // Process disabled extensions.
1831 const ExtensionSet* disabled_extensions = ext_service->disabled_extensions();
1832 std::vector<DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions(
1833 disabled_extensions, ext_service);
1834 for (std::vector<DictionaryValue*>::const_iterator app =
1835 disabled_apps->begin(); app != disabled_apps->end(); ++app) {
1836 (*app)->SetBoolean("is_disabled", true);
1837 apps_list->Append(*app);
1839 delete disabled_apps;
1840 // Process terminated extensions.
1841 const ExtensionSet* terminated_extensions =
1842 ext_service->terminated_extensions();
1843 std::vector<DictionaryValue*>* terminated_apps = GetAppInfoFromExtensions(
1844 terminated_extensions, ext_service);
1845 for (std::vector<DictionaryValue*>::const_iterator app =
1846 terminated_apps->begin(); app != terminated_apps->end(); ++app) {
1847 (*app)->SetBoolean("is_disabled", true);
1848 apps_list->Append(*app);
1850 delete terminated_apps;
1851 ntp_info_->Set("apps", apps_list);
1853 // Get the info that would be displayed in the recently closed section.
1854 ListValue* recently_closed_list = new ListValue;
1855 RecentlyClosedTabsHandler::CreateRecentlyClosedValues(service->entries(),
1856 recently_closed_list);
1857 ntp_info_->Set("recently_closed", recently_closed_list);
1859 // Add default site URLs.
1860 ListValue* default_sites_list = new ListValue;
1861 history::MostVisitedURLList urls = top_sites_->GetPrepopulatePages();
1862 for (size_t i = 0; i < urls.size(); ++i) {
1863 default_sites_list->Append(Value::CreateStringValue(
1864 urls[i].url.possibly_invalid_spec()));
1866 ntp_info_->Set("default_sites", default_sites_list);
1868 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_UPDATED,
1869 content::Source<history::TopSites>(top_sites_));
1870 if (top_sites_->loaded()) {
1873 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_LOADED,
1874 content::Source<Profile>(automation_->profile()));
1878 NTPInfoObserver::~NTPInfoObserver() {}
1880 void NTPInfoObserver::Observe(int type,
1881 const content::NotificationSource& source,
1882 const content::NotificationDetails& details) {
1883 if (type == chrome::NOTIFICATION_TOP_SITES_LOADED) {
1885 } else if (type == chrome::NOTIFICATION_TOP_SITES_UPDATED) {
1886 content::Details<CancelableRequestProvider::Handle> request_details(
1888 if (request_ == *request_details.ptr()) {
1889 top_sites_->GetMostVisitedURLs(
1890 base::Bind(&NTPInfoObserver::OnTopSitesReceived,
1891 base::Unretained(this)));
1896 void NTPInfoObserver::OnTopSitesLoaded() {
1897 request_ = top_sites_->StartQueryForMostVisited();
1900 void NTPInfoObserver::OnTopSitesReceived(
1901 const history::MostVisitedURLList& visited_list) {
1902 if (!automation_.get()) {
1907 ListValue* list_value = new ListValue;
1908 for (size_t i = 0; i < visited_list.size(); ++i) {
1909 const history::MostVisitedURL& visited = visited_list[i];
1910 if (visited.url.spec().empty())
1911 break; // This is the signal that there are no more real visited sites.
1912 DictionaryValue* dict = new DictionaryValue;
1913 dict->SetString("url", visited.url.spec());
1914 dict->SetString("title", visited.title);
1915 list_value->Append(dict);
1917 ntp_info_->Set("most_visited", list_value);
1918 AutomationJSONReply(automation_.get(), reply_message_.release())
1919 .SendSuccess(ntp_info_.get());
1923 AppLaunchObserver::AppLaunchObserver(
1924 NavigationController* controller,
1925 AutomationProvider* automation,
1926 IPC::Message* reply_message,
1927 extension_misc::LaunchContainer launch_container)
1928 : controller_(controller),
1929 automation_(automation->AsWeakPtr()),
1930 reply_message_(reply_message),
1931 launch_container_(launch_container),
1932 new_window_id_(extension_misc::kUnknownWindowId) {
1933 if (launch_container_ == extension_misc::LAUNCH_TAB) {
1934 // Need to wait for the currently-active tab to reload.
1935 content::Source<NavigationController> source(controller_);
1936 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1938 // Need to wait for a new tab in a new window to load.
1939 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
1940 content::NotificationService::AllSources());
1941 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
1942 content::NotificationService::AllSources());
1946 AppLaunchObserver::~AppLaunchObserver() {}
1948 void AppLaunchObserver::Observe(int type,
1949 const content::NotificationSource& source,
1950 const content::NotificationDetails& details) {
1951 if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) {
1953 ExtensionTabUtil::GetWindowId(content::Source<Browser>(source).ptr());
1957 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
1958 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(
1959 content::Source<NavigationController>(source)->GetWebContents());
1960 if ((launch_container_ == extension_misc::LAUNCH_TAB) ||
1961 (session_tab_helper &&
1962 (session_tab_helper->window_id().id() == new_window_id_))) {
1963 if (automation_.get()) {
1964 AutomationJSONReply(automation_.get(), reply_message_.release())
1973 // Returns whether all active notifications have an associated process ID.
1974 bool AreActiveNotificationProcessesReady() {
1975 BalloonNotificationUIManager* manager =
1976 BalloonNotificationUIManager::GetInstanceForTesting();
1977 const BalloonCollection::Balloons& balloons =
1978 manager->balloon_collection()->GetActiveBalloons();
1979 BalloonCollection::Balloons::const_iterator iter;
1980 for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
1981 BalloonHost* balloon_host = (*iter)->balloon_view()->GetHost();
1982 if (balloon_host && !balloon_host->IsRenderViewReady())
1990 GetAllNotificationsObserver::GetAllNotificationsObserver(
1991 AutomationProvider* automation,
1992 IPC::Message* reply_message)
1993 : automation_(automation->AsWeakPtr()),
1994 reply_message_(reply_message) {
1995 if (AreActiveNotificationProcessesReady()) {
1998 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
1999 content::NotificationService::AllSources());
2003 GetAllNotificationsObserver::~GetAllNotificationsObserver() {}
2005 void GetAllNotificationsObserver::Observe(
2007 const content::NotificationSource& source,
2008 const content::NotificationDetails& details) {
2009 if (!automation_.get()) {
2013 if (AreActiveNotificationProcessesReady())
2017 base::DictionaryValue* GetAllNotificationsObserver::NotificationToJson(
2018 const Notification* note) {
2019 DictionaryValue* dict = new base::DictionaryValue();
2020 dict->SetString("content_url", note->content_url().spec());
2021 dict->SetString("origin_url", note->origin_url().spec());
2022 dict->SetString("display_source", note->display_source());
2023 dict->SetString("id", note->notification_id());
2027 void GetAllNotificationsObserver::SendMessage() {
2028 BalloonNotificationUIManager* manager =
2029 BalloonNotificationUIManager::GetInstanceForTesting();
2030 const BalloonCollection::Balloons& balloons =
2031 manager->balloon_collection()->GetActiveBalloons();
2032 DictionaryValue return_value;
2033 ListValue* list = new ListValue;
2034 return_value.Set("notifications", list);
2035 BalloonCollection::Balloons::const_iterator balloon_iter;
2036 for (balloon_iter = balloons.begin(); balloon_iter != balloons.end();
2038 base::DictionaryValue* note = NotificationToJson(
2039 &(*balloon_iter)->notification());
2040 BalloonHost* balloon_host = (*balloon_iter)->balloon_view()->GetHost();
2042 int pid = base::GetProcId(balloon_host->web_contents()->
2043 GetRenderViewHost()->GetProcess()->GetHandle());
2044 note->SetInteger("pid", pid);
2048 std::vector<const Notification*> queued_notes;
2049 manager->GetQueuedNotificationsForTesting(&queued_notes);
2050 std::vector<const Notification*>::const_iterator queued_iter;
2051 for (queued_iter = queued_notes.begin(); queued_iter != queued_notes.end();
2053 list->Append(NotificationToJson(*queued_iter));
2055 AutomationJSONReply(automation_.get(), reply_message_.release())
2056 .SendSuccess(&return_value);
2060 NewNotificationBalloonObserver::NewNotificationBalloonObserver(
2061 AutomationProvider* provider,
2062 IPC::Message* reply_message)
2063 : automation_(provider->AsWeakPtr()),
2064 reply_message_(reply_message) {
2065 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
2066 content::NotificationService::AllSources());
2069 NewNotificationBalloonObserver::~NewNotificationBalloonObserver() { }
2071 void NewNotificationBalloonObserver::Observe(
2073 const content::NotificationSource& source,
2074 const content::NotificationDetails& details) {
2075 if (automation_.get()) {
2076 AutomationJSONReply(automation_.get(), reply_message_.release())
2082 OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver(
2083 AutomationProvider* provider,
2084 IPC::Message* reply_message,
2086 : automation_(provider->AsWeakPtr()),
2087 reply_message_(reply_message),
2088 collection_(BalloonNotificationUIManager::GetInstanceForTesting()->
2089 balloon_collection()),
2091 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
2092 content::NotificationService::AllSources());
2093 collection_->set_on_collection_changed_callback(
2094 base::Bind(&OnNotificationBalloonCountObserver::CheckBalloonCount,
2095 base::Unretained(this)));
2096 CheckBalloonCount();
2099 OnNotificationBalloonCountObserver::~OnNotificationBalloonCountObserver() {
2102 void OnNotificationBalloonCountObserver::Observe(
2104 const content::NotificationSource& source,
2105 const content::NotificationDetails& details) {
2106 CheckBalloonCount();
2109 void OnNotificationBalloonCountObserver::CheckBalloonCount() {
2110 bool balloon_count_met = AreActiveNotificationProcessesReady() &&
2111 static_cast<int>(collection_->GetActiveBalloons().size()) == count_;
2113 if (balloon_count_met && automation_.get()) {
2114 AutomationJSONReply(automation_.get(), reply_message_.release())
2118 if (balloon_count_met || !automation_.get()) {
2119 collection_->set_on_collection_changed_callback(base::Closure());
2124 RendererProcessClosedObserver::RendererProcessClosedObserver(
2125 AutomationProvider* automation,
2126 IPC::Message* reply_message)
2127 : automation_(automation->AsWeakPtr()),
2128 reply_message_(reply_message) {
2129 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
2130 content::NotificationService::AllSources());
2133 RendererProcessClosedObserver::~RendererProcessClosedObserver() {}
2135 void RendererProcessClosedObserver::Observe(
2137 const content::NotificationSource& source,
2138 const content::NotificationDetails& details) {
2139 if (automation_.get()) {
2140 AutomationJSONReply(automation_.get(), reply_message_.release())
2146 InputEventAckNotificationObserver::InputEventAckNotificationObserver(
2147 AutomationProvider* automation,
2148 IPC::Message* reply_message,
2151 : automation_(automation->AsWeakPtr()),
2152 reply_message_(reply_message),
2153 event_type_(event_type),
2158 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
2159 content::NotificationService::AllSources());
2162 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
2163 content::NotificationService::AllSources());
2166 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {}
2168 void InputEventAckNotificationObserver::Observe(
2170 const content::NotificationSource& source,
2171 const content::NotificationDetails& details) {
2172 if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
2173 AutomationJSONReply(automation_.get(), reply_message_.release())
2179 content::Details<int> request_details(details);
2180 // If the event type matches for |count_| times, replies with a JSON message.
2181 if (event_type_ == *request_details.ptr()) {
2182 if (--count_ == 0 && automation_.get()) {
2183 AutomationJSONReply(automation_.get(), reply_message_.release())
2188 LOG(WARNING) << "Ignoring unexpected event type: "
2189 << *request_details.ptr() << " (expected: " << event_type_
2194 NewTabObserver::NewTabObserver(AutomationProvider* automation,
2195 IPC::Message* reply_message,
2196 bool use_json_interface)
2197 : automation_(automation->AsWeakPtr()),
2198 reply_message_(reply_message),
2199 use_json_interface_(use_json_interface) {
2200 // Use TAB_PARENTED to detect the new tab.
2201 registrar_.Add(this,
2202 chrome::NOTIFICATION_TAB_PARENTED,
2203 content::NotificationService::AllSources());
2206 void NewTabObserver::Observe(int type,
2207 const content::NotificationSource& source,
2208 const content::NotificationDetails& details) {
2209 DCHECK_EQ(chrome::NOTIFICATION_TAB_PARENTED, type);
2210 NavigationController* controller =
2211 &(content::Source<content::WebContents>(source).ptr()->GetController());
2212 if (automation_.get()) {
2213 // TODO(phajdan.jr): Clean up this hack. We write the correct return type
2214 // here, but don't send the message. NavigationNotificationObserver
2215 // will wait properly for the load to finish, and send the message,
2216 // but it will also append its own return value at the end of the reply.
2217 if (!use_json_interface_)
2218 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
2220 new NavigationNotificationObserver(controller,
2222 reply_message_.release(),
2225 use_json_interface_);
2230 NewTabObserver::~NewTabObserver() {
2233 WaitForProcessLauncherThreadToGoIdleObserver::
2234 WaitForProcessLauncherThreadToGoIdleObserver(
2235 AutomationProvider* automation, IPC::Message* reply_message)
2236 : automation_(automation->AsWeakPtr()),
2237 reply_message_(reply_message) {
2238 // Balanced in RunOnUIThread.
2240 BrowserThread::PostTask(
2241 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2243 &WaitForProcessLauncherThreadToGoIdleObserver::
2244 RunOnProcessLauncherThread,
2248 WaitForProcessLauncherThreadToGoIdleObserver::
2249 ~WaitForProcessLauncherThreadToGoIdleObserver() {
2252 void WaitForProcessLauncherThreadToGoIdleObserver::
2253 RunOnProcessLauncherThread() {
2254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2255 BrowserThread::PostTask(
2256 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2258 &WaitForProcessLauncherThreadToGoIdleObserver::
2259 RunOnProcessLauncherThread2,
2263 void WaitForProcessLauncherThreadToGoIdleObserver::
2264 RunOnProcessLauncherThread2() {
2265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2266 BrowserThread::PostTask(
2267 BrowserThread::UI, FROM_HERE,
2268 base::Bind(&WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread,
2272 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() {
2273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2274 if (automation_.get())
2275 automation_->Send(reply_message_.release());
2279 DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver(
2280 AutomationProvider* automation,
2281 IPC::Message* reply_message)
2282 : automation_(automation->AsWeakPtr()),
2283 reply_message_(reply_message) {
2286 content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK,
2287 content::NotificationService::AllSources());
2290 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
2291 content::NotificationService::AllSources());
2294 DragTargetDropAckNotificationObserver::
2295 ~DragTargetDropAckNotificationObserver() {}
2297 void DragTargetDropAckNotificationObserver::Observe(
2299 const content::NotificationSource& source,
2300 const content::NotificationDetails& details) {
2301 if (automation_.get()) {
2302 AutomationJSONReply(automation_.get(), reply_message_.release())
2308 ProcessInfoObserver::ProcessInfoObserver(
2309 AutomationProvider* automation,
2310 IPC::Message* reply_message)
2311 : automation_(automation->AsWeakPtr()),
2312 reply_message_(reply_message) {}
2314 ProcessInfoObserver::~ProcessInfoObserver() {}
2316 void ProcessInfoObserver::OnDetailsAvailable() {
2317 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2318 ListValue* browser_proc_list = new ListValue();
2319 const std::vector<ProcessData>& all_processes = processes();
2320 for (size_t index = 0; index < all_processes.size(); ++index) {
2321 DictionaryValue* browser_data = new DictionaryValue();
2322 browser_data->SetString("name", all_processes[index].name);
2323 browser_data->SetString("process_name", all_processes[index].process_name);
2325 ListValue* proc_list = new ListValue();
2326 for (ProcessMemoryInformationList::const_iterator iterator =
2327 all_processes[index].processes.begin();
2328 iterator != all_processes[index].processes.end(); ++iterator) {
2329 DictionaryValue* proc_data = new DictionaryValue();
2331 proc_data->SetInteger("pid", iterator->pid);
2333 // Working set (resident) memory usage, in KBytes.
2334 DictionaryValue* working_set = new DictionaryValue();
2335 working_set->SetInteger("priv", iterator->working_set.priv);
2336 working_set->SetInteger("shareable", iterator->working_set.shareable);
2337 working_set->SetInteger("shared", iterator->working_set.shared);
2338 proc_data->Set("working_set_mem", working_set);
2340 // Committed (resident + paged) memory usage, in KBytes.
2341 DictionaryValue* committed = new DictionaryValue();
2342 committed->SetInteger("priv", iterator->committed.priv);
2343 committed->SetInteger("mapped", iterator->committed.mapped);
2344 committed->SetInteger("image", iterator->committed.image);
2345 proc_data->Set("committed_mem", committed);
2347 proc_data->SetString("version", iterator->version);
2348 proc_data->SetString("product_name", iterator->product_name);
2349 proc_data->SetInteger("num_processes", iterator->num_processes);
2350 proc_data->SetBoolean("is_diagnostics", iterator->is_diagnostics);
2352 // Process type, if this is a child process of Chrome (e.g., 'plugin').
2353 std::string process_type = "Unknown";
2354 // The following condition avoids a DCHECK in debug builds when the
2355 // process type passed to |GetTypeNameInEnglish| is unknown.
2356 if (iterator->process_type != content::PROCESS_TYPE_UNKNOWN) {
2358 content::GetProcessTypeNameInEnglish(iterator->process_type);
2360 proc_data->SetString("child_process_type", process_type);
2362 // Renderer type, if this is a renderer process.
2363 std::string renderer_type = "Unknown";
2364 if (iterator->renderer_type !=
2365 ProcessMemoryInformation::RENDERER_UNKNOWN) {
2366 renderer_type = ProcessMemoryInformation::GetRendererTypeNameInEnglish(
2367 iterator->renderer_type);
2369 proc_data->SetString("renderer_type", renderer_type);
2371 // Titles associated with this process.
2372 ListValue* titles = new ListValue();
2373 for (size_t title_index = 0; title_index < iterator->titles.size();
2375 titles->Append(Value::CreateStringValue(iterator->titles[title_index]));
2376 proc_data->Set("titles", titles);
2378 proc_list->Append(proc_data);
2380 browser_data->Set("processes", proc_list);
2382 browser_proc_list->Append(browser_data);
2384 return_value->Set("browsers", browser_proc_list);
2386 if (automation_.get()) {
2387 AutomationJSONReply(automation_.get(), reply_message_.release())
2388 .SendSuccess(return_value.get());
2392 V8HeapStatsObserver::V8HeapStatsObserver(
2393 AutomationProvider* automation,
2394 IPC::Message* reply_message,
2395 base::ProcessId renderer_id)
2396 : automation_(automation->AsWeakPtr()),
2397 reply_message_(reply_message),
2398 renderer_id_(renderer_id) {
2401 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
2402 content::NotificationService::AllSources());
2405 V8HeapStatsObserver::~V8HeapStatsObserver() {}
2407 void V8HeapStatsObserver::Observe(
2409 const content::NotificationSource& source,
2410 const content::NotificationDetails& details) {
2411 DCHECK(type == chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED);
2413 base::ProcessId updated_renderer_id =
2414 *(content::Source<base::ProcessId>(source).ptr());
2415 // Only return information for the renderer ID we're interested in.
2416 if (renderer_id_ != updated_renderer_id)
2419 ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap_details =
2420 content::Details<ChromeRenderMessageFilter::V8HeapStatsDetails>(details)
2422 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2423 return_value->SetInteger("renderer_id", updated_renderer_id);
2424 return_value->SetInteger("v8_memory_allocated",
2425 v8_heap_details->v8_memory_allocated());
2426 return_value->SetInteger("v8_memory_used",
2427 v8_heap_details->v8_memory_used());
2429 if (automation_.get()) {
2430 AutomationJSONReply(automation_.get(), reply_message_.release())
2431 .SendSuccess(return_value.get());
2436 FPSObserver::FPSObserver(
2437 AutomationProvider* automation,
2438 IPC::Message* reply_message,
2439 base::ProcessId renderer_id,
2441 : automation_(automation->AsWeakPtr()),
2442 reply_message_(reply_message),
2443 renderer_id_(renderer_id),
2444 routing_id_(routing_id) {
2447 chrome::NOTIFICATION_RENDERER_FPS_COMPUTED,
2448 content::NotificationService::AllSources());
2451 FPSObserver::~FPSObserver() {}
2453 void FPSObserver::Observe(
2455 const content::NotificationSource& source,
2456 const content::NotificationDetails& details) {
2457 DCHECK(type == chrome::NOTIFICATION_RENDERER_FPS_COMPUTED);
2459 base::ProcessId updated_renderer_id =
2460 *(content::Source<base::ProcessId>(source).ptr());
2461 // Only return information for the renderer ID we're interested in.
2462 if (renderer_id_ != updated_renderer_id)
2465 ChromeRenderMessageFilter::FPSDetails* fps_details =
2466 content::Details<ChromeRenderMessageFilter::FPSDetails>(details).ptr();
2467 // Only return information for the routing id of the host render view we're
2469 if (routing_id_ != fps_details->routing_id())
2472 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2473 return_value->SetInteger("renderer_id", updated_renderer_id);
2474 return_value->SetInteger("routing_id", fps_details->routing_id());
2475 return_value->SetDouble("fps", fps_details->fps());
2476 if (automation_.get()) {
2477 AutomationJSONReply(automation_.get(), reply_message_.release())
2478 .SendSuccess(return_value.get());
2483 BrowserOpenedWithNewProfileNotificationObserver::
2484 BrowserOpenedWithNewProfileNotificationObserver(
2485 AutomationProvider* automation,
2486 IPC::Message* reply_message)
2487 : automation_(automation->AsWeakPtr()),
2488 reply_message_(reply_message),
2489 new_window_id_(extension_misc::kUnknownWindowId) {
2490 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
2491 content::NotificationService::AllBrowserContextsAndSources());
2492 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2493 content::NotificationService::AllBrowserContextsAndSources());
2494 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2495 content::NotificationService::AllBrowserContextsAndSources());
2498 BrowserOpenedWithNewProfileNotificationObserver::
2499 ~BrowserOpenedWithNewProfileNotificationObserver() {
2502 void BrowserOpenedWithNewProfileNotificationObserver::Observe(
2504 const content::NotificationSource& source,
2505 const content::NotificationDetails& details) {
2506 if (!automation_.get()) {
2511 if (type == chrome::NOTIFICATION_PROFILE_CREATED) {
2512 // As part of multi-profile creation, a new browser window will
2513 // automatically be opened.
2514 Profile* profile = content::Source<Profile>(source).ptr();
2516 AutomationJSONReply(automation_.get(), reply_message_.release())
2517 .SendError("Profile could not be created.");
2520 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2521 // Store the new browser ID and continue waiting for a new tab within it
2523 new_window_id_ = ExtensionTabUtil::GetWindowId(
2524 content::Source<Browser>(source).ptr());
2526 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
2527 // Only send the result if the loaded tab is in the new window.
2528 NavigationController* controller =
2529 content::Source<NavigationController>(source).ptr();
2530 SessionTabHelper* session_tab_helper =
2531 SessionTabHelper::FromWebContents(controller->GetWebContents());
2532 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2534 if (window_id == new_window_id_) {
2535 if (automation_.get()) {
2536 AutomationJSONReply(automation_.get(), reply_message_.release())
2544 ExtensionPopupObserver::ExtensionPopupObserver(
2545 AutomationProvider* automation,
2546 IPC::Message* reply_message,
2547 const std::string& extension_id)
2548 : automation_(automation->AsWeakPtr()),
2549 reply_message_(reply_message),
2550 extension_id_(extension_id) {
2551 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
2552 content::NotificationService::AllSources());
2555 ExtensionPopupObserver::~ExtensionPopupObserver() {
2558 void ExtensionPopupObserver::Observe(
2560 const content::NotificationSource& source,
2561 const content::NotificationDetails& details) {
2562 if (!automation_.get()) {
2567 extensions::ExtensionHost* host =
2568 content::Details<extensions::ExtensionHost>(details).ptr();
2569 if (host->extension_id() == extension_id_ &&
2570 host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) {
2571 AutomationJSONReply(automation_.get(), reply_message_.release())
2577 #if defined(OS_LINUX)
2578 WindowMaximizedObserver::WindowMaximizedObserver(
2579 AutomationProvider* automation,
2580 IPC::Message* reply_message)
2581 : automation_(automation->AsWeakPtr()),
2582 reply_message_(reply_message) {
2583 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
2584 content::NotificationService::AllSources());
2587 WindowMaximizedObserver::~WindowMaximizedObserver() {}
2589 void WindowMaximizedObserver::Observe(
2591 const content::NotificationSource& source,
2592 const content::NotificationDetails& details) {
2593 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, type);
2595 if (automation_.get()) {
2596 AutomationJSONReply(automation_.get(), reply_message_.release())
2601 #endif // defined(OS_LINUX)
2603 BrowserOpenedWithExistingProfileNotificationObserver::
2604 BrowserOpenedWithExistingProfileNotificationObserver(
2605 AutomationProvider* automation,
2606 IPC::Message* reply_message,
2608 : automation_(automation->AsWeakPtr()),
2609 reply_message_(reply_message),
2610 new_window_id_(extension_misc::kUnknownWindowId),
2611 num_loads_(num_loads) {
2612 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2613 content::NotificationService::AllBrowserContextsAndSources());
2614 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2615 content::NotificationService::AllBrowserContextsAndSources());
2618 BrowserOpenedWithExistingProfileNotificationObserver::
2619 ~BrowserOpenedWithExistingProfileNotificationObserver() {
2622 void BrowserOpenedWithExistingProfileNotificationObserver::Observe(
2624 const content::NotificationSource& source,
2625 const content::NotificationDetails& details) {
2626 if (!automation_.get()) {
2631 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2632 // Store the new browser ID and continue waiting for NOTIFICATION_LOAD_STOP.
2633 new_window_id_ = ExtensionTabUtil::GetWindowId(
2634 content::Source<Browser>(source).ptr());
2635 } else if (type == content::NOTIFICATION_LOAD_STOP) {
2636 // Only consider if the loaded tab is in the new window.
2637 NavigationController* controller =
2638 content::Source<NavigationController>(source).ptr();
2639 SessionTabHelper* session_tab_helper =
2640 SessionTabHelper::FromWebContents(controller->GetWebContents());
2641 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2643 if (window_id == new_window_id_ && --num_loads_ == 0) {
2644 if (automation_.get()) {
2645 AutomationJSONReply(automation_.get(), reply_message_.release())