1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/automation/automation_provider_observers.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/file_util.h"
16 #include "base/json/json_writer.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "base/values.h"
25 #include "chrome/app/chrome_command_ids.h"
26 #include "chrome/browser/automation/automation_provider.h"
27 #include "chrome/browser/automation/automation_provider_json.h"
28 #include "chrome/browser/bookmarks/bookmark_model.h"
29 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/chrome_notification_types.h"
32 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
33 #include "chrome/browser/extensions/crx_installer.h"
34 #include "chrome/browser/extensions/extension_host.h"
35 #include "chrome/browser/extensions/extension_service.h"
36 #include "chrome/browser/extensions/extension_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"
89 using content::BrowserThread
;
90 using content::DomOperationNotificationDetails
;
91 using content::DownloadItem
;
92 using content::DownloadManager
;
93 using content::NavigationController
;
94 using content::RenderViewHost
;
95 using content::WebContents
;
97 // Holds onto start and stop timestamps for a particular tab
98 class InitialLoadObserver::TabTime
{
100 explicit TabTime(base::TimeTicks started
)
101 : load_start_time_(started
) {
103 void set_stop_time(base::TimeTicks stopped
) {
104 load_stop_time_
= stopped
;
106 base::TimeTicks
stop_time() const {
107 return load_stop_time_
;
109 base::TimeTicks
start_time() const {
110 return load_start_time_
;
113 base::TimeTicks load_start_time_
;
114 base::TimeTicks load_stop_time_
;
117 InitialLoadObserver::InitialLoadObserver(size_t tab_count
,
118 AutomationProvider
* automation
)
119 : automation_(automation
->AsWeakPtr()),
120 crashed_tab_count_(0),
121 outstanding_tab_count_(tab_count
),
122 init_time_(base::TimeTicks::Now()) {
123 if (outstanding_tab_count_
> 0) {
124 registrar_
.Add(this, content::NOTIFICATION_LOAD_START
,
125 content::NotificationService::AllSources());
126 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
127 content::NotificationService::AllSources());
128 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
129 content::NotificationService::AllSources());
133 InitialLoadObserver::~InitialLoadObserver() {
136 void InitialLoadObserver::Observe(int type
,
137 const content::NotificationSource
& source
,
138 const content::NotificationDetails
& details
) {
139 if (type
== content::NOTIFICATION_LOAD_START
) {
140 if (outstanding_tab_count_
> loading_tabs_
.size())
141 loading_tabs_
.insert(TabTimeMap::value_type(
143 TabTime(base::TimeTicks::Now())));
144 } else if (type
== content::NOTIFICATION_LOAD_STOP
) {
145 if (outstanding_tab_count_
> finished_tabs_
.size()) {
146 TabTimeMap::iterator iter
= loading_tabs_
.find(source
.map_key());
147 if (iter
!= loading_tabs_
.end()) {
148 finished_tabs_
.insert(source
.map_key());
149 iter
->second
.set_stop_time(base::TimeTicks::Now());
152 } else if (type
== content::NOTIFICATION_RENDERER_PROCESS_CLOSED
) {
153 base::TerminationStatus status
=
154 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
157 case base::TERMINATION_STATUS_NORMAL_TERMINATION
:
160 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
161 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
162 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
163 crashed_tab_count_
++;
166 case base::TERMINATION_STATUS_STILL_RUNNING
:
167 LOG(ERROR
) << "Got RENDERER_PROCESS_CLOSED notification, "
168 << "but the process is still running. We may miss further "
169 << "crash notification, resulting in hangs.";
173 LOG(ERROR
) << "Unhandled termination status " << status
;
181 if (finished_tabs_
.size() + crashed_tab_count_
>= outstanding_tab_count_
)
185 base::DictionaryValue
* InitialLoadObserver::GetTimingInformation() const {
186 base::ListValue
* items
= new base::ListValue
;
187 for (TabTimeMap::const_iterator it
= loading_tabs_
.begin();
188 it
!= loading_tabs_
.end();
190 base::DictionaryValue
* item
= new base::DictionaryValue
;
191 base::TimeDelta delta_start
= it
->second
.start_time() - init_time_
;
193 item
->SetDouble("load_start_ms", delta_start
.InMillisecondsF());
194 if (it
->second
.stop_time().is_null()) {
195 item
->Set("load_stop_ms", base::Value::CreateNullValue());
197 base::TimeDelta delta_stop
= it
->second
.stop_time() - init_time_
;
198 item
->SetDouble("load_stop_ms", delta_stop
.InMillisecondsF());
202 base::DictionaryValue
* return_value
= new base::DictionaryValue
;
203 return_value
->Set("tabs", items
);
207 void InitialLoadObserver::ConditionMet() {
208 registrar_
.RemoveAll();
209 if (automation_
.get())
210 automation_
->OnInitialTabLoadsComplete();
213 NavigationControllerRestoredObserver::NavigationControllerRestoredObserver(
214 AutomationProvider
* automation
,
215 NavigationController
* controller
,
216 IPC::Message
* reply_message
)
217 : automation_(automation
->AsWeakPtr()),
218 controller_(controller
),
219 reply_message_(reply_message
) {
220 if (FinishedRestoring()) {
223 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
224 content::NotificationService::AllSources());
228 NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() {
231 void NavigationControllerRestoredObserver::Observe(
232 int type
, const content::NotificationSource
& source
,
233 const content::NotificationDetails
& details
) {
234 if (FinishedRestoring()) {
235 registrar_
.RemoveAll();
240 bool NavigationControllerRestoredObserver::FinishedRestoring() {
241 return (!controller_
->NeedsReload() && !controller_
->GetPendingEntry() &&
242 !controller_
->GetWebContents()->IsLoading());
245 void NavigationControllerRestoredObserver::SendDone() {
246 if (automation_
.get()) {
247 AutomationJSONReply(automation_
.get(), reply_message_
.release())
253 NavigationNotificationObserver::NavigationNotificationObserver(
254 NavigationController
* controller
,
255 AutomationProvider
* automation
,
256 IPC::Message
* reply_message
,
257 int number_of_navigations
,
258 bool include_current_navigation
,
259 bool use_json_interface
)
260 : automation_(automation
->AsWeakPtr()),
261 reply_message_(reply_message
),
262 controller_(controller
),
263 navigations_remaining_(number_of_navigations
),
264 navigation_started_(false),
265 use_json_interface_(use_json_interface
) {
266 if (number_of_navigations
== 0) {
267 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS
);
270 DCHECK_LT(0, navigations_remaining_
);
271 content::Source
<NavigationController
> source(controller_
);
272 registrar_
.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED
, source
);
273 registrar_
.Add(this, content::NOTIFICATION_LOAD_START
, source
);
274 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
, source
);
275 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_NEEDED
, source
);
276 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED
, source
);
277 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED
, source
);
278 registrar_
.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN
,
279 content::NotificationService::AllSources());
281 if (include_current_navigation
&& controller
->GetWebContents()->IsLoading())
282 navigation_started_
= true;
285 NavigationNotificationObserver::~NavigationNotificationObserver() {
288 void NavigationNotificationObserver::Observe(
289 int type
, const content::NotificationSource
& source
,
290 const content::NotificationDetails
& details
) {
291 if (!automation_
.get()) {
296 // We listen for 2 events to determine when the navigation started because:
297 // - when this is used by the WaitForNavigation method, we might be invoked
298 // afer the load has started (but not after the entry was committed, as
299 // WaitForNavigation compares times of the last navigation).
300 // - when this is used with a page requiring authentication, we will not get
301 // a chrome::NAV_ENTRY_COMMITTED until after we authenticate, so
302 // we need the chrome::LOAD_START.
303 if (type
== content::NOTIFICATION_NAV_ENTRY_COMMITTED
||
304 type
== content::NOTIFICATION_LOAD_START
) {
305 navigation_started_
= true;
306 } else if (type
== content::NOTIFICATION_LOAD_STOP
) {
307 if (navigation_started_
) {
308 navigation_started_
= false;
309 if (--navigations_remaining_
== 0)
310 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS
);
312 } else if (type
== chrome::NOTIFICATION_AUTH_SUPPLIED
||
313 type
== chrome::NOTIFICATION_AUTH_CANCELLED
) {
314 // Treat this as if navigation started again, since load start/stop don't
315 // occur while authentication is ongoing.
316 navigation_started_
= true;
317 } else if (type
== chrome::NOTIFICATION_AUTH_NEEDED
) {
318 // Respond that authentication is needed.
319 navigation_started_
= false;
320 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED
);
321 } else if (type
== chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN
) {
322 ConditionMet(AUTOMATION_MSG_NAVIGATION_BLOCKED_BY_MODAL_DIALOG
);
328 void NavigationNotificationObserver::ConditionMet(
329 AutomationMsg_NavigationResponseValues navigation_result
) {
330 if (automation_
.get()) {
331 if (use_json_interface_
) {
332 if (navigation_result
== AUTOMATION_MSG_NAVIGATION_SUCCESS
) {
333 base::DictionaryValue dict
;
334 dict
.SetInteger("result", navigation_result
);
335 AutomationJSONReply(automation_
.get(), reply_message_
.release())
338 AutomationJSONReply(automation_
.get(), reply_message_
.release())
339 .SendError(base::StringPrintf(
340 "Navigation failed with error code=%d.", navigation_result
));
343 IPC::ParamTraits
<int>::Write(
344 reply_message_
.get(), navigation_result
);
345 automation_
->Send(reply_message_
.release());
352 TabStripNotificationObserver::TabStripNotificationObserver(
353 int notification
, AutomationProvider
* automation
)
354 : automation_(automation
->AsWeakPtr()),
355 notification_(notification
) {
356 registrar_
.Add(this, notification_
,
357 content::NotificationService::AllSources());
360 TabStripNotificationObserver::~TabStripNotificationObserver() {
363 void TabStripNotificationObserver::Observe(
365 const content::NotificationSource
& source
,
366 const content::NotificationDetails
& details
) {
367 DCHECK_EQ(notification_
, type
);
368 if (type
== chrome::NOTIFICATION_TAB_PARENTED
) {
369 ObserveTab(&content::Source
<content::WebContents
>(source
)->GetController());
370 } else if (type
== content::NOTIFICATION_WEB_CONTENTS_DESTROYED
) {
371 ObserveTab(&content::Source
<content::WebContents
>(source
)->GetController());
373 ObserveTab(content::Source
<NavigationController
>(source
).ptr());
378 TabAppendedNotificationObserver::TabAppendedNotificationObserver(
380 AutomationProvider
* automation
,
381 IPC::Message
* reply_message
,
382 bool use_json_interface
)
383 : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED
,
386 reply_message_(reply_message
),
387 use_json_interface_(use_json_interface
) {
390 TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {}
392 void TabAppendedNotificationObserver::ObserveTab(
393 NavigationController
* controller
) {
394 if (!automation_
.get() || !reply_message_
.get())
397 if (automation_
->GetIndexForNavigationController(controller
, parent_
) ==
398 TabStripModel::kNoTab
) {
399 // This tab notification doesn't belong to the parent_.
403 new NavigationNotificationObserver(controller
,
405 reply_message_
.release(),
408 use_json_interface_
);
411 IPC::Message
* TabAppendedNotificationObserver::ReleaseReply() {
412 return reply_message_
.release();
415 TabClosedNotificationObserver::TabClosedNotificationObserver(
416 AutomationProvider
* automation
,
417 bool wait_until_closed
,
418 IPC::Message
* reply_message
,
419 bool use_json_interface
)
420 : TabStripNotificationObserver((wait_until_closed
?
421 static_cast<int>(content::NOTIFICATION_WEB_CONTENTS_DESTROYED
) :
422 static_cast<int>(chrome::NOTIFICATION_TAB_CLOSING
)), automation
),
423 reply_message_(reply_message
),
424 use_json_interface_(use_json_interface
),
425 for_browser_command_(false) {
428 TabClosedNotificationObserver::~TabClosedNotificationObserver() {}
430 void TabClosedNotificationObserver::ObserveTab(
431 NavigationController
* controller
) {
432 if (!automation_
.get())
435 if (use_json_interface_
) {
436 AutomationJSONReply(automation_
.get(), reply_message_
.release())
439 if (for_browser_command_
) {
440 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_
.get(),
443 AutomationMsg_CloseTab::WriteReplyParams(reply_message_
.get(), true);
445 automation_
->Send(reply_message_
.release());
449 void TabClosedNotificationObserver::set_for_browser_command(
450 bool for_browser_command
) {
451 for_browser_command_
= for_browser_command
;
454 TabCountChangeObserver::TabCountChangeObserver(AutomationProvider
* automation
,
456 IPC::Message
* reply_message
,
457 int target_tab_count
)
458 : automation_(automation
->AsWeakPtr()),
459 reply_message_(reply_message
),
460 tab_strip_model_(browser
->tab_strip_model()),
461 target_tab_count_(target_tab_count
) {
462 tab_strip_model_
->AddObserver(this);
466 TabCountChangeObserver::~TabCountChangeObserver() {
467 tab_strip_model_
->RemoveObserver(this);
470 void TabCountChangeObserver::TabInsertedAt(WebContents
* contents
,
476 void TabCountChangeObserver::TabDetachedAt(WebContents
* contents
,
481 void TabCountChangeObserver::TabStripModelDeleted() {
482 if (automation_
.get()) {
483 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
484 reply_message_
.get(), false);
485 automation_
->Send(reply_message_
.release());
491 void TabCountChangeObserver::CheckTabCount() {
492 if (tab_strip_model_
->count() != target_tab_count_
)
495 if (automation_
.get()) {
496 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
497 reply_message_
.get(), true);
498 automation_
->Send(reply_message_
.release());
504 bool DidExtensionViewsStopLoading(extensions::ProcessManager
* manager
) {
505 extensions::ProcessManager::ViewSet all_views
= manager
->GetAllViews();
506 for (extensions::ProcessManager::ViewSet::const_iterator iter
=
508 iter
!= all_views
.end(); ++iter
) {
509 if ((*iter
)->IsLoading())
515 ExtensionUninstallObserver::ExtensionUninstallObserver(
516 AutomationProvider
* automation
,
517 IPC::Message
* reply_message
,
518 const std::string
& id
)
519 : automation_(automation
->AsWeakPtr()),
520 reply_message_(reply_message
),
522 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
523 content::NotificationService::AllSources());
524 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED
,
525 content::NotificationService::AllSources());
528 ExtensionUninstallObserver::~ExtensionUninstallObserver() {
531 void ExtensionUninstallObserver::Observe(
533 const content::NotificationSource
& source
,
534 const content::NotificationDetails
& details
) {
535 if (!automation_
.get()) {
541 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
: {
542 if (id_
== content::Details
<extensions::Extension
>(details
).ptr()->id()) {
543 scoped_ptr
<base::DictionaryValue
> return_value(
544 new base::DictionaryValue
);
545 return_value
->SetBoolean("success", true);
546 AutomationJSONReply(automation_
.get(), reply_message_
.release())
547 .SendSuccess(return_value
.get());
554 case chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED
: {
555 const extensions::Extension
* extension
=
556 content::Details
<extensions::Extension
>(details
).ptr();
557 if (id_
== extension
->id()) {
558 scoped_ptr
<base::DictionaryValue
> return_value(
559 new base::DictionaryValue
);
560 return_value
->SetBoolean("success", false);
561 AutomationJSONReply(automation_
.get(), reply_message_
.release())
562 .SendSuccess(return_value
.get());
574 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
575 extensions::ProcessManager
* manager
, ExtensionService
* service
,
576 AutomationProvider
* automation
, IPC::Message
* reply_message
)
579 automation_(automation
->AsWeakPtr()),
580 reply_message_(reply_message
),
585 ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() {
588 void ExtensionReadyNotificationObserver::Init() {
589 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
590 content::NotificationService::AllSources());
591 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED
,
592 content::NotificationService::AllSources());
593 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR
,
594 content::NotificationService::AllSources());
595 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR
,
596 content::NotificationService::AllSources());
597 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED
,
598 content::NotificationService::AllSources());
601 void ExtensionReadyNotificationObserver::Observe(
602 int type
, const content::NotificationSource
& source
,
603 const content::NotificationDetails
& details
) {
604 if (!automation_
.get()) {
610 case content::NOTIFICATION_LOAD_STOP
:
611 // Only continue on with this method if our extension has been loaded
612 // and all the extension views have stopped loading.
613 if (!extension_
|| !DidExtensionViewsStopLoading(manager_
))
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
))
624 extension_
= loaded_extension
;
625 if (!DidExtensionViewsStopLoading(manager_
))
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_
))
635 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR
:
636 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR
:
637 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED
:
644 AutomationJSONReply
reply(automation_
.get(), reply_message_
.release());
646 base::DictionaryValue dict
;
647 dict
.SetString("id", extension_
->id());
648 reply
.SendSuccess(&dict
);
650 reply
.SendError("Extension could not be installed");
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;
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()) {
694 DCHECK(type
== content::NOTIFICATION_LOAD_STOP
);
698 void ExtensionsUpdatedObserver::UpdateCheckFinished() {
699 if (!automation_
.get()) {
704 // Extension updater has completed updating all extensions.
705 updater_finished_
= true;
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
);
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(
739 const content::NotificationSource
& source
,
740 const content::NotificationDetails
& details
) {
741 if (!automation_
.get()) {
746 if (type
== chrome::NOTIFICATION_BROWSER_OPENED
) {
747 // Store the new browser ID and continue waiting for a new tab within it
749 new_window_id_
= extensions::ExtensionTabUtil::GetWindowId(
750 content::Source
<Browser
>(source
).ptr());
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()
760 if (window_id
== new_window_id_
) {
761 if (use_json_interface_
) {
762 AutomationJSONReply(automation_
.get(), reply_message_
.release())
765 if (for_browser_command_
) {
766 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
767 reply_message_
.get(), true);
769 automation_
->Send(reply_message_
.release());
777 void BrowserOpenedNotificationObserver::set_for_browser_command(
778 bool for_browser_command
) {
779 for_browser_command_
= for_browser_command
;
782 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
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()) {
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())
817 if (for_browser_command_
) {
818 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_
.get(),
821 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_
.get(), true,
824 automation_
->Send(reply_message_
.release());
829 void BrowserClosedNotificationObserver::set_for_browser_command(
830 bool for_browser_command
) {
831 for_browser_command_
= for_browser_command
;
834 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
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(
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
);
867 if (!automation_
.get()) {
872 if (current_count
== target_count_
) {
873 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
874 reply_message_
.get(), true);
875 automation_
->Send(reply_message_
.release());
882 // Define mapping from command to notification
883 struct CommandNotification
{
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
},
906 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
910 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
911 AutomationProvider
* automation
,
914 IPC::Message
* reply_message
,
915 bool use_json_interface
) {
919 new NewTabObserver(automation
, reply_message
, use_json_interface
);
923 case IDC_NEW_INCOGNITO_WINDOW
: {
924 BrowserOpenedNotificationObserver
* observer
=
925 new BrowserOpenedNotificationObserver(automation
, reply_message
,
927 observer
->set_for_browser_command(true);
930 case IDC_CLOSE_WINDOW
: {
931 BrowserClosedNotificationObserver
* observer
=
932 new BrowserClosedNotificationObserver(browser
, automation
,
935 observer
->set_for_browser_command(true);
938 case IDC_CLOSE_TAB
: {
939 TabClosedNotificationObserver
* observer
=
940 new TabClosedNotificationObserver(automation
, true, reply_message
,
942 observer
->set_for_browser_command(true);
948 new NavigationNotificationObserver(
949 &browser
->tab_strip_model()->GetActiveWebContents()->GetController(),
950 automation
, reply_message
, 1, false, use_json_interface
);
954 ExecuteBrowserCommandObserver
* observer
=
955 new ExecuteBrowserCommandObserver(automation
, reply_message
,
957 if (!observer
->Register(command
)) {
958 observer
->ReleaseReply();
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())
977 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
978 reply_message_
.get(), true);
979 automation_
->Send(reply_message_
.release());
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
, ¬ification_type_
))
1001 registrar_
.Add(this, notification_type_
,
1002 content::NotificationService::AllSources());
1006 bool ExecuteBrowserCommandObserver::Getint(
1007 int command
, int* type
) {
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
;
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";
1048 if (!automation_
.get()) {
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());
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());
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();
1109 DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
, type
);
1110 WebContents
* web_contents
= content::Source
<WebContents
>(source
).ptr();
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
);
1143 AutomationMsg_DomOperation::WriteReplyParams(reply_message_
.get(), json
);
1144 automation_
->Send(reply_message_
.release());
1150 void DomOperationMessageSender::OnJavascriptBlocked() {
1151 if (automation_
.get() && use_json_interface_
) {
1152 AutomationJSONReply(automation_
.get(), reply_message_
.release())
1153 .SendError("Javascript execution was blocked");
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())
1173 void MetricEventDurationObserver::Observe(
1175 const content::NotificationSource
& source
,
1176 const content::NotificationDetails
& details
) {
1177 if (type
!= chrome::NOTIFICATION_METRIC_EVENT_DURATION
) {
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
,
1199 registrar_
.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED
,
1204 InfoBarCountObserver::~InfoBarCountObserver() {}
1206 void InfoBarCountObserver::Observe(
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
);
1215 void InfoBarCountObserver::CheckCount() {
1216 if (InfoBarService::FromWebContents(web_contents_
)->infobar_count() !=
1220 if (automation_
.get()) {
1221 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_
.get(),
1223 automation_
->Send(reply_message_
.release());
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
),
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())
1267 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1268 reply_message_
.get(), success
);
1269 automation_provider_
->Send(reply_message_
.release());
1275 AutomationProviderDownloadUpdatedObserver::
1276 AutomationProviderDownloadUpdatedObserver(
1277 AutomationProvider
* provider
,
1278 IPC::Message
* reply_message
,
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())
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());
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());
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())
1341 void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated(
1342 DownloadManager
* manager
, DownloadItem
* item
) {
1346 void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved(
1347 DownloadManager
* manager
, DownloadItem
* item
) {
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
) {
1362 if ((*it
)->GetAsInteger(&val
)) {
1363 pre_download_ids_
.insert(val
);
1365 AutomationJSONReply(provider_
.get(), reply_message_
.release())
1366 .SendError("Cannot convert ID of prior download to integer.");
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
);
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
);
1419 void AllDownloadsCompleteObserver::ReplyIfNecessary() {
1420 if (!pending_downloads_
.empty())
1423 download_manager_
->RemoveObserver(this);
1424 if (provider_
.get())
1425 AutomationJSONReply(provider_
.get(), reply_message_
.release())
1430 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver(
1431 AutomationProvider
* provider
,
1433 IPC::Message
* reply_message
)
1434 : provider_(provider
->AsWeakPtr()),
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())
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()) {
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(
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());
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())
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()) {
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());
1571 void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults(
1572 const std::vector
<autofill::PasswordForm
*>& results
) {
1573 // TODO(kaiwang): Implement when I refactor
1574 // PasswordManager::GetAutofillableLogins.
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) {
1591 PasswordStoreLoginsChangedObserver::~PasswordStoreLoginsChangedObserver() {
1592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1595 void PasswordStoreLoginsChangedObserver::Init() {
1596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1597 BrowserThread::PostTask(
1600 base::Bind(&PasswordStoreLoginsChangedObserver::RegisterObserversTask
,
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(
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(
1629 base::Bind(&PasswordStoreLoginsChangedObserver::IndicateError
, this,
1634 // Notify the UI thread that we're done listening.
1635 BrowserThread::PostTask(
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())
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());
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())
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(
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())
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())
1721 void SavePackageNotificationObserver::ManagerGoingDown(
1722 content::DownloadManager
* manager
) {
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.
1748 const char* kLaunchType
= "launch_type";
1749 if (!app_info
->GetInteger(kLaunchType
, &launch_type
)) {
1750 NOTREACHED() << "Can't get integer from key " << kLaunchType
;
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");
1762 app_info
->SetString(kLaunchType
, "unknown");
1765 apps_list
->push_back(app_info
);
1773 NTPInfoObserver::NTPInfoObserver(AutomationProvider
* automation
,
1774 IPC::Message
* reply_message
)
1775 : automation_(automation
->AsWeakPtr()),
1776 reply_message_(reply_message
),
1778 ntp_info_(new base::DictionaryValue
) {
1779 top_sites_
= automation_
->profile()->GetTopSites();
1781 AutomationJSONReply(automation_
.get(), reply_message_
.release())
1782 .SendError("Profile does not have service for querying the top sites.");
1785 TabRestoreService
* service
=
1786 TabRestoreServiceFactory::GetForProfile(automation_
->profile());
1788 AutomationJSONReply(automation_
.get(), reply_message_
.release())
1789 .SendError("No TabRestoreService.");
1793 // Collect information about the apps in the new tab page.
1794 ExtensionService
* ext_service
= extensions::ExtensionSystem::Get(
1795 automation_
->profile())->extension_service();
1797 AutomationJSONReply(automation_
.get(), reply_message_
.release())
1798 .SendError("No ExtensionService.");
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()) {
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
) {
1871 } else if (type
== chrome::NOTIFICATION_TOP_SITES_UPDATED
) {
1872 content::Details
<CancelableRequestProvider::Handle
> request_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()) {
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());
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
);
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());
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())
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())
1976 GetAllNotificationsObserver::GetAllNotificationsObserver(
1977 AutomationProvider
* automation
,
1978 IPC::Message
* reply_message
)
1979 : automation_(automation
->AsWeakPtr()),
1980 reply_message_(reply_message
) {
1981 if (AreActiveNotificationProcessesReady()) {
1984 registrar_
.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED
,
1985 content::NotificationService::AllSources());
1989 GetAllNotificationsObserver::~GetAllNotificationsObserver() {}
1991 void GetAllNotificationsObserver::Observe(
1993 const content::NotificationSource
& source
,
1994 const content::NotificationDetails
& details
) {
1995 if (!automation_
.get()) {
1999 if (AreActiveNotificationProcessesReady())
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());
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();
2024 base::DictionaryValue
* note
= NotificationToJson(
2025 &(*balloon_iter
)->notification());
2026 BalloonHost
* balloon_host
= (*balloon_iter
)->balloon_view()->GetHost();
2028 int pid
= base::GetProcId(balloon_host
->web_contents()->
2029 GetRenderViewHost()->GetProcess()->GetHandle());
2030 note
->SetInteger("pid", pid
);
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();
2039 list
->Append(NotificationToJson(*queued_iter
));
2041 AutomationJSONReply(automation_
.get(), reply_message_
.release())
2042 .SendSuccess(&return_value
);
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(
2059 const content::NotificationSource
& source
,
2060 const content::NotificationDetails
& details
) {
2061 if (automation_
.get()) {
2062 AutomationJSONReply(automation_
.get(), reply_message_
.release())
2068 OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver(
2069 AutomationProvider
* provider
,
2070 IPC::Message
* reply_message
,
2072 : automation_(provider
->AsWeakPtr()),
2073 reply_message_(reply_message
),
2074 collection_(BalloonNotificationUIManager::GetInstanceForTesting()->
2075 balloon_collection()),
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(
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())
2104 if (balloon_count_met
|| !automation_
.get()) {
2105 collection_
->set_on_collection_changed_callback(base::Closure());
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(
2123 const content::NotificationSource
& source
,
2124 const content::NotificationDetails
& details
) {
2125 if (automation_
.get()) {
2126 AutomationJSONReply(automation_
.get(), reply_message_
.release())
2132 InputEventAckNotificationObserver::InputEventAckNotificationObserver(
2133 AutomationProvider
* automation
,
2134 IPC::Message
* reply_message
,
2137 : automation_(automation
->AsWeakPtr()),
2138 reply_message_(reply_message
),
2139 event_type_(event_type
),
2144 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK
,
2145 content::NotificationService::AllSources());
2148 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN
,
2149 content::NotificationService::AllSources());
2152 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {}
2154 void InputEventAckNotificationObserver::Observe(
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())
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())
2174 LOG(WARNING
) << "Ignoring unexpected event type: "
2175 << *request_details
.ptr() << " (expected: " << event_type_
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(),
2206 new NavigationNotificationObserver(controller
,
2208 reply_message_
.release(),
2211 use_json_interface_
);
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.
2226 BrowserThread::PostTask(
2227 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
2229 &WaitForProcessLauncherThreadToGoIdleObserver::
2230 RunOnProcessLauncherThread
,
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
,
2244 &WaitForProcessLauncherThreadToGoIdleObserver::
2245 RunOnProcessLauncherThread2
,
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
,
2258 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() {
2259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
2260 if (automation_
.get())
2261 automation_
->Send(reply_message_
.release());
2265 DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver(
2266 AutomationProvider
* automation
,
2267 IPC::Message
* reply_message
)
2268 : automation_(automation
->AsWeakPtr()),
2269 reply_message_(reply_message
) {
2272 content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK
,
2273 content::NotificationService::AllSources());
2276 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN
,
2277 content::NotificationService::AllSources());
2280 DragTargetDropAckNotificationObserver::
2281 ~DragTargetDropAckNotificationObserver() {}
2283 void DragTargetDropAckNotificationObserver::Observe(
2285 const content::NotificationSource
& source
,
2286 const content::NotificationDetails
& details
) {
2287 if (automation_
.get()) {
2288 AutomationJSONReply(automation_
.get(), reply_message_
.release())
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
) {
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();
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
) {
2389 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED
,
2390 content::NotificationService::AllSources());
2393 V8HeapStatsObserver::~V8HeapStatsObserver() {}
2395 void V8HeapStatsObserver::Observe(
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
)
2407 ChromeRenderMessageFilter::V8HeapStatsDetails
* v8_heap_details
=
2408 content::Details
<ChromeRenderMessageFilter::V8HeapStatsDetails
>(details
)
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());
2424 FPSObserver::FPSObserver(
2425 AutomationProvider
* automation
,
2426 IPC::Message
* reply_message
,
2427 base::ProcessId renderer_id
,
2429 : automation_(automation
->AsWeakPtr()),
2430 reply_message_(reply_message
),
2431 renderer_id_(renderer_id
),
2432 routing_id_(routing_id
) {
2435 chrome::NOTIFICATION_RENDERER_FPS_COMPUTED
,
2436 content::NotificationService::AllSources());
2439 FPSObserver::~FPSObserver() {}
2441 void FPSObserver::Observe(
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
)
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
2457 if (routing_id_
!= fps_details
->routing_id())
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());
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(
2492 const content::NotificationSource
& source
,
2493 const content::NotificationDetails
& details
) {
2494 if (!automation_
.get()) {
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();
2504 AutomationJSONReply(automation_
.get(), reply_message_
.release())
2505 .SendError("Profile could not be created.");
2508 } else if (type
== chrome::NOTIFICATION_BROWSER_OPENED
) {
2509 // Store the new browser ID and continue waiting for a new tab within it
2511 new_window_id_
= extensions::ExtensionTabUtil::GetWindowId(
2512 content::Source
<Browser
>(source
).ptr());
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()
2522 if (window_id
== new_window_id_
) {
2523 if (automation_
.get()) {
2524 AutomationJSONReply(automation_
.get(), reply_message_
.release())
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(
2548 const content::NotificationSource
& source
,
2549 const content::NotificationDetails
& details
) {
2550 if (!automation_
.get()) {
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())
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(
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())
2589 #endif // defined(OS_LINUX)
2591 BrowserOpenedWithExistingProfileNotificationObserver::
2592 BrowserOpenedWithExistingProfileNotificationObserver(
2593 AutomationProvider
* automation
,
2594 IPC::Message
* reply_message
,
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(
2612 const content::NotificationSource
& source
,
2613 const content::NotificationDetails
& details
) {
2614 if (!automation_
.get()) {
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()
2631 if (window_id
== new_window_id_
&& --num_loads_
== 0) {
2632 if (automation_
.get()) {
2633 AutomationJSONReply(automation_
.get(), reply_message_
.release())