Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / automation / automation_provider_observers.cc
blobbdf41a5bbfe1c35c521ce2cc2c862bd7391493e9
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"
7 #include <deque>
8 #include <string>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/file_util.h"
16 #include "base/json/json_writer.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "base/values.h"
25 #include "chrome/app/chrome_command_ids.h"
26 #include "chrome/browser/automation/automation_provider.h"
27 #include "chrome/browser/automation/automation_provider_json.h"
28 #include "chrome/browser/bookmarks/bookmark_model.h"
29 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/chrome_notification_types.h"
32 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
33 #include "chrome/browser/extensions/crx_installer.h"
34 #include "chrome/browser/extensions/extension_host.h"
35 #include "chrome/browser/extensions/extension_service.h"
36 #include "chrome/browser/extensions/extension_system.h"
37 #include "chrome/browser/extensions/extension_tab_util.h"
38 #include "chrome/browser/history/history_types.h"
39 #include "chrome/browser/history/top_sites.h"
40 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
41 #include "chrome/browser/infobars/infobar_service.h"
42 #include "chrome/browser/metrics/metric_event_duration_details.h"
43 #include "chrome/browser/notifications/balloon.h"
44 #include "chrome/browser/notifications/balloon_collection.h"
45 #include "chrome/browser/notifications/balloon_host.h"
46 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
47 #include "chrome/browser/notifications/notification.h"
48 #include "chrome/browser/password_manager/password_store_change.h"
49 #include "chrome/browser/profiles/profile.h"
50 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
51 #include "chrome/browser/search_engines/template_url_service.h"
52 #include "chrome/browser/search_engines/template_url_service_factory.h"
53 #include "chrome/browser/sessions/session_tab_helper.h"
54 #include "chrome/browser/sessions/tab_restore_service.h"
55 #include "chrome/browser/sessions/tab_restore_service_factory.h"
56 #include "chrome/browser/ui/browser.h"
57 #include "chrome/browser/ui/browser_iterator.h"
58 #include "chrome/browser/ui/browser_list.h"
59 #include "chrome/browser/ui/browser_window.h"
60 #include "chrome/browser/ui/find_bar/find_notification_details.h"
61 #include "chrome/browser/ui/host_desktop.h"
62 #include "chrome/browser/ui/login/login_prompt.h"
63 #include "chrome/browser/ui/tabs/tab_strip_model.h"
64 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
65 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
66 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
67 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
68 #include "chrome/common/automation_constants.h"
69 #include "chrome/common/automation_messages.h"
70 #include "chrome/common/content_settings_types.h"
71 #include "chrome/common/extensions/extension_constants.h"
72 #include "content/public/browser/dom_operation_notification_details.h"
73 #include "content/public/browser/navigation_controller.h"
74 #include "content/public/browser/notification_service.h"
75 #include "content/public/browser/render_process_host.h"
76 #include "content/public/browser/render_view_host.h"
77 #include "content/public/browser/web_contents.h"
78 #include "content/public/common/process_type.h"
79 #include "extensions/browser/extension_registry.h"
80 #include "extensions/browser/process_manager.h"
81 #include "extensions/common/extension.h"
82 #include "extensions/common/extension_set.h"
83 #include "extensions/common/manifest.h"
84 #include "extensions/common/view_type.h"
85 #include "ui/gfx/codec/png_codec.h"
86 #include "ui/gfx/rect.h"
87 #include "url/gurl.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 {
99 public:
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_;
112 private:
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(
142 source.map_key(),
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>(
155 details)->status;
156 switch (status) {
157 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
158 break;
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_++;
164 break;
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.";
170 break;
172 default:
173 LOG(ERROR) << "Unhandled termination status " << status;
174 NOTREACHED();
175 break;
177 } else {
178 NOTREACHED();
181 if (finished_tabs_.size() + crashed_tab_count_ >= outstanding_tab_count_)
182 ConditionMet();
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();
189 ++it) {
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());
196 } else {
197 base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
198 item->SetDouble("load_stop_ms", delta_stop.InMillisecondsF());
200 items->Append(item);
202 base::DictionaryValue* return_value = new base::DictionaryValue;
203 return_value->Set("tabs", items);
204 return return_value;
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()) {
221 SendDone();
222 } else {
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();
236 SendDone();
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())
248 .SendSuccess(NULL);
250 delete this;
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);
268 return;
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()) {
292 delete this;
293 return;
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);
323 } else {
324 NOTREACHED();
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())
336 .SendSuccess(&dict);
337 } else {
338 AutomationJSONReply(automation_.get(), reply_message_.release())
339 .SendError(base::StringPrintf(
340 "Navigation failed with error code=%d.", navigation_result));
342 } else {
343 IPC::ParamTraits<int>::Write(
344 reply_message_.get(), navigation_result);
345 automation_->Send(reply_message_.release());
349 delete this;
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(
364 int type,
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());
372 } else {
373 ObserveTab(content::Source<NavigationController>(source).ptr());
375 delete this;
378 TabAppendedNotificationObserver::TabAppendedNotificationObserver(
379 Browser* parent,
380 AutomationProvider* automation,
381 IPC::Message* reply_message,
382 bool use_json_interface)
383 : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED,
384 automation),
385 parent_(parent),
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())
395 return;
397 if (automation_->GetIndexForNavigationController(controller, parent_) ==
398 TabStripModel::kNoTab) {
399 // This tab notification doesn't belong to the parent_.
400 return;
403 new NavigationNotificationObserver(controller,
404 automation_.get(),
405 reply_message_.release(),
407 false,
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())
433 return;
435 if (use_json_interface_) {
436 AutomationJSONReply(automation_.get(), reply_message_.release())
437 .SendSuccess(NULL);
438 } else {
439 if (for_browser_command_) {
440 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
441 true);
442 } else {
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,
455 Browser* browser,
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);
463 CheckTabCount();
466 TabCountChangeObserver::~TabCountChangeObserver() {
467 tab_strip_model_->RemoveObserver(this);
470 void TabCountChangeObserver::TabInsertedAt(WebContents* contents,
471 int index,
472 bool foreground) {
473 CheckTabCount();
476 void TabCountChangeObserver::TabDetachedAt(WebContents* contents,
477 int index) {
478 CheckTabCount();
481 void TabCountChangeObserver::TabStripModelDeleted() {
482 if (automation_.get()) {
483 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
484 reply_message_.get(), false);
485 automation_->Send(reply_message_.release());
488 delete this;
491 void TabCountChangeObserver::CheckTabCount() {
492 if (tab_strip_model_->count() != target_tab_count_)
493 return;
495 if (automation_.get()) {
496 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
497 reply_message_.get(), true);
498 automation_->Send(reply_message_.release());
501 delete this;
504 bool DidExtensionViewsStopLoading(extensions::ProcessManager* manager) {
505 extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
506 for (extensions::ProcessManager::ViewSet::const_iterator iter =
507 all_views.begin();
508 iter != all_views.end(); ++iter) {
509 if ((*iter)->IsLoading())
510 return false;
512 return true;
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),
521 id_(id) {
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(
532 int type,
533 const content::NotificationSource& source,
534 const content::NotificationDetails& details) {
535 if (!automation_.get()) {
536 delete this;
537 return;
540 switch (type) {
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());
548 delete this;
549 return;
551 break;
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());
563 delete this;
564 return;
566 break;
569 default:
570 NOTREACHED();
574 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
575 extensions::ProcessManager* manager, ExtensionService* service,
576 AutomationProvider* automation, IPC::Message* reply_message)
577 : manager_(manager),
578 service_(service),
579 automation_(automation->AsWeakPtr()),
580 reply_message_(reply_message),
581 extension_(NULL) {
582 Init();
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()) {
605 delete this;
606 return;
609 switch (type) {
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.
613 if (!extension_ || !DidExtensionViewsStopLoading(manager_))
614 return;
615 break;
616 case chrome::NOTIFICATION_EXTENSION_LOADED: {
617 const extensions::Extension* loaded_extension =
618 content::Details<const extensions::Extension>(details).ptr();
619 // Only track an internal or unpacked extension load.
620 extensions::Manifest::Location location = loaded_extension->location();
621 if (location != extensions::Manifest::INTERNAL &&
622 !extensions::Manifest::IsUnpackedLocation(location))
623 return;
624 extension_ = loaded_extension;
625 if (!DidExtensionViewsStopLoading(manager_))
626 return;
627 // For some reason, the background extension view is not yet
628 // created at this point so just checking whether all extension views
629 // are loaded is not sufficient. If background page is not ready,
630 // we wait for NOTIFICATION_LOAD_STOP.
631 if (!service_->IsBackgroundPageReady(extension_))
632 return;
633 break;
635 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
636 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
637 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
638 break;
639 default:
640 NOTREACHED();
641 break;
644 AutomationJSONReply reply(automation_.get(), reply_message_.release());
645 if (extension_) {
646 base::DictionaryValue dict;
647 dict.SetString("id", extension_->id());
648 reply.SendSuccess(&dict);
649 } else {
650 reply.SendError("Extension could not be installed");
652 delete this;
655 ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
656 : did_receive_unload_notification_(false) {
657 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
658 content::NotificationService::AllSources());
661 ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
664 void ExtensionUnloadNotificationObserver::Observe(
665 int type, const content::NotificationSource& source,
666 const content::NotificationDetails& details) {
667 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
668 did_receive_unload_notification_ = true;
669 } else {
670 NOTREACHED();
674 ExtensionsUpdatedObserver::ExtensionsUpdatedObserver(
675 extensions::ProcessManager* manager, AutomationProvider* automation,
676 IPC::Message* reply_message)
677 : manager_(manager), automation_(automation->AsWeakPtr()),
678 reply_message_(reply_message), updater_finished_(false) {
679 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
680 content::NotificationService::AllSources());
683 ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() {
686 void ExtensionsUpdatedObserver::Observe(
687 int type, const content::NotificationSource& source,
688 const content::NotificationDetails& details) {
689 if (!automation_.get()) {
690 delete this;
691 return;
694 DCHECK(type == content::NOTIFICATION_LOAD_STOP);
695 MaybeReply();
698 void ExtensionsUpdatedObserver::UpdateCheckFinished() {
699 if (!automation_.get()) {
700 delete this;
701 return;
704 // Extension updater has completed updating all extensions.
705 updater_finished_ = true;
706 MaybeReply();
709 void ExtensionsUpdatedObserver::MaybeReply() {
710 // Send the reply if (1) the extension updater has finished updating all
711 // extensions; and (2) all extension views have stopped loading.
712 if (updater_finished_ && DidExtensionViewsStopLoading(manager_)) {
713 AutomationJSONReply reply(automation_.get(), reply_message_.release());
714 reply.SendSuccess(NULL);
715 delete this;
719 BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver(
720 AutomationProvider* automation,
721 IPC::Message* reply_message,
722 bool use_json_interface)
723 : automation_(automation->AsWeakPtr()),
724 reply_message_(reply_message),
725 new_window_id_(extension_misc::kUnknownWindowId),
726 use_json_interface_(use_json_interface),
727 for_browser_command_(false) {
728 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
729 content::NotificationService::AllBrowserContextsAndSources());
730 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
731 content::NotificationService::AllBrowserContextsAndSources());
734 BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() {
737 void BrowserOpenedNotificationObserver::Observe(
738 int type,
739 const content::NotificationSource& source,
740 const content::NotificationDetails& details) {
741 if (!automation_.get()) {
742 delete this;
743 return;
746 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
747 // Store the new browser ID and continue waiting for a new tab within it
748 // to stop loading.
749 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
750 content::Source<Browser>(source).ptr());
751 } else {
752 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
753 // Only send the result if the loaded tab is in the new window.
754 NavigationController* controller =
755 content::Source<NavigationController>(source).ptr();
756 SessionTabHelper* session_tab_helper =
757 SessionTabHelper::FromWebContents(controller->GetWebContents());
758 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
759 : -1;
760 if (window_id == new_window_id_) {
761 if (use_json_interface_) {
762 AutomationJSONReply(automation_.get(), reply_message_.release())
763 .SendSuccess(NULL);
764 } else {
765 if (for_browser_command_) {
766 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
767 reply_message_.get(), true);
769 automation_->Send(reply_message_.release());
771 delete this;
772 return;
777 void BrowserOpenedNotificationObserver::set_for_browser_command(
778 bool for_browser_command) {
779 for_browser_command_ = for_browser_command;
782 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
783 Browser* browser,
784 AutomationProvider* automation,
785 IPC::Message* reply_message,
786 bool use_json_interface)
787 : automation_(automation->AsWeakPtr()),
788 reply_message_(reply_message),
789 use_json_interface_(use_json_interface),
790 for_browser_command_(false) {
791 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
792 content::Source<Browser>(browser));
795 BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {}
797 void BrowserClosedNotificationObserver::Observe(
798 int type, const content::NotificationSource& source,
799 const content::NotificationDetails& details) {
800 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSED, type);
802 if (!automation_.get()) {
803 delete this;
804 return;
807 // The automation layer doesn't support non-native desktops.
808 int browser_count = static_cast<int>(BrowserList::GetInstance(
809 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
810 // We get the notification before the browser is removed from the BrowserList.
811 bool app_closing = browser_count == 1;
813 if (use_json_interface_) {
814 AutomationJSONReply(automation_.get(), reply_message_.release())
815 .SendSuccess(NULL);
816 } else {
817 if (for_browser_command_) {
818 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
819 true);
820 } else {
821 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true,
822 app_closing);
824 automation_->Send(reply_message_.release());
826 delete this;
829 void BrowserClosedNotificationObserver::set_for_browser_command(
830 bool for_browser_command) {
831 for_browser_command_ = for_browser_command;
834 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
835 int target_count,
836 AutomationProvider* automation,
837 IPC::Message* reply_message)
838 : target_count_(target_count),
839 automation_(automation->AsWeakPtr()),
840 reply_message_(reply_message) {
841 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
842 content::NotificationService::AllBrowserContextsAndSources());
843 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
844 content::NotificationService::AllBrowserContextsAndSources());
847 BrowserCountChangeNotificationObserver::
848 ~BrowserCountChangeNotificationObserver() {}
850 void BrowserCountChangeNotificationObserver::Observe(
851 int type,
852 const content::NotificationSource& source,
853 const content::NotificationDetails& details) {
854 DCHECK(type == chrome::NOTIFICATION_BROWSER_OPENED ||
855 type == chrome::NOTIFICATION_BROWSER_CLOSED);
857 // The automation layer doesn't support non-native desktops.
858 int current_count = static_cast<int>(BrowserList::GetInstance(
859 chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
860 if (type == chrome::NOTIFICATION_BROWSER_CLOSED) {
861 // At the time of the notification the browser being closed is not removed
862 // from the list. The real count is one less than the reported count.
863 DCHECK_LT(0, current_count);
864 current_count--;
867 if (!automation_.get()) {
868 delete this;
869 return;
872 if (current_count == target_count_) {
873 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
874 reply_message_.get(), true);
875 automation_->Send(reply_message_.release());
876 delete this;
880 namespace {
882 // Define mapping from command to notification
883 struct CommandNotification {
884 int command;
885 int notification_type;
888 const struct CommandNotification command_notifications[] = {
889 {IDC_DUPLICATE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
891 // Returns as soon as the restored tab is created. To further wait until
892 // the content page is loaded, use WaitForTabToBeRestored.
893 {IDC_RESTORE_TAB, chrome::NOTIFICATION_TAB_PARENTED},
895 // For the following commands, we need to wait for a new tab to be created,
896 // load to finish, and title to change.
897 {IDC_MANAGE_EXTENSIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
898 {IDC_OPTIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
899 {IDC_PRINT, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
900 {IDC_SHOW_DOWNLOADS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
901 {IDC_SHOW_HISTORY, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED},
904 } // namespace
906 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
909 // static
910 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
911 AutomationProvider* automation,
912 Browser* browser,
913 int command,
914 IPC::Message* reply_message,
915 bool use_json_interface) {
916 bool result = true;
917 switch (command) {
918 case IDC_NEW_TAB: {
919 new NewTabObserver(automation, reply_message, use_json_interface);
920 break;
922 case IDC_NEW_WINDOW:
923 case IDC_NEW_INCOGNITO_WINDOW: {
924 BrowserOpenedNotificationObserver* observer =
925 new BrowserOpenedNotificationObserver(automation, reply_message,
926 use_json_interface);
927 observer->set_for_browser_command(true);
928 break;
930 case IDC_CLOSE_WINDOW: {
931 BrowserClosedNotificationObserver* observer =
932 new BrowserClosedNotificationObserver(browser, automation,
933 reply_message,
934 use_json_interface);
935 observer->set_for_browser_command(true);
936 break;
938 case IDC_CLOSE_TAB: {
939 TabClosedNotificationObserver* observer =
940 new TabClosedNotificationObserver(automation, true, reply_message,
941 use_json_interface);
942 observer->set_for_browser_command(true);
943 break;
945 case IDC_BACK:
946 case IDC_FORWARD:
947 case IDC_RELOAD: {
948 new NavigationNotificationObserver(
949 &browser->tab_strip_model()->GetActiveWebContents()->GetController(),
950 automation, reply_message, 1, false, use_json_interface);
951 break;
953 default: {
954 ExecuteBrowserCommandObserver* observer =
955 new ExecuteBrowserCommandObserver(automation, reply_message,
956 use_json_interface);
957 if (!observer->Register(command)) {
958 observer->ReleaseReply();
959 delete observer;
960 result = false;
962 break;
965 return result;
968 void ExecuteBrowserCommandObserver::Observe(
969 int type, const content::NotificationSource& source,
970 const content::NotificationDetails& details) {
971 if (type == notification_type_) {
972 if (automation_.get()) {
973 if (use_json_interface_) {
974 AutomationJSONReply(automation_.get(), reply_message_.release())
975 .SendSuccess(NULL);
976 } else {
977 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
978 reply_message_.get(), true);
979 automation_->Send(reply_message_.release());
982 delete this;
983 } else {
984 NOTREACHED();
988 ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
989 AutomationProvider* automation,
990 IPC::Message* reply_message,
991 bool use_json_interface)
992 : automation_(automation->AsWeakPtr()),
993 notification_type_(content::NOTIFICATION_ALL),
994 reply_message_(reply_message),
995 use_json_interface_(use_json_interface) {
998 bool ExecuteBrowserCommandObserver::Register(int command) {
999 if (!Getint(command, &notification_type_))
1000 return false;
1001 registrar_.Add(this, notification_type_,
1002 content::NotificationService::AllSources());
1003 return true;
1006 bool ExecuteBrowserCommandObserver::Getint(
1007 int command, int* type) {
1008 if (!type)
1009 return false;
1010 bool found = false;
1011 for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
1012 if (command_notifications[i].command == command) {
1013 *type = command_notifications[i].notification_type;
1014 found = true;
1015 break;
1018 return found;
1021 IPC::Message* ExecuteBrowserCommandObserver::ReleaseReply() {
1022 return reply_message_.release();
1025 FindInPageNotificationObserver::FindInPageNotificationObserver(
1026 AutomationProvider* automation, WebContents* parent_tab,
1027 bool reply_with_json, IPC::Message* reply_message)
1028 : automation_(automation->AsWeakPtr()),
1029 active_match_ordinal_(-1),
1030 reply_with_json_(reply_with_json),
1031 reply_message_(reply_message) {
1032 registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
1033 content::Source<WebContents>(parent_tab));
1036 FindInPageNotificationObserver::~FindInPageNotificationObserver() {
1039 void FindInPageNotificationObserver::Observe(
1040 int type, const content::NotificationSource& source,
1041 const content::NotificationDetails& details) {
1042 content::Details<FindNotificationDetails> find_details(details);
1043 if (!(find_details->final_update() && reply_message_ != NULL)) {
1044 DVLOG(1) << "Ignoring, since we only care about the final message";
1045 return;
1048 if (!automation_.get()) {
1049 delete this;
1050 return;
1053 // We get multiple responses and one of those will contain the ordinal.
1054 // This message comes to us before the final update is sent.
1055 if (find_details->request_id() == kFindInPageRequestId) {
1056 if (reply_with_json_) {
1057 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1058 return_value->SetInteger("match_count",
1059 find_details->number_of_matches());
1060 gfx::Rect rect = find_details->selection_rect();
1061 // If MatchCount is > 0, then rect should not be Empty.
1062 // We dont guard it here because we want to let the test
1063 // code catch this invalid case if needed.
1064 if (!rect.IsEmpty()) {
1065 return_value->SetInteger("match_left", rect.x());
1066 return_value->SetInteger("match_top", rect.y());
1067 return_value->SetInteger("match_right", rect.right());
1068 return_value->SetInteger("match_bottom", rect.bottom());
1070 AutomationJSONReply(automation_.get(), reply_message_.release())
1071 .SendSuccess(return_value.get());
1072 delete this;
1073 } else {
1074 if (find_details->active_match_ordinal() > -1) {
1075 active_match_ordinal_ = find_details->active_match_ordinal();
1076 AutomationMsg_Find::WriteReplyParams(reply_message_.get(),
1077 active_match_ordinal_, find_details->number_of_matches());
1078 automation_->Send(reply_message_.release());
1084 // static
1085 const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
1087 DomOperationObserver::DomOperationObserver(int automation_id)
1088 : automation_id_(automation_id) {
1089 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
1090 content::NotificationService::AllSources());
1091 registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
1092 content::NotificationService::AllSources());
1093 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1094 content::NotificationService::AllSources());
1097 DomOperationObserver::~DomOperationObserver() {}
1099 void DomOperationObserver::Observe(
1100 int type, const content::NotificationSource& source,
1101 const content::NotificationDetails& details) {
1102 if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) {
1103 content::Details<DomOperationNotificationDetails> dom_op_details(details);
1104 if (dom_op_details->automation_id == automation_id_)
1105 OnDomOperationCompleted(dom_op_details->json);
1106 } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
1107 OnJavascriptBlocked();
1108 } else {
1109 DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type);
1110 WebContents* web_contents = content::Source<WebContents>(source).ptr();
1111 if (web_contents) {
1112 TabSpecificContentSettings* tab_content_settings =
1113 TabSpecificContentSettings::FromWebContents(web_contents);
1114 if (tab_content_settings &&
1115 tab_content_settings->IsContentBlocked(
1116 CONTENT_SETTINGS_TYPE_JAVASCRIPT))
1117 OnJavascriptBlocked();
1122 DomOperationMessageSender::DomOperationMessageSender(
1123 AutomationProvider* automation,
1124 IPC::Message* reply_message,
1125 bool use_json_interface)
1126 : DomOperationObserver(0),
1127 automation_(automation->AsWeakPtr()),
1128 reply_message_(reply_message),
1129 use_json_interface_(use_json_interface) {
1132 DomOperationMessageSender::~DomOperationMessageSender() {}
1134 void DomOperationMessageSender::OnDomOperationCompleted(
1135 const std::string& json) {
1136 if (automation_.get()) {
1137 if (use_json_interface_) {
1138 base::DictionaryValue dict;
1139 dict.SetString("result", json);
1140 AutomationJSONReply(automation_.get(), reply_message_.release())
1141 .SendSuccess(&dict);
1142 } else {
1143 AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json);
1144 automation_->Send(reply_message_.release());
1147 delete this;
1150 void DomOperationMessageSender::OnJavascriptBlocked() {
1151 if (automation_.get() && use_json_interface_) {
1152 AutomationJSONReply(automation_.get(), reply_message_.release())
1153 .SendError("Javascript execution was blocked");
1154 delete this;
1158 MetricEventDurationObserver::MetricEventDurationObserver() {
1159 registrar_.Add(this, chrome::NOTIFICATION_METRIC_EVENT_DURATION,
1160 content::NotificationService::AllSources());
1163 MetricEventDurationObserver::~MetricEventDurationObserver() {}
1165 int MetricEventDurationObserver::GetEventDurationMs(
1166 const std::string& event_name) {
1167 EventDurationMap::const_iterator it = durations_.find(event_name);
1168 if (it == durations_.end())
1169 return -1;
1170 return it->second;
1173 void MetricEventDurationObserver::Observe(
1174 int type,
1175 const content::NotificationSource& source,
1176 const content::NotificationDetails& details) {
1177 if (type != chrome::NOTIFICATION_METRIC_EVENT_DURATION) {
1178 NOTREACHED();
1179 return;
1181 MetricEventDurationDetails* metric_event_duration =
1182 content::Details<MetricEventDurationDetails>(details).ptr();
1183 durations_[metric_event_duration->event_name] =
1184 metric_event_duration->duration_ms;
1187 InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
1188 IPC::Message* reply_message,
1189 WebContents* web_contents,
1190 size_t target_count)
1191 : automation_(automation->AsWeakPtr()),
1192 reply_message_(reply_message),
1193 web_contents_(web_contents),
1194 target_count_(target_count) {
1195 content::Source<InfoBarService> source(
1196 InfoBarService::FromWebContents(web_contents));
1197 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
1198 source);
1199 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
1200 source);
1201 CheckCount();
1204 InfoBarCountObserver::~InfoBarCountObserver() {}
1206 void InfoBarCountObserver::Observe(
1207 int type,
1208 const content::NotificationSource& source,
1209 const content::NotificationDetails& details) {
1210 DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED ||
1211 type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
1212 CheckCount();
1215 void InfoBarCountObserver::CheckCount() {
1216 if (InfoBarService::FromWebContents(web_contents_)->infobar_count() !=
1217 target_count_)
1218 return;
1220 if (automation_.get()) {
1221 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(),
1222 true);
1223 automation_->Send(reply_message_.release());
1225 delete this;
1228 AutomationProviderBookmarkModelObserver::
1229 AutomationProviderBookmarkModelObserver(
1230 AutomationProvider* provider,
1231 IPC::Message* reply_message,
1232 BookmarkModel* model,
1233 bool use_json_interface)
1234 : automation_provider_(provider->AsWeakPtr()),
1235 reply_message_(reply_message),
1236 model_(model),
1237 use_json_interface_(use_json_interface) {
1238 model_->AddObserver(this);
1241 AutomationProviderBookmarkModelObserver::
1242 ~AutomationProviderBookmarkModelObserver() {
1243 model_->RemoveObserver(this);
1246 void AutomationProviderBookmarkModelObserver::BookmarkModelLoaded(
1247 BookmarkModel* model,
1248 bool ids_reassigned) {
1249 ReplyAndDelete(true);
1252 void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted(
1253 BookmarkModel* model) {
1254 ReplyAndDelete(false);
1257 IPC::Message* AutomationProviderBookmarkModelObserver::ReleaseReply() {
1258 return reply_message_.release();
1261 void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
1262 if (automation_provider_.get()) {
1263 if (use_json_interface_) {
1264 AutomationJSONReply(automation_provider_.get(), reply_message_.release())
1265 .SendSuccess(NULL);
1266 } else {
1267 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1268 reply_message_.get(), success);
1269 automation_provider_->Send(reply_message_.release());
1272 delete this;
1275 AutomationProviderDownloadUpdatedObserver::
1276 AutomationProviderDownloadUpdatedObserver(
1277 AutomationProvider* provider,
1278 IPC::Message* reply_message,
1279 bool wait_for_open,
1280 bool incognito)
1281 : provider_(provider->AsWeakPtr()),
1282 reply_message_(reply_message),
1283 wait_for_open_(wait_for_open),
1284 incognito_(incognito) {
1287 AutomationProviderDownloadUpdatedObserver::
1288 ~AutomationProviderDownloadUpdatedObserver() {}
1290 void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
1291 DownloadItem* download) {
1292 // If this observer is watching for open, only send the reply if the download
1293 // has been auto-opened.
1294 if (wait_for_open_ && !download->GetAutoOpened())
1295 return;
1297 download->RemoveObserver(this);
1299 if (provider_.get()) {
1300 scoped_ptr<base::DictionaryValue> return_value(
1301 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1302 AutomationJSONReply(provider_.get(), reply_message_.release())
1303 .SendSuccess(return_value.get());
1305 delete this;
1308 void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
1309 DownloadItem* download) {
1310 download->RemoveObserver(this);
1312 if (provider_.get()) {
1313 scoped_ptr<base::DictionaryValue> return_value(
1314 provider_->GetDictionaryFromDownloadItem(download, incognito_));
1315 AutomationJSONReply(provider_.get(), reply_message_.release())
1316 .SendSuccess(return_value.get());
1318 delete this;
1321 AutomationProviderDownloadModelChangedObserver::
1322 AutomationProviderDownloadModelChangedObserver(
1323 AutomationProvider* provider,
1324 IPC::Message* reply_message,
1325 DownloadManager* download_manager)
1326 : provider_(provider->AsWeakPtr()),
1327 reply_message_(reply_message),
1328 notifier_(download_manager, this) {
1331 AutomationProviderDownloadModelChangedObserver::
1332 ~AutomationProviderDownloadModelChangedObserver() {}
1334 void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
1335 if (provider_.get())
1336 AutomationJSONReply(provider_.get(), reply_message_.release())
1337 .SendSuccess(NULL);
1338 delete this;
1341 void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated(
1342 DownloadManager* manager, DownloadItem* item) {
1343 ModelChanged();
1346 void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved(
1347 DownloadManager* manager, DownloadItem* item) {
1348 ModelChanged();
1351 AllDownloadsCompleteObserver::AllDownloadsCompleteObserver(
1352 AutomationProvider* provider,
1353 IPC::Message* reply_message,
1354 DownloadManager* download_manager,
1355 base::ListValue* pre_download_ids)
1356 : provider_(provider->AsWeakPtr()),
1357 reply_message_(reply_message),
1358 download_manager_(download_manager) {
1359 for (base::ListValue::iterator it = pre_download_ids->begin();
1360 it != pre_download_ids->end(); ++it) {
1361 int val = 0;
1362 if ((*it)->GetAsInteger(&val)) {
1363 pre_download_ids_.insert(val);
1364 } else {
1365 AutomationJSONReply(provider_.get(), reply_message_.release())
1366 .SendError("Cannot convert ID of prior download to integer.");
1367 delete this;
1368 return;
1371 download_manager_->AddObserver(this);
1372 DownloadManager::DownloadVector all_items;
1373 download_manager->GetAllDownloads(&all_items);
1374 for (DownloadManager::DownloadVector::const_iterator
1375 it = all_items.begin(); it != all_items.end(); ++it) {
1376 OnDownloadCreated(download_manager_, *it);
1378 ReplyIfNecessary();
1381 AllDownloadsCompleteObserver::~AllDownloadsCompleteObserver() {
1382 if (download_manager_) {
1383 download_manager_->RemoveObserver(this);
1384 download_manager_ = NULL;
1386 for (std::set<DownloadItem*>::const_iterator it = pending_downloads_.begin();
1387 it != pending_downloads_.end(); ++it) {
1388 (*it)->RemoveObserver(this);
1390 pending_downloads_.clear();
1393 void AllDownloadsCompleteObserver::ManagerGoingDown(DownloadManager* manager) {
1394 DCHECK_EQ(manager, download_manager_);
1395 download_manager_->RemoveObserver(this);
1396 download_manager_ = NULL;
1399 void AllDownloadsCompleteObserver::OnDownloadCreated(
1400 DownloadManager* manager, DownloadItem* item) {
1401 // This method is also called in the c-tor for previously existing items.
1402 if (pre_download_ids_.find(item->GetId()) == pre_download_ids_.end() &&
1403 item->GetState() == DownloadItem::IN_PROGRESS) {
1404 item->AddObserver(this);
1405 pending_downloads_.insert(item);
1409 void AllDownloadsCompleteObserver::OnDownloadUpdated(DownloadItem* download) {
1410 // If the current download's status has changed to a final state (not state
1411 // "in progress"), remove it from the pending list.
1412 if (download->GetState() != DownloadItem::IN_PROGRESS) {
1413 download->RemoveObserver(this);
1414 pending_downloads_.erase(download);
1415 ReplyIfNecessary();
1419 void AllDownloadsCompleteObserver::ReplyIfNecessary() {
1420 if (!pending_downloads_.empty())
1421 return;
1423 download_manager_->RemoveObserver(this);
1424 if (provider_.get())
1425 AutomationJSONReply(provider_.get(), reply_message_.release())
1426 .SendSuccess(NULL);
1427 delete this;
1430 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver(
1431 AutomationProvider* provider,
1432 Profile* profile,
1433 IPC::Message* reply_message)
1434 : provider_(provider->AsWeakPtr()),
1435 profile_(profile),
1436 reply_message_(reply_message) {
1439 AutomationProviderSearchEngineObserver::
1440 ~AutomationProviderSearchEngineObserver() {}
1442 void AutomationProviderSearchEngineObserver::OnTemplateURLServiceChanged() {
1443 if (provider_.get()) {
1444 TemplateURLService* url_service =
1445 TemplateURLServiceFactory::GetForProfile(profile_);
1446 url_service->RemoveObserver(this);
1447 AutomationJSONReply(provider_.get(), reply_message_.release())
1448 .SendSuccess(NULL);
1450 delete this;
1453 AutomationProviderHistoryObserver::AutomationProviderHistoryObserver(
1454 AutomationProvider* provider,
1455 IPC::Message* reply_message)
1456 : provider_(provider->AsWeakPtr()),
1457 reply_message_(reply_message) {
1460 AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {}
1462 void AutomationProviderHistoryObserver::HistoryQueryComplete(
1463 HistoryService::Handle request_handle,
1464 history::QueryResults* results) {
1465 if (!provider_.get()) {
1466 delete this;
1467 return;
1470 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1472 base::ListValue* history_list = new base::ListValue;
1473 for (size_t i = 0; i < results->size(); ++i) {
1474 base::DictionaryValue* page_value = new base::DictionaryValue;
1475 history::URLResult const &page = (*results)[i];
1476 page_value->SetString("title", page.title());
1477 page_value->SetString("url", page.url().spec());
1478 page_value->SetDouble("time",
1479 static_cast<double>(page.visit_time().ToDoubleT()));
1480 page_value->SetString("snippet", page.snippet().text());
1481 page_value->SetBoolean(
1482 "starred",
1483 BookmarkModelFactory::GetForProfile(
1484 provider_->profile())->IsBookmarked(page.url()));
1485 history_list->Append(page_value);
1488 return_value->Set("history", history_list);
1489 // Return history info.
1490 AutomationJSONReply reply(provider_.get(), reply_message_.release());
1491 reply.SendSuccess(return_value.get());
1492 delete this;
1495 AutomationProviderImportSettingsObserver::
1496 AutomationProviderImportSettingsObserver(
1497 AutomationProvider* provider,
1498 IPC::Message* reply_message)
1499 : provider_(provider->AsWeakPtr()),
1500 reply_message_(reply_message) {
1503 AutomationProviderImportSettingsObserver::
1504 ~AutomationProviderImportSettingsObserver() {}
1506 void AutomationProviderImportSettingsObserver::ImportStarted() {
1509 void AutomationProviderImportSettingsObserver::ImportItemStarted(
1510 importer::ImportItem item) {
1513 void AutomationProviderImportSettingsObserver::ImportItemEnded(
1514 importer::ImportItem item) {
1517 void AutomationProviderImportSettingsObserver::ImportEnded() {
1518 if (provider_.get())
1519 AutomationJSONReply(provider_.get(), reply_message_.release())
1520 .SendSuccess(NULL);
1521 delete this;
1524 AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver(
1525 AutomationProvider* provider,
1526 IPC::Message* reply_message)
1527 : provider_(provider->AsWeakPtr()),
1528 reply_message_(reply_message) {
1531 AutomationProviderGetPasswordsObserver::
1532 ~AutomationProviderGetPasswordsObserver() {}
1534 void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone(
1535 CancelableRequestProvider::Handle handle,
1536 const std::vector<autofill::PasswordForm*>& result) {
1537 if (!provider_.get()) {
1538 delete this;
1539 return;
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 result.begin(); it != result.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());
1568 delete this;
1571 void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults(
1572 const std::vector<autofill::PasswordForm*>& results) {
1573 // TODO(kaiwang): Implement when I refactor
1574 // PasswordManager::GetAutofillableLogins.
1575 NOTIMPLEMENTED();
1578 PasswordStoreLoginsChangedObserver::PasswordStoreLoginsChangedObserver(
1579 AutomationProvider* automation,
1580 IPC::Message* reply_message,
1581 PasswordStoreChange::Type expected_type,
1582 const std::string& result_key)
1583 : automation_(automation->AsWeakPtr()),
1584 reply_message_(reply_message),
1585 expected_type_(expected_type),
1586 result_key_(result_key),
1587 done_event_(false, false) {
1588 AddRef();
1591 PasswordStoreLoginsChangedObserver::~PasswordStoreLoginsChangedObserver() {
1592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1595 void PasswordStoreLoginsChangedObserver::Init() {
1596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1597 BrowserThread::PostTask(
1598 BrowserThread::DB,
1599 FROM_HERE,
1600 base::Bind(&PasswordStoreLoginsChangedObserver::RegisterObserversTask,
1601 this));
1602 done_event_.Wait();
1605 void PasswordStoreLoginsChangedObserver::RegisterObserversTask() {
1606 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1607 registrar_.reset(new content::NotificationRegistrar);
1608 registrar_->Add(this, chrome::NOTIFICATION_LOGINS_CHANGED,
1609 content::NotificationService::AllSources());
1610 done_event_.Signal();
1613 void PasswordStoreLoginsChangedObserver::Observe(
1614 int type,
1615 const content::NotificationSource& source,
1616 const content::NotificationDetails& details) {
1617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1618 DCHECK(type == chrome::NOTIFICATION_LOGINS_CHANGED);
1619 registrar_.reset(); // Must be done from the DB thread.
1620 PasswordStoreChangeList* change_details =
1621 content::Details<PasswordStoreChangeList>(details).ptr();
1622 if (change_details->size() != 1 ||
1623 change_details->front().type() != expected_type_) {
1624 // Notify the UI thread that there's an error.
1625 std::string error = "Unexpected password store login change details.";
1626 BrowserThread::PostTask(
1627 BrowserThread::UI,
1628 FROM_HERE,
1629 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateError, this,
1630 error));
1631 return;
1634 // Notify the UI thread that we're done listening.
1635 BrowserThread::PostTask(
1636 BrowserThread::UI,
1637 FROM_HERE,
1638 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateDone, this));
1641 void PasswordStoreLoginsChangedObserver::IndicateDone() {
1642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1643 if (automation_.get()) {
1644 if (result_key_.empty()) {
1645 AutomationJSONReply(automation_.get(), reply_message_.release())
1646 .SendSuccess(NULL);
1647 } else {
1648 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
1649 return_value->SetBoolean(result_key_, true);
1650 AutomationJSONReply(automation_.get(), reply_message_.release())
1651 .SendSuccess(return_value.get());
1654 Release();
1657 void PasswordStoreLoginsChangedObserver::IndicateError(
1658 const std::string& error) {
1659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1660 if (automation_.get())
1661 AutomationJSONReply(automation_.get(), reply_message_.release())
1662 .SendError(error);
1663 Release();
1666 OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver(
1667 NavigationController* controller,
1668 AutomationProvider* automation,
1669 IPC::Message* reply_message)
1670 : automation_(automation->AsWeakPtr()),
1671 reply_message_(reply_message),
1672 controller_(controller) {
1673 content::Source<NavigationController> source(controller_);
1674 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1675 // Pages requiring auth don't send LOAD_STOP.
1676 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
1679 OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() {
1682 void OmniboxAcceptNotificationObserver::Observe(
1683 int type,
1684 const content::NotificationSource& source,
1685 const content::NotificationDetails& details) {
1686 if (type == content::NOTIFICATION_LOAD_STOP ||
1687 type == chrome::NOTIFICATION_AUTH_NEEDED) {
1688 if (automation_.get()) {
1689 AutomationJSONReply(automation_.get(), reply_message_.release())
1690 .SendSuccess(NULL);
1692 delete this;
1693 } else {
1694 NOTREACHED();
1698 SavePackageNotificationObserver::SavePackageNotificationObserver(
1699 content::DownloadManager* download_manager,
1700 AutomationProvider* automation,
1701 IPC::Message* reply_message)
1702 : download_manager_(download_manager),
1703 automation_(automation->AsWeakPtr()),
1704 reply_message_(reply_message) {
1705 download_manager_->AddObserver(this);
1708 SavePackageNotificationObserver::~SavePackageNotificationObserver() {
1709 download_manager_->RemoveObserver(this);
1712 void SavePackageNotificationObserver::OnSavePackageSuccessfullyFinished(
1713 content::DownloadManager* manager, content::DownloadItem* item) {
1714 if (automation_.get()) {
1715 AutomationJSONReply(automation_.get(), reply_message_.release())
1716 .SendSuccess(NULL);
1718 delete this;
1721 void SavePackageNotificationObserver::ManagerGoingDown(
1722 content::DownloadManager* manager) {
1723 delete this;
1726 namespace {
1728 // Returns a vector of dictionaries containing information about installed apps,
1729 // as identified from a given list of extensions. The caller takes ownership
1730 // of the created vector.
1731 std::vector<base::DictionaryValue*>* GetAppInfoFromExtensions(
1732 const extensions::ExtensionSet* extensions,
1733 ExtensionService* ext_service) {
1734 std::vector<base::DictionaryValue*>* apps_list =
1735 new std::vector<base::DictionaryValue*>();
1736 for (extensions::ExtensionSet::const_iterator ext = extensions->begin();
1737 ext != extensions->end(); ++ext) {
1738 // Only return information about extensions that are actually apps.
1739 if ((*ext)->is_app()) {
1740 base::DictionaryValue* app_info = new base::DictionaryValue();
1741 AppLauncherHandler::CreateAppInfo(ext->get(), ext_service, app_info);
1742 app_info->SetBoolean(
1743 "is_component_extension",
1744 (*ext)->location() == extensions::Manifest::COMPONENT);
1746 // Convert the launch_type integer into a more descriptive string.
1747 int launch_type;
1748 const char* kLaunchType = "launch_type";
1749 if (!app_info->GetInteger(kLaunchType, &launch_type)) {
1750 NOTREACHED() << "Can't get integer from key " << kLaunchType;
1751 continue;
1753 if (launch_type == extensions::LAUNCH_TYPE_PINNED) {
1754 app_info->SetString(kLaunchType, "pinned");
1755 } else if (launch_type == extensions::LAUNCH_TYPE_REGULAR) {
1756 app_info->SetString(kLaunchType, "regular");
1757 } else if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN) {
1758 app_info->SetString(kLaunchType, "fullscreen");
1759 } else if (launch_type == extensions::LAUNCH_TYPE_WINDOW) {
1760 app_info->SetString(kLaunchType, "window");
1761 } else {
1762 app_info->SetString(kLaunchType, "unknown");
1765 apps_list->push_back(app_info);
1768 return apps_list;
1771 } // namespace
1773 NTPInfoObserver::NTPInfoObserver(AutomationProvider* automation,
1774 IPC::Message* reply_message)
1775 : automation_(automation->AsWeakPtr()),
1776 reply_message_(reply_message),
1777 request_(0),
1778 ntp_info_(new base::DictionaryValue) {
1779 top_sites_ = automation_->profile()->GetTopSites();
1780 if (!top_sites_) {
1781 AutomationJSONReply(automation_.get(), reply_message_.release())
1782 .SendError("Profile does not have service for querying the top sites.");
1783 return;
1785 TabRestoreService* service =
1786 TabRestoreServiceFactory::GetForProfile(automation_->profile());
1787 if (!service) {
1788 AutomationJSONReply(automation_.get(), reply_message_.release())
1789 .SendError("No TabRestoreService.");
1790 return;
1793 // Collect information about the apps in the new tab page.
1794 ExtensionService* ext_service = extensions::ExtensionSystem::Get(
1795 automation_->profile())->extension_service();
1796 if (!ext_service) {
1797 AutomationJSONReply(automation_.get(), reply_message_.release())
1798 .SendError("No ExtensionService.");
1799 return;
1801 // Process enabled extensions.
1802 extensions::ExtensionRegistry* extension_registry =
1803 extensions::ExtensionRegistry::Get(automation_->profile());
1804 base::ListValue* apps_list = new base::ListValue();
1805 const extensions::ExtensionSet& enabled_extensions =
1806 extension_registry->enabled_extensions();
1807 std::vector<base::DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions(
1808 &enabled_extensions, ext_service);
1809 for (std::vector<base::DictionaryValue*>::const_iterator app =
1810 enabled_apps->begin(); app != enabled_apps->end(); ++app) {
1811 (*app)->SetBoolean("is_disabled", false);
1812 apps_list->Append(*app);
1814 delete enabled_apps;
1815 // Process disabled extensions.
1816 const extensions::ExtensionSet& disabled_extensions =
1817 extension_registry->disabled_extensions();
1818 std::vector<base::DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions(
1819 &disabled_extensions, ext_service);
1820 for (std::vector<base::DictionaryValue*>::const_iterator app =
1821 disabled_apps->begin(); app != disabled_apps->end(); ++app) {
1822 (*app)->SetBoolean("is_disabled", true);
1823 apps_list->Append(*app);
1825 delete disabled_apps;
1826 // Process terminated extensions.
1827 const extensions::ExtensionSet& terminated_extensions =
1828 extension_registry->terminated_extensions();
1829 std::vector<base::DictionaryValue*>* terminated_apps =
1830 GetAppInfoFromExtensions(&terminated_extensions, ext_service);
1831 for (std::vector<base::DictionaryValue*>::const_iterator app =
1832 terminated_apps->begin(); app != terminated_apps->end(); ++app) {
1833 (*app)->SetBoolean("is_disabled", true);
1834 apps_list->Append(*app);
1836 delete terminated_apps;
1837 ntp_info_->Set("apps", apps_list);
1839 // Get the info that would be displayed in the recently closed section.
1840 base::ListValue* recently_closed_list = new base::ListValue;
1841 RecentlyClosedTabsHandler::CreateRecentlyClosedValues(service->entries(),
1842 recently_closed_list);
1843 ntp_info_->Set("recently_closed", recently_closed_list);
1845 // Add default site URLs.
1846 base::ListValue* default_sites_list = new base::ListValue;
1847 history::MostVisitedURLList urls = top_sites_->GetPrepopulatePages();
1848 for (size_t i = 0; i < urls.size(); ++i) {
1849 default_sites_list->Append(base::Value::CreateStringValue(
1850 urls[i].url.possibly_invalid_spec()));
1852 ntp_info_->Set("default_sites", default_sites_list);
1854 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_UPDATED,
1855 content::Source<history::TopSites>(top_sites_));
1856 if (top_sites_->loaded()) {
1857 OnTopSitesLoaded();
1858 } else {
1859 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_LOADED,
1860 content::Source<Profile>(automation_->profile()));
1864 NTPInfoObserver::~NTPInfoObserver() {}
1866 void NTPInfoObserver::Observe(int type,
1867 const content::NotificationSource& source,
1868 const content::NotificationDetails& details) {
1869 if (type == chrome::NOTIFICATION_TOP_SITES_LOADED) {
1870 OnTopSitesLoaded();
1871 } else if (type == chrome::NOTIFICATION_TOP_SITES_UPDATED) {
1872 content::Details<CancelableRequestProvider::Handle> request_details(
1873 details);
1874 if (request_ == *request_details.ptr()) {
1875 top_sites_->GetMostVisitedURLs(
1876 base::Bind(&NTPInfoObserver::OnTopSitesReceived,
1877 base::Unretained(this)), false);
1882 void NTPInfoObserver::OnTopSitesLoaded() {
1883 request_ = top_sites_->StartQueryForMostVisited();
1886 void NTPInfoObserver::OnTopSitesReceived(
1887 const history::MostVisitedURLList& visited_list) {
1888 if (!automation_.get()) {
1889 delete this;
1890 return;
1893 base::ListValue* list_value = new base::ListValue;
1894 for (size_t i = 0; i < visited_list.size(); ++i) {
1895 const history::MostVisitedURL& visited = visited_list[i];
1896 if (visited.url.spec().empty())
1897 break; // This is the signal that there are no more real visited sites.
1898 base::DictionaryValue* dict = new base::DictionaryValue;
1899 dict->SetString("url", visited.url.spec());
1900 dict->SetString("title", visited.title);
1901 list_value->Append(dict);
1903 ntp_info_->Set("most_visited", list_value);
1904 AutomationJSONReply(automation_.get(), reply_message_.release())
1905 .SendSuccess(ntp_info_.get());
1906 delete this;
1909 AppLaunchObserver::AppLaunchObserver(
1910 NavigationController* controller,
1911 AutomationProvider* automation,
1912 IPC::Message* reply_message,
1913 extensions::LaunchContainer launch_container)
1914 : controller_(controller),
1915 automation_(automation->AsWeakPtr()),
1916 reply_message_(reply_message),
1917 launch_container_(launch_container),
1918 new_window_id_(extension_misc::kUnknownWindowId) {
1919 if (launch_container_ == extensions::LAUNCH_CONTAINER_TAB) {
1920 // Need to wait for the currently-active tab to reload.
1921 content::Source<NavigationController> source(controller_);
1922 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source);
1923 } else {
1924 // Need to wait for a new tab in a new window to load.
1925 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
1926 content::NotificationService::AllSources());
1927 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
1928 content::NotificationService::AllSources());
1932 AppLaunchObserver::~AppLaunchObserver() {}
1934 void AppLaunchObserver::Observe(int type,
1935 const content::NotificationSource& source,
1936 const content::NotificationDetails& details) {
1937 if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) {
1938 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
1939 content::Source<Browser>(source).ptr());
1940 return;
1943 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
1944 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(
1945 content::Source<NavigationController>(source)->GetWebContents());
1946 if ((launch_container_ == extensions::LAUNCH_CONTAINER_TAB) ||
1947 (session_tab_helper &&
1948 (session_tab_helper->window_id().id() == new_window_id_))) {
1949 if (automation_.get()) {
1950 AutomationJSONReply(automation_.get(), reply_message_.release())
1951 .SendSuccess(NULL);
1953 delete this;
1957 namespace {
1959 // Returns whether all active notifications have an associated process ID.
1960 bool AreActiveNotificationProcessesReady() {
1961 BalloonNotificationUIManager* manager =
1962 BalloonNotificationUIManager::GetInstanceForTesting();
1963 const BalloonCollection::Balloons& balloons =
1964 manager->balloon_collection()->GetActiveBalloons();
1965 BalloonCollection::Balloons::const_iterator iter;
1966 for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
1967 BalloonHost* balloon_host = (*iter)->balloon_view()->GetHost();
1968 if (balloon_host && !balloon_host->IsRenderViewReady())
1969 return false;
1971 return true;
1974 } // namespace
1976 GetAllNotificationsObserver::GetAllNotificationsObserver(
1977 AutomationProvider* automation,
1978 IPC::Message* reply_message)
1979 : automation_(automation->AsWeakPtr()),
1980 reply_message_(reply_message) {
1981 if (AreActiveNotificationProcessesReady()) {
1982 SendMessage();
1983 } else {
1984 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
1985 content::NotificationService::AllSources());
1989 GetAllNotificationsObserver::~GetAllNotificationsObserver() {}
1991 void GetAllNotificationsObserver::Observe(
1992 int type,
1993 const content::NotificationSource& source,
1994 const content::NotificationDetails& details) {
1995 if (!automation_.get()) {
1996 delete this;
1997 return;
1999 if (AreActiveNotificationProcessesReady())
2000 SendMessage();
2003 base::DictionaryValue* GetAllNotificationsObserver::NotificationToJson(
2004 const Notification* note) {
2005 base::DictionaryValue* dict = new base::DictionaryValue();
2006 dict->SetString("content_url", note->content_url().spec());
2007 dict->SetString("origin_url", note->origin_url().spec());
2008 dict->SetString("display_source", note->display_source());
2009 dict->SetString("id", note->notification_id());
2010 return dict;
2013 void GetAllNotificationsObserver::SendMessage() {
2014 BalloonNotificationUIManager* manager =
2015 BalloonNotificationUIManager::GetInstanceForTesting();
2016 const BalloonCollection::Balloons& balloons =
2017 manager->balloon_collection()->GetActiveBalloons();
2018 base::DictionaryValue return_value;
2019 base::ListValue* list = new base::ListValue;
2020 return_value.Set("notifications", list);
2021 BalloonCollection::Balloons::const_iterator balloon_iter;
2022 for (balloon_iter = balloons.begin(); balloon_iter != balloons.end();
2023 ++balloon_iter) {
2024 base::DictionaryValue* note = NotificationToJson(
2025 &(*balloon_iter)->notification());
2026 BalloonHost* balloon_host = (*balloon_iter)->balloon_view()->GetHost();
2027 if (balloon_host) {
2028 int pid = base::GetProcId(balloon_host->web_contents()->
2029 GetRenderViewHost()->GetProcess()->GetHandle());
2030 note->SetInteger("pid", pid);
2032 list->Append(note);
2034 std::vector<const Notification*> queued_notes;
2035 manager->GetQueuedNotificationsForTesting(&queued_notes);
2036 std::vector<const Notification*>::const_iterator queued_iter;
2037 for (queued_iter = queued_notes.begin(); queued_iter != queued_notes.end();
2038 ++queued_iter) {
2039 list->Append(NotificationToJson(*queued_iter));
2041 AutomationJSONReply(automation_.get(), reply_message_.release())
2042 .SendSuccess(&return_value);
2043 delete this;
2046 NewNotificationBalloonObserver::NewNotificationBalloonObserver(
2047 AutomationProvider* provider,
2048 IPC::Message* reply_message)
2049 : automation_(provider->AsWeakPtr()),
2050 reply_message_(reply_message) {
2051 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
2052 content::NotificationService::AllSources());
2055 NewNotificationBalloonObserver::~NewNotificationBalloonObserver() { }
2057 void NewNotificationBalloonObserver::Observe(
2058 int type,
2059 const content::NotificationSource& source,
2060 const content::NotificationDetails& details) {
2061 if (automation_.get()) {
2062 AutomationJSONReply(automation_.get(), reply_message_.release())
2063 .SendSuccess(NULL);
2065 delete this;
2068 OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver(
2069 AutomationProvider* provider,
2070 IPC::Message* reply_message,
2071 int count)
2072 : automation_(provider->AsWeakPtr()),
2073 reply_message_(reply_message),
2074 collection_(BalloonNotificationUIManager::GetInstanceForTesting()->
2075 balloon_collection()),
2076 count_(count) {
2077 registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
2078 content::NotificationService::AllSources());
2079 collection_->set_on_collection_changed_callback(
2080 base::Bind(&OnNotificationBalloonCountObserver::CheckBalloonCount,
2081 base::Unretained(this)));
2082 CheckBalloonCount();
2085 OnNotificationBalloonCountObserver::~OnNotificationBalloonCountObserver() {
2088 void OnNotificationBalloonCountObserver::Observe(
2089 int type,
2090 const content::NotificationSource& source,
2091 const content::NotificationDetails& details) {
2092 CheckBalloonCount();
2095 void OnNotificationBalloonCountObserver::CheckBalloonCount() {
2096 bool balloon_count_met = AreActiveNotificationProcessesReady() &&
2097 static_cast<int>(collection_->GetActiveBalloons().size()) == count_;
2099 if (balloon_count_met && automation_.get()) {
2100 AutomationJSONReply(automation_.get(), reply_message_.release())
2101 .SendSuccess(NULL);
2104 if (balloon_count_met || !automation_.get()) {
2105 collection_->set_on_collection_changed_callback(base::Closure());
2106 delete this;
2110 RendererProcessClosedObserver::RendererProcessClosedObserver(
2111 AutomationProvider* automation,
2112 IPC::Message* reply_message)
2113 : automation_(automation->AsWeakPtr()),
2114 reply_message_(reply_message) {
2115 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
2116 content::NotificationService::AllSources());
2119 RendererProcessClosedObserver::~RendererProcessClosedObserver() {}
2121 void RendererProcessClosedObserver::Observe(
2122 int type,
2123 const content::NotificationSource& source,
2124 const content::NotificationDetails& details) {
2125 if (automation_.get()) {
2126 AutomationJSONReply(automation_.get(), reply_message_.release())
2127 .SendSuccess(NULL);
2129 delete this;
2132 InputEventAckNotificationObserver::InputEventAckNotificationObserver(
2133 AutomationProvider* automation,
2134 IPC::Message* reply_message,
2135 int event_type,
2136 int count)
2137 : automation_(automation->AsWeakPtr()),
2138 reply_message_(reply_message),
2139 event_type_(event_type),
2140 count_(count) {
2141 DCHECK(1 <= count);
2142 registrar_.Add(
2143 this,
2144 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
2145 content::NotificationService::AllSources());
2146 registrar_.Add(
2147 this,
2148 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
2149 content::NotificationService::AllSources());
2152 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {}
2154 void InputEventAckNotificationObserver::Observe(
2155 int type,
2156 const content::NotificationSource& source,
2157 const content::NotificationDetails& details) {
2158 if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) {
2159 AutomationJSONReply(automation_.get(), reply_message_.release())
2160 .SendSuccess(NULL);
2161 delete this;
2162 return;
2165 content::Details<int> request_details(details);
2166 // If the event type matches for |count_| times, replies with a JSON message.
2167 if (event_type_ == *request_details.ptr()) {
2168 if (--count_ == 0 && automation_.get()) {
2169 AutomationJSONReply(automation_.get(), reply_message_.release())
2170 .SendSuccess(NULL);
2171 delete this;
2173 } else {
2174 LOG(WARNING) << "Ignoring unexpected event type: "
2175 << *request_details.ptr() << " (expected: " << event_type_
2176 << ")";
2180 NewTabObserver::NewTabObserver(AutomationProvider* automation,
2181 IPC::Message* reply_message,
2182 bool use_json_interface)
2183 : automation_(automation->AsWeakPtr()),
2184 reply_message_(reply_message),
2185 use_json_interface_(use_json_interface) {
2186 // Use TAB_PARENTED to detect the new tab.
2187 registrar_.Add(this,
2188 chrome::NOTIFICATION_TAB_PARENTED,
2189 content::NotificationService::AllSources());
2192 void NewTabObserver::Observe(int type,
2193 const content::NotificationSource& source,
2194 const content::NotificationDetails& details) {
2195 DCHECK_EQ(chrome::NOTIFICATION_TAB_PARENTED, type);
2196 NavigationController* controller =
2197 &(content::Source<content::WebContents>(source).ptr()->GetController());
2198 if (automation_.get()) {
2199 // TODO(phajdan.jr): Clean up this hack. We write the correct return type
2200 // here, but don't send the message. NavigationNotificationObserver
2201 // will wait properly for the load to finish, and send the message,
2202 // but it will also append its own return value at the end of the reply.
2203 if (!use_json_interface_)
2204 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
2205 true);
2206 new NavigationNotificationObserver(controller,
2207 automation_.get(),
2208 reply_message_.release(),
2210 false,
2211 use_json_interface_);
2213 delete this;
2216 NewTabObserver::~NewTabObserver() {
2219 WaitForProcessLauncherThreadToGoIdleObserver::
2220 WaitForProcessLauncherThreadToGoIdleObserver(
2221 AutomationProvider* automation, IPC::Message* reply_message)
2222 : automation_(automation->AsWeakPtr()),
2223 reply_message_(reply_message) {
2224 // Balanced in RunOnUIThread.
2225 AddRef();
2226 BrowserThread::PostTask(
2227 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2228 base::Bind(
2229 &WaitForProcessLauncherThreadToGoIdleObserver::
2230 RunOnProcessLauncherThread,
2231 this));
2234 WaitForProcessLauncherThreadToGoIdleObserver::
2235 ~WaitForProcessLauncherThreadToGoIdleObserver() {
2238 void WaitForProcessLauncherThreadToGoIdleObserver::
2239 RunOnProcessLauncherThread() {
2240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2241 BrowserThread::PostTask(
2242 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2243 base::Bind(
2244 &WaitForProcessLauncherThreadToGoIdleObserver::
2245 RunOnProcessLauncherThread2,
2246 this));
2249 void WaitForProcessLauncherThreadToGoIdleObserver::
2250 RunOnProcessLauncherThread2() {
2251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2252 BrowserThread::PostTask(
2253 BrowserThread::UI, FROM_HERE,
2254 base::Bind(&WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread,
2255 this));
2258 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() {
2259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2260 if (automation_.get())
2261 automation_->Send(reply_message_.release());
2262 Release();
2265 DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver(
2266 AutomationProvider* automation,
2267 IPC::Message* reply_message)
2268 : automation_(automation->AsWeakPtr()),
2269 reply_message_(reply_message) {
2270 registrar_.Add(
2271 this,
2272 content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK,
2273 content::NotificationService::AllSources());
2274 registrar_.Add(
2275 this,
2276 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
2277 content::NotificationService::AllSources());
2280 DragTargetDropAckNotificationObserver::
2281 ~DragTargetDropAckNotificationObserver() {}
2283 void DragTargetDropAckNotificationObserver::Observe(
2284 int type,
2285 const content::NotificationSource& source,
2286 const content::NotificationDetails& details) {
2287 if (automation_.get()) {
2288 AutomationJSONReply(automation_.get(), reply_message_.release())
2289 .SendSuccess(NULL);
2291 delete this;
2294 ProcessInfoObserver::ProcessInfoObserver(
2295 AutomationProvider* automation,
2296 IPC::Message* reply_message)
2297 : automation_(automation->AsWeakPtr()),
2298 reply_message_(reply_message) {}
2300 ProcessInfoObserver::~ProcessInfoObserver() {}
2302 void ProcessInfoObserver::OnDetailsAvailable() {
2303 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2304 base::ListValue* browser_proc_list = new base::ListValue();
2305 const std::vector<ProcessData>& all_processes = processes();
2306 for (size_t index = 0; index < all_processes.size(); ++index) {
2307 base::DictionaryValue* browser_data = new base::DictionaryValue();
2308 browser_data->SetString("name", all_processes[index].name);
2309 browser_data->SetString("process_name", all_processes[index].process_name);
2311 base::ListValue* proc_list = new base::ListValue();
2312 for (ProcessMemoryInformationList::const_iterator iterator =
2313 all_processes[index].processes.begin();
2314 iterator != all_processes[index].processes.end(); ++iterator) {
2315 base::DictionaryValue* proc_data = new base::DictionaryValue();
2317 proc_data->SetInteger("pid", iterator->pid);
2319 // Working set (resident) memory usage, in KBytes.
2320 base::DictionaryValue* working_set = new base::DictionaryValue();
2321 working_set->SetInteger("priv", iterator->working_set.priv);
2322 working_set->SetInteger("shareable", iterator->working_set.shareable);
2323 working_set->SetInteger("shared", iterator->working_set.shared);
2324 proc_data->Set("working_set_mem", working_set);
2326 // Committed (resident + paged) memory usage, in KBytes.
2327 base::DictionaryValue* committed = new base::DictionaryValue();
2328 committed->SetInteger("priv", iterator->committed.priv);
2329 committed->SetInteger("mapped", iterator->committed.mapped);
2330 committed->SetInteger("image", iterator->committed.image);
2331 proc_data->Set("committed_mem", committed);
2333 proc_data->SetString("version", iterator->version);
2334 proc_data->SetString("product_name", iterator->product_name);
2335 proc_data->SetInteger("num_processes", iterator->num_processes);
2336 proc_data->SetBoolean("is_diagnostics", iterator->is_diagnostics);
2338 // Process type, if this is a child process of Chrome (e.g., 'plugin').
2339 std::string process_type = "Unknown";
2340 // The following condition avoids a DCHECK in debug builds when the
2341 // process type passed to |GetTypeNameInEnglish| is unknown.
2342 if (iterator->process_type != content::PROCESS_TYPE_UNKNOWN) {
2343 process_type =
2344 content::GetProcessTypeNameInEnglish(iterator->process_type);
2346 proc_data->SetString("child_process_type", process_type);
2348 // Renderer type, if this is a renderer process.
2349 std::string renderer_type = "Unknown";
2350 if (iterator->renderer_type !=
2351 ProcessMemoryInformation::RENDERER_UNKNOWN) {
2352 renderer_type = ProcessMemoryInformation::GetRendererTypeNameInEnglish(
2353 iterator->renderer_type);
2355 proc_data->SetString("renderer_type", renderer_type);
2357 // Titles associated with this process.
2358 base::ListValue* titles = new base::ListValue();
2359 for (size_t title_index = 0; title_index < iterator->titles.size();
2360 ++title_index) {
2361 titles->Append(
2362 base::Value::CreateStringValue(iterator->titles[title_index]));
2364 proc_data->Set("titles", titles);
2366 proc_list->Append(proc_data);
2368 browser_data->Set("processes", proc_list);
2370 browser_proc_list->Append(browser_data);
2372 return_value->Set("browsers", browser_proc_list);
2374 if (automation_.get()) {
2375 AutomationJSONReply(automation_.get(), reply_message_.release())
2376 .SendSuccess(return_value.get());
2380 V8HeapStatsObserver::V8HeapStatsObserver(
2381 AutomationProvider* automation,
2382 IPC::Message* reply_message,
2383 base::ProcessId renderer_id)
2384 : automation_(automation->AsWeakPtr()),
2385 reply_message_(reply_message),
2386 renderer_id_(renderer_id) {
2387 registrar_.Add(
2388 this,
2389 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
2390 content::NotificationService::AllSources());
2393 V8HeapStatsObserver::~V8HeapStatsObserver() {}
2395 void V8HeapStatsObserver::Observe(
2396 int type,
2397 const content::NotificationSource& source,
2398 const content::NotificationDetails& details) {
2399 DCHECK(type == chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED);
2401 base::ProcessId updated_renderer_id =
2402 *(content::Source<base::ProcessId>(source).ptr());
2403 // Only return information for the renderer ID we're interested in.
2404 if (renderer_id_ != updated_renderer_id)
2405 return;
2407 ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap_details =
2408 content::Details<ChromeRenderMessageFilter::V8HeapStatsDetails>(details)
2409 .ptr();
2410 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2411 return_value->SetInteger("renderer_id", updated_renderer_id);
2412 return_value->SetInteger("v8_memory_allocated",
2413 v8_heap_details->v8_memory_allocated());
2414 return_value->SetInteger("v8_memory_used",
2415 v8_heap_details->v8_memory_used());
2417 if (automation_.get()) {
2418 AutomationJSONReply(automation_.get(), reply_message_.release())
2419 .SendSuccess(return_value.get());
2421 delete this;
2424 FPSObserver::FPSObserver(
2425 AutomationProvider* automation,
2426 IPC::Message* reply_message,
2427 base::ProcessId renderer_id,
2428 int routing_id)
2429 : automation_(automation->AsWeakPtr()),
2430 reply_message_(reply_message),
2431 renderer_id_(renderer_id),
2432 routing_id_(routing_id) {
2433 registrar_.Add(
2434 this,
2435 chrome::NOTIFICATION_RENDERER_FPS_COMPUTED,
2436 content::NotificationService::AllSources());
2439 FPSObserver::~FPSObserver() {}
2441 void FPSObserver::Observe(
2442 int type,
2443 const content::NotificationSource& source,
2444 const content::NotificationDetails& details) {
2445 DCHECK(type == chrome::NOTIFICATION_RENDERER_FPS_COMPUTED);
2447 base::ProcessId updated_renderer_id =
2448 *(content::Source<base::ProcessId>(source).ptr());
2449 // Only return information for the renderer ID we're interested in.
2450 if (renderer_id_ != updated_renderer_id)
2451 return;
2453 ChromeRenderMessageFilter::FPSDetails* fps_details =
2454 content::Details<ChromeRenderMessageFilter::FPSDetails>(details).ptr();
2455 // Only return information for the routing id of the host render view we're
2456 // interested in.
2457 if (routing_id_ != fps_details->routing_id())
2458 return;
2460 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
2461 return_value->SetInteger("renderer_id", updated_renderer_id);
2462 return_value->SetInteger("routing_id", fps_details->routing_id());
2463 return_value->SetDouble("fps", fps_details->fps());
2464 if (automation_.get()) {
2465 AutomationJSONReply(automation_.get(), reply_message_.release())
2466 .SendSuccess(return_value.get());
2468 delete this;
2471 BrowserOpenedWithNewProfileNotificationObserver::
2472 BrowserOpenedWithNewProfileNotificationObserver(
2473 AutomationProvider* automation,
2474 IPC::Message* reply_message)
2475 : automation_(automation->AsWeakPtr()),
2476 reply_message_(reply_message),
2477 new_window_id_(extension_misc::kUnknownWindowId) {
2478 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
2479 content::NotificationService::AllBrowserContextsAndSources());
2480 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2481 content::NotificationService::AllBrowserContextsAndSources());
2482 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2483 content::NotificationService::AllBrowserContextsAndSources());
2486 BrowserOpenedWithNewProfileNotificationObserver::
2487 ~BrowserOpenedWithNewProfileNotificationObserver() {
2490 void BrowserOpenedWithNewProfileNotificationObserver::Observe(
2491 int type,
2492 const content::NotificationSource& source,
2493 const content::NotificationDetails& details) {
2494 if (!automation_.get()) {
2495 delete this;
2496 return;
2499 if (type == chrome::NOTIFICATION_PROFILE_CREATED) {
2500 // As part of multi-profile creation, a new browser window will
2501 // automatically be opened.
2502 Profile* profile = content::Source<Profile>(source).ptr();
2503 if (!profile) {
2504 AutomationJSONReply(automation_.get(), reply_message_.release())
2505 .SendError("Profile could not be created.");
2506 return;
2508 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2509 // Store the new browser ID and continue waiting for a new tab within it
2510 // to stop loading.
2511 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
2512 content::Source<Browser>(source).ptr());
2513 } else {
2514 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
2515 // Only send the result if the loaded tab is in the new window.
2516 NavigationController* controller =
2517 content::Source<NavigationController>(source).ptr();
2518 SessionTabHelper* session_tab_helper =
2519 SessionTabHelper::FromWebContents(controller->GetWebContents());
2520 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2521 : -1;
2522 if (window_id == new_window_id_) {
2523 if (automation_.get()) {
2524 AutomationJSONReply(automation_.get(), reply_message_.release())
2525 .SendSuccess(NULL);
2527 delete this;
2532 ExtensionPopupObserver::ExtensionPopupObserver(
2533 AutomationProvider* automation,
2534 IPC::Message* reply_message,
2535 const std::string& extension_id)
2536 : automation_(automation->AsWeakPtr()),
2537 reply_message_(reply_message),
2538 extension_id_(extension_id) {
2539 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
2540 content::NotificationService::AllSources());
2543 ExtensionPopupObserver::~ExtensionPopupObserver() {
2546 void ExtensionPopupObserver::Observe(
2547 int type,
2548 const content::NotificationSource& source,
2549 const content::NotificationDetails& details) {
2550 if (!automation_.get()) {
2551 delete this;
2552 return;
2555 extensions::ExtensionHost* host =
2556 content::Details<extensions::ExtensionHost>(details).ptr();
2557 if (host->extension_id() == extension_id_ &&
2558 host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) {
2559 AutomationJSONReply(automation_.get(), reply_message_.release())
2560 .SendSuccess(NULL);
2561 delete this;
2565 #if defined(OS_LINUX)
2566 WindowMaximizedObserver::WindowMaximizedObserver(
2567 AutomationProvider* automation,
2568 IPC::Message* reply_message)
2569 : automation_(automation->AsWeakPtr()),
2570 reply_message_(reply_message) {
2571 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
2572 content::NotificationService::AllSources());
2575 WindowMaximizedObserver::~WindowMaximizedObserver() {}
2577 void WindowMaximizedObserver::Observe(
2578 int type,
2579 const content::NotificationSource& source,
2580 const content::NotificationDetails& details) {
2581 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, type);
2583 if (automation_.get()) {
2584 AutomationJSONReply(automation_.get(), reply_message_.release())
2585 .SendSuccess(NULL);
2587 delete this;
2589 #endif // defined(OS_LINUX)
2591 BrowserOpenedWithExistingProfileNotificationObserver::
2592 BrowserOpenedWithExistingProfileNotificationObserver(
2593 AutomationProvider* automation,
2594 IPC::Message* reply_message,
2595 int num_loads)
2596 : automation_(automation->AsWeakPtr()),
2597 reply_message_(reply_message),
2598 new_window_id_(extension_misc::kUnknownWindowId),
2599 num_loads_(num_loads) {
2600 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
2601 content::NotificationService::AllBrowserContextsAndSources());
2602 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
2603 content::NotificationService::AllBrowserContextsAndSources());
2606 BrowserOpenedWithExistingProfileNotificationObserver::
2607 ~BrowserOpenedWithExistingProfileNotificationObserver() {
2610 void BrowserOpenedWithExistingProfileNotificationObserver::Observe(
2611 int type,
2612 const content::NotificationSource& source,
2613 const content::NotificationDetails& details) {
2614 if (!automation_.get()) {
2615 delete this;
2616 return;
2619 if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
2620 // Store the new browser ID and continue waiting for NOTIFICATION_LOAD_STOP.
2621 new_window_id_ = extensions::ExtensionTabUtil::GetWindowId(
2622 content::Source<Browser>(source).ptr());
2623 } else if (type == content::NOTIFICATION_LOAD_STOP) {
2624 // Only consider if the loaded tab is in the new window.
2625 NavigationController* controller =
2626 content::Source<NavigationController>(source).ptr();
2627 SessionTabHelper* session_tab_helper =
2628 SessionTabHelper::FromWebContents(controller->GetWebContents());
2629 int window_id = session_tab_helper ? session_tab_helper->window_id().id()
2630 : -1;
2631 if (window_id == new_window_id_ && --num_loads_ == 0) {
2632 if (automation_.get()) {
2633 AutomationJSONReply(automation_.get(), reply_message_.release())
2634 .SendSuccess(NULL);
2636 delete this;
2638 } else {
2639 NOTREACHED();