1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/automation/automation_provider_observers.h"
6
7 #include <deque>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/callback.h"
13 #include "base/file_util.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/string_util.h"
17 #include "base/stringprintf.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "chrome/app/chrome_command_ids.h"
22 #include "chrome/browser/automation/automation_provider.h"
23 #include "chrome/browser/automation/automation_provider_json.h"
24 #include "chrome/browser/bookmarks/bookmark_model.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/dom_operation_notification_details.h"
27 #include "chrome/browser/download/download_item.h"
28 #include "chrome/browser/download/save_package.h"
29 #include "chrome/browser/extensions/crx_installer.h"
30 #include "chrome/browser/extensions/extension_host.h"
31 #include "chrome/browser/extensions/extension_process_manager.h"
32 #include "chrome/browser/extensions/extension_tabs_module.h"
33 #include "chrome/browser/extensions/extension_updater.h"
34 #include "chrome/browser/history/top_sites.h"
35 #include "chrome/browser/metrics/metric_event_duration_details.h"
36 #include "chrome/browser/notifications/balloon.h"
37 #include "chrome/browser/notifications/balloon_collection.h"
38 #include "chrome/browser/notifications/balloon_host.h"
39 #include "chrome/browser/notifications/notification.h"
40 #include "chrome/browser/notifications/notification_ui_manager.h"
41 #include "chrome/browser/printing/print_job.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/browser/search_engines/template_url_model.h"
44 #include "chrome/browser/sessions/tab_restore_service.h"
45 #include "chrome/browser/tab_contents/thumbnail_generator.h"
46 #include "chrome/browser/translate/page_translated_details.h"
47 #include "chrome/browser/translate/translate_infobar_delegate.h"
48 #include "chrome/browser/translate/translate_tab_helper.h"
49 #include "chrome/browser/ui/browser.h"
50 #include "chrome/browser/ui/browser_list.h"
51 #include "chrome/browser/ui/find_bar/find_notification_details.h"
52 #include "chrome/browser/ui/login/login_prompt.h"
53 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
54 #include "chrome/browser/ui/webui/app_launcher_handler.h"
55 #include "chrome/browser/ui/webui/most_visited_handler.h"
56 #include "chrome/browser/ui/webui/new_tab_ui.h"
57 #include "chrome/common/automation_messages.h"
58 #include "chrome/common/extensions/extension.h"
59 #include "content/browser/renderer_host/render_process_host.h"
60 #include "content/browser/renderer_host/render_view_host.h"
61 #include "content/browser/tab_contents/navigation_controller.h"
62 #include "content/browser/tab_contents/tab_contents.h"
63 #include "content/common/notification_service.h"
64 #include "googleurl/src/gurl.h"
65 #include "ui/gfx/codec/png_codec.h"
66 #include "ui/gfx/rect.h"
67
68 // Holds onto start and stop timestamps for a particular tab
69 class InitialLoadObserver::TabTime {
70 public:
TabTime(base::TimeTicks started)71 explicit TabTime(base::TimeTicks started)
72 : load_start_time_(started) {
73 }
set_stop_time(base::TimeTicks stopped)74 void set_stop_time(base::TimeTicks stopped) {
75 load_stop_time_ = stopped;
76 }
stop_time() const77 base::TimeTicks stop_time() const {
78 return load_stop_time_;
79 }
start_time() const80 base::TimeTicks start_time() const {
81 return load_start_time_;
82 }
83 private:
84 base::TimeTicks load_start_time_;
85 base::TimeTicks load_stop_time_;
86 };
87
InitialLoadObserver(size_t tab_count,AutomationProvider * automation)88 InitialLoadObserver::InitialLoadObserver(size_t tab_count,
89 AutomationProvider* automation)
90 : automation_(automation->AsWeakPtr()),
91 outstanding_tab_count_(tab_count),
92 init_time_(base::TimeTicks::Now()) {
93 if (outstanding_tab_count_ > 0) {
94 registrar_.Add(this, NotificationType::LOAD_START,
95 NotificationService::AllSources());
96 registrar_.Add(this, NotificationType::LOAD_STOP,
97 NotificationService::AllSources());
98 }
99 }
100
~InitialLoadObserver()101 InitialLoadObserver::~InitialLoadObserver() {
102 }
103
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)104 void InitialLoadObserver::Observe(NotificationType type,
105 const NotificationSource& source,
106 const NotificationDetails& details) {
107 if (type == NotificationType::LOAD_START) {
108 if (outstanding_tab_count_ > loading_tabs_.size())
109 loading_tabs_.insert(TabTimeMap::value_type(
110 source.map_key(),
111 TabTime(base::TimeTicks::Now())));
112 } else if (type == NotificationType::LOAD_STOP) {
113 if (outstanding_tab_count_ > finished_tabs_.size()) {
114 TabTimeMap::iterator iter = loading_tabs_.find(source.map_key());
115 if (iter != loading_tabs_.end()) {
116 finished_tabs_.insert(source.map_key());
117 iter->second.set_stop_time(base::TimeTicks::Now());
118 }
119 if (outstanding_tab_count_ == finished_tabs_.size())
120 ConditionMet();
121 }
122 } else {
123 NOTREACHED();
124 }
125 }
126
GetTimingInformation() const127 DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
128 ListValue* items = new ListValue;
129 for (TabTimeMap::const_iterator it = loading_tabs_.begin();
130 it != loading_tabs_.end();
131 ++it) {
132 DictionaryValue* item = new DictionaryValue;
133 base::TimeDelta delta_start = it->second.start_time() - init_time_;
134
135 item->SetDouble("load_start_ms", delta_start.InMillisecondsF());
136 if (it->second.stop_time().is_null()) {
137 item->Set("load_stop_ms", Value::CreateNullValue());
138 } else {
139 base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
140 item->SetDouble("load_stop_ms", delta_stop.InMillisecondsF());
141 }
142 items->Append(item);
143 }
144 DictionaryValue* return_value = new DictionaryValue;
145 return_value->Set("tabs", items);
146 return return_value;
147 }
148
ConditionMet()149 void InitialLoadObserver::ConditionMet() {
150 registrar_.RemoveAll();
151 if (automation_)
152 automation_->OnInitialTabLoadsComplete();
153 }
154
NewTabUILoadObserver(AutomationProvider * automation)155 NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation)
156 : automation_(automation->AsWeakPtr()) {
157 registrar_.Add(this, NotificationType::INITIAL_NEW_TAB_UI_LOAD,
158 NotificationService::AllSources());
159 }
160
~NewTabUILoadObserver()161 NewTabUILoadObserver::~NewTabUILoadObserver() {
162 }
163
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)164 void NewTabUILoadObserver::Observe(NotificationType type,
165 const NotificationSource& source,
166 const NotificationDetails& details) {
167 if (type == NotificationType::INITIAL_NEW_TAB_UI_LOAD) {
168 Details<int> load_time(details);
169 if (automation_) {
170 automation_->Send(
171 new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr()));
172 }
173 } else {
174 NOTREACHED();
175 }
176 }
177
NavigationControllerRestoredObserver(AutomationProvider * automation,NavigationController * controller,IPC::Message * reply_message)178 NavigationControllerRestoredObserver::NavigationControllerRestoredObserver(
179 AutomationProvider* automation,
180 NavigationController* controller,
181 IPC::Message* reply_message)
182 : automation_(automation->AsWeakPtr()),
183 controller_(controller),
184 reply_message_(reply_message) {
185 if (FinishedRestoring()) {
186 SendDone();
187 } else {
188 registrar_.Add(this, NotificationType::LOAD_STOP,
189 NotificationService::AllSources());
190 }
191 }
192
~NavigationControllerRestoredObserver()193 NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() {
194 }
195
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)196 void NavigationControllerRestoredObserver::Observe(
197 NotificationType type, const NotificationSource& source,
198 const NotificationDetails& details) {
199 if (FinishedRestoring()) {
200 SendDone();
201 registrar_.RemoveAll();
202 }
203 }
204
FinishedRestoring()205 bool NavigationControllerRestoredObserver::FinishedRestoring() {
206 return (!controller_->needs_reload() && !controller_->pending_entry() &&
207 !controller_->tab_contents()->is_loading());
208 }
209
SendDone()210 void NavigationControllerRestoredObserver::SendDone() {
211 if (!automation_)
212 return;
213
214 AutomationMsg_WaitForTabToBeRestored::WriteReplyParams(reply_message_.get(),
215 true);
216 automation_->Send(reply_message_.release());
217 }
218
NavigationNotificationObserver(NavigationController * controller,AutomationProvider * automation,IPC::Message * reply_message,int number_of_navigations,bool include_current_navigation,bool use_json_interface)219 NavigationNotificationObserver::NavigationNotificationObserver(
220 NavigationController* controller,
221 AutomationProvider* automation,
222 IPC::Message* reply_message,
223 int number_of_navigations,
224 bool include_current_navigation,
225 bool use_json_interface)
226 : automation_(automation->AsWeakPtr()),
227 reply_message_(reply_message),
228 controller_(controller),
229 navigations_remaining_(number_of_navigations),
230 navigation_started_(false),
231 use_json_interface_(use_json_interface) {
232 DCHECK_LT(0, navigations_remaining_);
233 Source<NavigationController> source(controller_);
234 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, source);
235 registrar_.Add(this, NotificationType::LOAD_START, source);
236 registrar_.Add(this, NotificationType::LOAD_STOP, source);
237 registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
238 registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source);
239 registrar_.Add(this, NotificationType::AUTH_CANCELLED, source);
240
241 if (include_current_navigation && controller->tab_contents()->is_loading())
242 navigation_started_ = true;
243 }
244
~NavigationNotificationObserver()245 NavigationNotificationObserver::~NavigationNotificationObserver() {
246 }
247
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)248 void NavigationNotificationObserver::Observe(
249 NotificationType type, const NotificationSource& source,
250 const NotificationDetails& details) {
251 if (!automation_) {
252 delete this;
253 return;
254 }
255
256 // We listen for 2 events to determine when the navigation started because:
257 // - when this is used by the WaitForNavigation method, we might be invoked
258 // afer the load has started (but not after the entry was committed, as
259 // WaitForNavigation compares times of the last navigation).
260 // - when this is used with a page requiring authentication, we will not get
261 // a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so
262 // we need the NotificationType::LOAD_START.
263 if (type == NotificationType::NAV_ENTRY_COMMITTED ||
264 type == NotificationType::LOAD_START) {
265 navigation_started_ = true;
266 } else if (type == NotificationType::LOAD_STOP) {
267 if (navigation_started_) {
268 navigation_started_ = false;
269 if (--navigations_remaining_ == 0)
270 ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
271 }
272 } else if (type == NotificationType::AUTH_SUPPLIED ||
273 type == NotificationType::AUTH_CANCELLED) {
274 // The LoginHandler for this tab is no longer valid.
275 automation_->RemoveLoginHandler(controller_);
276
277 // Treat this as if navigation started again, since load start/stop don't
278 // occur while authentication is ongoing.
279 navigation_started_ = true;
280 } else if (type == NotificationType::AUTH_NEEDED) {
281 // Remember the login handler that wants authentication.
282 // We do this in all cases (not just when navigation_started_ == true) so
283 // tests can still wait for auth dialogs outside of navigation.
284 LoginHandler* handler =
285 Details<LoginNotificationDetails>(details)->handler();
286 automation_->AddLoginHandler(controller_, handler);
287
288 // Respond that authentication is needed.
289 navigation_started_ = false;
290 ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
291 } else {
292 NOTREACHED();
293 }
294 }
295
ConditionMet(AutomationMsg_NavigationResponseValues navigation_result)296 void NavigationNotificationObserver::ConditionMet(
297 AutomationMsg_NavigationResponseValues navigation_result) {
298 if (automation_) {
299 if (use_json_interface_) {
300 DictionaryValue dict;
301 dict.SetInteger("result", navigation_result);
302 AutomationJSONReply(automation_, reply_message_.release())
303 .SendSuccess(&dict);
304 } else {
305 IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::Write(
306 reply_message_.get(), navigation_result);
307 automation_->Send(reply_message_.release());
308 }
309 }
310
311 delete this;
312 }
313
TabStripNotificationObserver(NotificationType notification,AutomationProvider * automation)314 TabStripNotificationObserver::TabStripNotificationObserver(
315 NotificationType notification, AutomationProvider* automation)
316 : automation_(automation->AsWeakPtr()),
317 notification_(notification) {
318 registrar_.Add(this, notification_, NotificationService::AllSources());
319 }
320
~TabStripNotificationObserver()321 TabStripNotificationObserver::~TabStripNotificationObserver() {
322 }
323
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)324 void TabStripNotificationObserver::Observe(NotificationType type,
325 const NotificationSource& source,
326 const NotificationDetails& details) {
327 if (type == notification_) {
328 ObserveTab(Source<NavigationController>(source).ptr());
329 delete this;
330 } else {
331 NOTREACHED();
332 }
333 }
334
TabAppendedNotificationObserver(Browser * parent,AutomationProvider * automation,IPC::Message * reply_message)335 TabAppendedNotificationObserver::TabAppendedNotificationObserver(
336 Browser* parent, AutomationProvider* automation,
337 IPC::Message* reply_message)
338 : TabStripNotificationObserver(NotificationType::TAB_PARENTED, automation),
339 parent_(parent),
340 reply_message_(reply_message) {
341 }
342
~TabAppendedNotificationObserver()343 TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {}
344
ObserveTab(NavigationController * controller)345 void TabAppendedNotificationObserver::ObserveTab(
346 NavigationController* controller) {
347 if (!automation_)
348 return;
349
350 if (automation_->GetIndexForNavigationController(controller, parent_) ==
351 TabStripModel::kNoTab) {
352 // This tab notification doesn't belong to the parent_.
353 return;
354 }
355
356 new NavigationNotificationObserver(controller, automation_,
357 reply_message_.release(),
358 1, false, false);
359 }
360
TabClosedNotificationObserver(AutomationProvider * automation,bool wait_until_closed,IPC::Message * reply_message)361 TabClosedNotificationObserver::TabClosedNotificationObserver(
362 AutomationProvider* automation, bool wait_until_closed,
363 IPC::Message* reply_message)
364 : TabStripNotificationObserver(wait_until_closed ?
365 NotificationType::TAB_CLOSED : NotificationType::TAB_CLOSING,
366 automation),
367 reply_message_(reply_message),
368 for_browser_command_(false) {
369 }
370
~TabClosedNotificationObserver()371 TabClosedNotificationObserver::~TabClosedNotificationObserver() {}
372
ObserveTab(NavigationController * controller)373 void TabClosedNotificationObserver::ObserveTab(
374 NavigationController* controller) {
375 if (!automation_)
376 return;
377
378 if (for_browser_command_) {
379 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
380 true);
381 } else {
382 AutomationMsg_CloseTab::WriteReplyParams(reply_message_.get(), true);
383 }
384 automation_->Send(reply_message_.release());
385 }
386
set_for_browser_command(bool for_browser_command)387 void TabClosedNotificationObserver::set_for_browser_command(
388 bool for_browser_command) {
389 for_browser_command_ = for_browser_command;
390 }
391
TabCountChangeObserver(AutomationProvider * automation,Browser * browser,IPC::Message * reply_message,int target_tab_count)392 TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation,
393 Browser* browser,
394 IPC::Message* reply_message,
395 int target_tab_count)
396 : automation_(automation->AsWeakPtr()),
397 reply_message_(reply_message),
398 tab_strip_model_(browser->tabstrip_model()),
399 target_tab_count_(target_tab_count) {
400 tab_strip_model_->AddObserver(this);
401 CheckTabCount();
402 }
403
~TabCountChangeObserver()404 TabCountChangeObserver::~TabCountChangeObserver() {
405 tab_strip_model_->RemoveObserver(this);
406 }
407
TabInsertedAt(TabContentsWrapper * contents,int index,bool foreground)408 void TabCountChangeObserver::TabInsertedAt(TabContentsWrapper* contents,
409 int index,
410 bool foreground) {
411 CheckTabCount();
412 }
413
TabDetachedAt(TabContentsWrapper * contents,int index)414 void TabCountChangeObserver::TabDetachedAt(TabContentsWrapper* contents,
415 int index) {
416 CheckTabCount();
417 }
418
TabStripModelDeleted()419 void TabCountChangeObserver::TabStripModelDeleted() {
420 if (automation_) {
421 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
422 reply_message_.get(), false);
423 automation_->Send(reply_message_.release());
424 }
425
426 delete this;
427 }
428
CheckTabCount()429 void TabCountChangeObserver::CheckTabCount() {
430 if (tab_strip_model_->count() != target_tab_count_)
431 return;
432
433 if (automation_) {
434 AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(
435 reply_message_.get(), true);
436 automation_->Send(reply_message_.release());
437 }
438
439 delete this;
440 }
441
DidExtensionHostsStopLoading(ExtensionProcessManager * manager)442 bool DidExtensionHostsStopLoading(ExtensionProcessManager* manager) {
443 for (ExtensionProcessManager::const_iterator iter = manager->begin();
444 iter != manager->end(); ++iter) {
445 if (!(*iter)->did_stop_loading())
446 return false;
447 }
448 return true;
449 }
450
ExtensionInstallNotificationObserver(AutomationProvider * automation,int id,IPC::Message * reply_message)451 ExtensionInstallNotificationObserver::ExtensionInstallNotificationObserver(
452 AutomationProvider* automation, int id, IPC::Message* reply_message)
453 : automation_(automation->AsWeakPtr()),
454 id_(id),
455 reply_message_(reply_message) {
456 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
457 NotificationService::AllSources());
458 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR,
459 NotificationService::AllSources());
460 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
461 NotificationService::AllSources());
462 }
463
~ExtensionInstallNotificationObserver()464 ExtensionInstallNotificationObserver::~ExtensionInstallNotificationObserver() {
465 }
466
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)467 void ExtensionInstallNotificationObserver::Observe(
468 NotificationType type, const NotificationSource& source,
469 const NotificationDetails& details) {
470 switch (type.value) {
471 case NotificationType::EXTENSION_LOADED:
472 SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED);
473 break;
474 case NotificationType::EXTENSION_INSTALL_ERROR:
475 case NotificationType::EXTENSION_UPDATE_DISABLED:
476 SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
477 break;
478 default:
479 NOTREACHED();
480 break;
481 }
482
483 delete this;
484 }
485
SendResponse(AutomationMsg_ExtensionResponseValues response)486 void ExtensionInstallNotificationObserver::SendResponse(
487 AutomationMsg_ExtensionResponseValues response) {
488 if (!automation_ || !reply_message_.get()) {
489 delete this;
490 return;
491 }
492
493 switch (id_) {
494 case AutomationMsg_InstallExtension::ID:
495 AutomationMsg_InstallExtension::WriteReplyParams(reply_message_.get(),
496 response);
497 break;
498 default:
499 NOTREACHED();
500 break;
501 }
502
503 automation_->Send(reply_message_.release());
504 }
505
ExtensionUninstallObserver(AutomationProvider * automation,IPC::Message * reply_message,const std::string & id)506 ExtensionUninstallObserver::ExtensionUninstallObserver(
507 AutomationProvider* automation,
508 IPC::Message* reply_message,
509 const std::string& id)
510 : automation_(automation->AsWeakPtr()),
511 reply_message_(reply_message),
512 id_(id) {
513 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
514 NotificationService::AllSources());
515 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED,
516 NotificationService::AllSources());
517 }
518
~ExtensionUninstallObserver()519 ExtensionUninstallObserver::~ExtensionUninstallObserver() {
520 }
521
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)522 void ExtensionUninstallObserver::Observe(
523 NotificationType type,
524 const NotificationSource& source,
525 const NotificationDetails& details) {
526 if (!automation_) {
527 delete this;
528 return;
529 }
530
531 switch (type.value) {
532 case NotificationType::EXTENSION_UNINSTALLED: {
533 UninstalledExtensionInfo* info =
534 Details<UninstalledExtensionInfo>(details).ptr();
535 if (id_ == info->extension_id) {
536 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
537 return_value->SetBoolean("success", true);
538 AutomationJSONReply(automation_, reply_message_.release())
539 .SendSuccess(return_value.get());
540 delete this;
541 return;
542 }
543 break;
544 }
545
546 case NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED: {
547 const Extension* extension = Details<Extension>(details).ptr();
548 if (id_ == extension->id()) {
549 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
550 return_value->SetBoolean("success", false);
551 AutomationJSONReply(automation_, reply_message_.release())
552 .SendSuccess(return_value.get());
553 delete this;
554 return;
555 }
556 break;
557 }
558
559 default:
560 NOTREACHED();
561 }
562 }
563
ExtensionReadyNotificationObserver(ExtensionProcessManager * manager,AutomationProvider * automation,int id,IPC::Message * reply_message)564 ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
565 ExtensionProcessManager* manager, AutomationProvider* automation, int id,
566 IPC::Message* reply_message)
567 : manager_(manager),
568 automation_(automation->AsWeakPtr()),
569 id_(id),
570 reply_message_(reply_message),
571 extension_(NULL) {
572 registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
573 NotificationService::AllSources());
574 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
575 NotificationService::AllSources());
576 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR,
577 NotificationService::AllSources());
578 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
579 NotificationService::AllSources());
580 }
581
~ExtensionReadyNotificationObserver()582 ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() {
583 }
584
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)585 void ExtensionReadyNotificationObserver::Observe(
586 NotificationType type, const NotificationSource& source,
587 const NotificationDetails& details) {
588 if (!automation_) {
589 delete this;
590 return;
591 }
592
593 bool success = false;
594 switch (type.value) {
595 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
596 // Only continue on with this method if our extension has been loaded
597 // and all the extension hosts have stopped loading.
598 if (!extension_ || !DidExtensionHostsStopLoading(manager_))
599 return;
600 success = true;
601 break;
602 case NotificationType::EXTENSION_LOADED:
603 extension_ = Details<const Extension>(details).ptr();
604 if (!DidExtensionHostsStopLoading(manager_))
605 return;
606 success = true;
607 break;
608 case NotificationType::EXTENSION_INSTALL_ERROR:
609 case NotificationType::EXTENSION_UPDATE_DISABLED:
610 success = false;
611 break;
612 default:
613 NOTREACHED();
614 break;
615 }
616
617 if (id_ == AutomationMsg_InstallExtensionAndGetHandle::ID) {
618 // A handle of zero indicates an error.
619 int extension_handle = 0;
620 if (extension_)
621 extension_handle = automation_->AddExtension(extension_);
622 AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams(
623 reply_message_.get(), extension_handle);
624 } else if (id_ == AutomationMsg_EnableExtension::ID) {
625 AutomationMsg_EnableExtension::WriteReplyParams(reply_message_.get(), true);
626 } else {
627 NOTREACHED();
628 LOG(ERROR) << "Cannot write reply params for unknown message id.";
629 }
630
631 automation_->Send(reply_message_.release());
632 delete this;
633 }
634
ExtensionUnloadNotificationObserver()635 ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
636 : did_receive_unload_notification_(false) {
637 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
638 NotificationService::AllSources());
639 }
640
~ExtensionUnloadNotificationObserver()641 ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
642 }
643
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)644 void ExtensionUnloadNotificationObserver::Observe(
645 NotificationType type, const NotificationSource& source,
646 const NotificationDetails& details) {
647 if (type.value == NotificationType::EXTENSION_UNLOADED) {
648 did_receive_unload_notification_ = true;
649 } else {
650 NOTREACHED();
651 }
652 }
653
ExtensionsUpdatedObserver(ExtensionProcessManager * manager,AutomationProvider * automation,IPC::Message * reply_message)654 ExtensionsUpdatedObserver::ExtensionsUpdatedObserver(
655 ExtensionProcessManager* manager, AutomationProvider* automation,
656 IPC::Message* reply_message)
657 : manager_(manager), automation_(automation->AsWeakPtr()),
658 reply_message_(reply_message), updater_finished_(false) {
659 registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
660 NotificationService::AllSources());
661 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR,
662 NotificationService::AllSources());
663 registrar_.Add(this, NotificationType::EXTENSION_INSTALL_NOT_ALLOWED,
664 NotificationService::AllSources());
665 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
666 NotificationService::AllSources());
667 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
668 NotificationService::AllSources());
669 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_FOUND,
670 NotificationService::AllSources());
671 registrar_.Add(this, NotificationType::EXTENSION_UPDATING_FINISHED,
672 NotificationService::AllSources());
673 }
674
~ExtensionsUpdatedObserver()675 ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() {
676 }
677
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)678 void ExtensionsUpdatedObserver::Observe(
679 NotificationType type, const NotificationSource& source,
680 const NotificationDetails& details) {
681 if (!automation_) {
682 delete this;
683 return;
684 }
685
686 // We expect the following sequence of events. First, the ExtensionUpdater
687 // service notifies of each extension that needs to be updated. Once the
688 // ExtensionUpdater has finished searching for extensions to update, it
689 // notifies that it is finished. Meanwhile, the extensions are updated
690 // asynchronously: either they will be updated and loaded, or else they will
691 // not load due to (1) not being allowed; (2) having updating disabled; or
692 // (3) encountering an error. Finally, notifications are also sent whenever
693 // an extension host stops loading. Updating is not considered complete if
694 // any extension hosts are still loading.
695 switch (type.value) {
696 case NotificationType::EXTENSION_UPDATE_FOUND:
697 // Extension updater has identified an extension that needs to be updated.
698 in_progress_updates_.insert(*(Details<const std::string>(details).ptr()));
699 break;
700
701 case NotificationType::EXTENSION_UPDATING_FINISHED:
702 // Extension updater has completed notifying all extensions to update
703 // themselves.
704 updater_finished_ = true;
705 break;
706
707 case NotificationType::EXTENSION_LOADED:
708 case NotificationType::EXTENSION_INSTALL_NOT_ALLOWED:
709 case NotificationType::EXTENSION_UPDATE_DISABLED: {
710 // An extension has either completed update installation and is now
711 // loaded, or else the install has been skipped because it is
712 // either not allowed or else has been disabled.
713 const Extension* extension = Details<Extension>(details).ptr();
714 in_progress_updates_.erase(extension->id());
715 break;
716 }
717
718 case NotificationType::EXTENSION_INSTALL_ERROR: {
719 // An extension had an error on update installation.
720 CrxInstaller* installer = Source<CrxInstaller>(source).ptr();
721 in_progress_updates_.erase(installer->expected_id());
722 break;
723 }
724
725 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
726 // Break out to the conditional check below to see if all extension hosts
727 // have stopped loading.
728 break;
729
730 default:
731 NOTREACHED();
732 break;
733 }
734
735 // Send the reply if (1) the extension updater has finished notifying all
736 // extensions to update themselves; (2) all extensions that need to be updated
737 // have completed installation and are now loaded; and (3) all extension hosts
738 // have stopped loading.
739 if (updater_finished_ && in_progress_updates_.empty() &&
740 DidExtensionHostsStopLoading(manager_)) {
741 AutomationJSONReply reply(automation_, reply_message_.release());
742 reply.SendSuccess(NULL);
743 delete this;
744 }
745 }
746
747 ExtensionTestResultNotificationObserver::
ExtensionTestResultNotificationObserver(AutomationProvider * automation)748 ExtensionTestResultNotificationObserver(AutomationProvider* automation)
749 : automation_(automation->AsWeakPtr()) {
750 registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
751 NotificationService::AllSources());
752 registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
753 NotificationService::AllSources());
754 }
755
756 ExtensionTestResultNotificationObserver::
~ExtensionTestResultNotificationObserver()757 ~ExtensionTestResultNotificationObserver() {
758 }
759
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)760 void ExtensionTestResultNotificationObserver::Observe(
761 NotificationType type, const NotificationSource& source,
762 const NotificationDetails& details) {
763 switch (type.value) {
764 case NotificationType::EXTENSION_TEST_PASSED:
765 results_.push_back(true);
766 messages_.push_back("");
767 break;
768
769 case NotificationType::EXTENSION_TEST_FAILED:
770 results_.push_back(false);
771 messages_.push_back(*(Details<std::string>(details).ptr()));
772 break;
773
774 default:
775 NOTREACHED();
776 }
777 // There may be a reply message waiting for this event, so check.
778 MaybeSendResult();
779 }
780
MaybeSendResult()781 void ExtensionTestResultNotificationObserver::MaybeSendResult() {
782 if (!automation_)
783 return;
784
785 if (!results_.empty()) {
786 // This release method should return the automation's current
787 // reply message, or NULL if there is no current one. If it is not
788 // NULL, we are stating that we will handle this reply message.
789 IPC::Message* reply_message = automation_->reply_message_release();
790 // Send the result back if we have a reply message.
791 if (reply_message) {
792 AutomationMsg_WaitForExtensionTestResult::WriteReplyParams(
793 reply_message, results_.front(), messages_.front());
794 results_.pop_front();
795 messages_.pop_front();
796 automation_->Send(reply_message);
797 }
798 }
799 }
800
BrowserOpenedNotificationObserver(AutomationProvider * automation,IPC::Message * reply_message)801 BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver(
802 AutomationProvider* automation,
803 IPC::Message* reply_message)
804 : automation_(automation->AsWeakPtr()),
805 reply_message_(reply_message),
806 new_window_id_(extension_misc::kUnknownWindowId),
807 for_browser_command_(false) {
808 registrar_.Add(this, NotificationType::BROWSER_OPENED,
809 NotificationService::AllSources());
810 registrar_.Add(this, NotificationType::LOAD_STOP,
811 NotificationService::AllSources());
812 }
813
~BrowserOpenedNotificationObserver()814 BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() {
815 }
816
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)817 void BrowserOpenedNotificationObserver::Observe(
818 NotificationType type, const NotificationSource& source,
819 const NotificationDetails& details) {
820 if (!automation_) {
821 delete this;
822 return;
823 }
824
825 if (type.value == NotificationType::BROWSER_OPENED) {
826 // Store the new browser ID and continue waiting for a new tab within it
827 // to stop loading.
828 new_window_id_ = ExtensionTabUtil::GetWindowId(
829 Source<Browser>(source).ptr());
830 } else if (type.value == NotificationType::LOAD_STOP) {
831 // Only send the result if the loaded tab is in the new window.
832 int window_id = Source<NavigationController>(source)->window_id().id();
833 if (window_id == new_window_id_) {
834 if (for_browser_command_) {
835 AutomationMsg_WindowExecuteCommand::WriteReplyParams(
836 reply_message_.get(), true);
837 }
838 automation_->Send(reply_message_.release());
839 delete this;
840 return;
841 }
842 } else {
843 NOTREACHED();
844 }
845 }
846
set_for_browser_command(bool for_browser_command)847 void BrowserOpenedNotificationObserver::set_for_browser_command(
848 bool for_browser_command) {
849 for_browser_command_ = for_browser_command;
850 }
851
BrowserClosedNotificationObserver(Browser * browser,AutomationProvider * automation,IPC::Message * reply_message)852 BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
853 Browser* browser,
854 AutomationProvider* automation,
855 IPC::Message* reply_message)
856 : automation_(automation->AsWeakPtr()),
857 reply_message_(reply_message),
858 for_browser_command_(false) {
859 registrar_.Add(this, NotificationType::BROWSER_CLOSED,
860 Source<Browser>(browser));
861 }
862
~BrowserClosedNotificationObserver()863 BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {}
864
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)865 void BrowserClosedNotificationObserver::Observe(
866 NotificationType type, const NotificationSource& source,
867 const NotificationDetails& details) {
868 DCHECK(type == NotificationType::BROWSER_CLOSED);
869
870 if (!automation_) {
871 delete this;
872 return;
873 }
874
875 Details<bool> close_app(details);
876
877 if (for_browser_command_) {
878 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
879 true);
880 } else {
881 AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true,
882 *(close_app.ptr()));
883 }
884 automation_->Send(reply_message_.release());
885 delete this;
886 }
887
set_for_browser_command(bool for_browser_command)888 void BrowserClosedNotificationObserver::set_for_browser_command(
889 bool for_browser_command) {
890 for_browser_command_ = for_browser_command;
891 }
892
BrowserCountChangeNotificationObserver(int target_count,AutomationProvider * automation,IPC::Message * reply_message)893 BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
894 int target_count,
895 AutomationProvider* automation,
896 IPC::Message* reply_message)
897 : target_count_(target_count),
898 automation_(automation->AsWeakPtr()),
899 reply_message_(reply_message) {
900 registrar_.Add(this, NotificationType::BROWSER_OPENED,
901 NotificationService::AllSources());
902 registrar_.Add(this, NotificationType::BROWSER_CLOSED,
903 NotificationService::AllSources());
904 }
905
906 BrowserCountChangeNotificationObserver::
~BrowserCountChangeNotificationObserver()907 ~BrowserCountChangeNotificationObserver() {}
908
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)909 void BrowserCountChangeNotificationObserver::Observe(
910 NotificationType type,
911 const NotificationSource& source,
912 const NotificationDetails& details) {
913 DCHECK(type == NotificationType::BROWSER_OPENED ||
914 type == NotificationType::BROWSER_CLOSED);
915 int current_count = static_cast<int>(BrowserList::size());
916 if (type == NotificationType::BROWSER_CLOSED) {
917 // At the time of the notification the browser being closed is not removed
918 // from the list. The real count is one less than the reported count.
919 DCHECK_LT(0, current_count);
920 current_count--;
921 }
922
923 if (!automation_) {
924 delete this;
925 return;
926 }
927
928 if (current_count == target_count_) {
929 AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
930 reply_message_.get(), true);
931 automation_->Send(reply_message_.release());
932 delete this;
933 }
934 }
935
AppModalDialogShownObserver(AutomationProvider * automation,IPC::Message * reply_message)936 AppModalDialogShownObserver::AppModalDialogShownObserver(
937 AutomationProvider* automation, IPC::Message* reply_message)
938 : automation_(automation->AsWeakPtr()),
939 reply_message_(reply_message) {
940 registrar_.Add(this, NotificationType::APP_MODAL_DIALOG_SHOWN,
941 NotificationService::AllSources());
942 }
943
~AppModalDialogShownObserver()944 AppModalDialogShownObserver::~AppModalDialogShownObserver() {
945 }
946
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)947 void AppModalDialogShownObserver::Observe(
948 NotificationType type, const NotificationSource& source,
949 const NotificationDetails& details) {
950 DCHECK(type == NotificationType::APP_MODAL_DIALOG_SHOWN);
951
952 if (automation_) {
953 AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
954 reply_message_.get(), true);
955 automation_->Send(reply_message_.release());
956 }
957 delete this;
958 }
959
960 namespace {
961
962 // Define mapping from command to notification
963 struct CommandNotification {
964 int command;
965 NotificationType::Type notification_type;
966 };
967
968 const struct CommandNotification command_notifications[] = {
969 {IDC_DUPLICATE_TAB, NotificationType::TAB_PARENTED},
970
971 // Returns as soon as the restored tab is created. To further wait until
972 // the content page is loaded, use WaitForTabToBeRestored.
973 {IDC_RESTORE_TAB, NotificationType::TAB_PARENTED},
974
975 // For the following commands, we need to wait for a new tab to be created,
976 // load to finish, and title to change.
977 {IDC_MANAGE_EXTENSIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
978 {IDC_OPTIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
979 {IDC_PRINT, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
980 {IDC_SHOW_DOWNLOADS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
981 {IDC_SHOW_HISTORY, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
982 };
983
984 } // namespace
985
~ExecuteBrowserCommandObserver()986 ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
987 }
988
989 // static
CreateAndRegisterObserver(AutomationProvider * automation,Browser * browser,int command,IPC::Message * reply_message)990 bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
991 AutomationProvider* automation, Browser* browser, int command,
992 IPC::Message* reply_message) {
993 bool result = true;
994 switch (command) {
995 case IDC_NEW_TAB: {
996 new NewTabObserver(automation, reply_message);
997 break;
998 }
999 case IDC_NEW_WINDOW:
1000 case IDC_NEW_INCOGNITO_WINDOW: {
1001 BrowserOpenedNotificationObserver* observer =
1002 new BrowserOpenedNotificationObserver(automation, reply_message);
1003 observer->set_for_browser_command(true);
1004 break;
1005 }
1006 case IDC_CLOSE_WINDOW: {
1007 BrowserClosedNotificationObserver* observer =
1008 new BrowserClosedNotificationObserver(browser, automation,
1009 reply_message);
1010 observer->set_for_browser_command(true);
1011 break;
1012 }
1013 case IDC_CLOSE_TAB: {
1014 TabClosedNotificationObserver* observer =
1015 new TabClosedNotificationObserver(automation, true, reply_message);
1016 observer->set_for_browser_command(true);
1017 break;
1018 }
1019 case IDC_BACK:
1020 case IDC_FORWARD:
1021 case IDC_RELOAD: {
1022 new NavigationNotificationObserver(
1023 &browser->GetSelectedTabContents()->controller(),
1024 automation, reply_message, 1, false, false);
1025 break;
1026 }
1027 default: {
1028 ExecuteBrowserCommandObserver* observer =
1029 new ExecuteBrowserCommandObserver(automation, reply_message);
1030 if (!observer->Register(command)) {
1031 delete observer;
1032 result = false;
1033 }
1034 break;
1035 }
1036 }
1037 return result;
1038 }
1039
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1040 void ExecuteBrowserCommandObserver::Observe(
1041 NotificationType type, const NotificationSource& source,
1042 const NotificationDetails& details) {
1043 if (type == notification_type_) {
1044 if (automation_) {
1045 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
1046 true);
1047 automation_->Send(reply_message_.release());
1048 }
1049 delete this;
1050 } else {
1051 NOTREACHED();
1052 }
1053 }
1054
ExecuteBrowserCommandObserver(AutomationProvider * automation,IPC::Message * reply_message)1055 ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
1056 AutomationProvider* automation, IPC::Message* reply_message)
1057 : automation_(automation->AsWeakPtr()),
1058 notification_type_(NotificationType::ALL),
1059 reply_message_(reply_message) {
1060 }
1061
Register(int command)1062 bool ExecuteBrowserCommandObserver::Register(int command) {
1063 if (!GetNotificationType(command, ¬ification_type_))
1064 return false;
1065 registrar_.Add(this, notification_type_, NotificationService::AllSources());
1066 return true;
1067 }
1068
GetNotificationType(int command,NotificationType::Type * type)1069 bool ExecuteBrowserCommandObserver::GetNotificationType(
1070 int command, NotificationType::Type* type) {
1071 if (!type)
1072 return false;
1073 bool found = false;
1074 for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
1075 if (command_notifications[i].command == command) {
1076 *type = command_notifications[i].notification_type;
1077 found = true;
1078 break;
1079 }
1080 }
1081 return found;
1082 }
1083
FindInPageNotificationObserver(AutomationProvider * automation,TabContents * parent_tab,bool reply_with_json,IPC::Message * reply_message)1084 FindInPageNotificationObserver::FindInPageNotificationObserver(
1085 AutomationProvider* automation, TabContents* parent_tab,
1086 bool reply_with_json, IPC::Message* reply_message)
1087 : automation_(automation->AsWeakPtr()),
1088 active_match_ordinal_(-1),
1089 reply_with_json_(reply_with_json),
1090 reply_message_(reply_message) {
1091 registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE,
1092 Source<TabContents>(parent_tab));
1093 }
1094
~FindInPageNotificationObserver()1095 FindInPageNotificationObserver::~FindInPageNotificationObserver() {
1096 }
1097
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1098 void FindInPageNotificationObserver::Observe(
1099 NotificationType type, const NotificationSource& source,
1100 const NotificationDetails& details) {
1101 Details<FindNotificationDetails> find_details(details);
1102 if (!(find_details->final_update() && reply_message_ != NULL)) {
1103 DVLOG(1) << "Ignoring, since we only care about the final message";
1104 return;
1105 }
1106
1107 if (!automation_) {
1108 delete this;
1109 return;
1110 }
1111
1112 // We get multiple responses and one of those will contain the ordinal.
1113 // This message comes to us before the final update is sent.
1114 if (find_details->request_id() == kFindInPageRequestId) {
1115 if (reply_with_json_) {
1116 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1117 return_value->SetInteger("match_count",
1118 find_details->number_of_matches());
1119 gfx::Rect rect = find_details->selection_rect();
1120 // If MatchCount is > 0, then rect should not be Empty.
1121 // We dont guard it here because we want to let the test
1122 // code catch this invalid case if needed.
1123 if (!rect.IsEmpty()) {
1124 return_value->SetInteger("match_left", rect.x());
1125 return_value->SetInteger("match_top", rect.y());
1126 return_value->SetInteger("match_right", rect.right());
1127 return_value->SetInteger("match_bottom", rect.bottom());
1128 }
1129 AutomationJSONReply(automation_, reply_message_.release())
1130 .SendSuccess(return_value.get());
1131 delete this;
1132 } else {
1133 if (find_details->active_match_ordinal() > -1) {
1134 active_match_ordinal_ = find_details->active_match_ordinal();
1135 AutomationMsg_Find::WriteReplyParams(reply_message_.get(),
1136 active_match_ordinal_, find_details->number_of_matches());
1137 automation_->Send(reply_message_.release());
1138 }
1139 }
1140 }
1141 }
1142
1143 // static
1144 const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
1145
DomOperationObserver()1146 DomOperationObserver::DomOperationObserver() {
1147 registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
1148 NotificationService::AllSources());
1149 }
1150
~DomOperationObserver()1151 DomOperationObserver::~DomOperationObserver() {}
1152
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1153 void DomOperationObserver::Observe(
1154 NotificationType type, const NotificationSource& source,
1155 const NotificationDetails& details) {
1156 if (NotificationType::DOM_OPERATION_RESPONSE == type) {
1157 Details<DomOperationNotificationDetails> dom_op_details(details);
1158 OnDomOperationCompleted(dom_op_details->json());
1159 }
1160 }
1161
DomOperationMessageSender(AutomationProvider * automation,IPC::Message * reply_message,bool use_json_interface)1162 DomOperationMessageSender::DomOperationMessageSender(
1163 AutomationProvider* automation,
1164 IPC::Message* reply_message,
1165 bool use_json_interface)
1166 : automation_(automation->AsWeakPtr()),
1167 reply_message_(reply_message),
1168 use_json_interface_(use_json_interface) {
1169 }
1170
~DomOperationMessageSender()1171 DomOperationMessageSender::~DomOperationMessageSender() {}
1172
OnDomOperationCompleted(const std::string & json)1173 void DomOperationMessageSender::OnDomOperationCompleted(
1174 const std::string& json) {
1175 if (automation_) {
1176 if (use_json_interface_) {
1177 DictionaryValue dict;
1178 dict.SetString("result", json);
1179 AutomationJSONReply(automation_, reply_message_.release())
1180 .SendSuccess(&dict);
1181 } else {
1182 AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json);
1183 automation_->Send(reply_message_.release());
1184 }
1185 }
1186 delete this;
1187 }
1188
DocumentPrintedNotificationObserver(AutomationProvider * automation,IPC::Message * reply_message)1189 DocumentPrintedNotificationObserver::DocumentPrintedNotificationObserver(
1190 AutomationProvider* automation, IPC::Message* reply_message)
1191 : automation_(automation->AsWeakPtr()),
1192 success_(false),
1193 reply_message_(reply_message) {
1194 registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
1195 NotificationService::AllSources());
1196 }
1197
~DocumentPrintedNotificationObserver()1198 DocumentPrintedNotificationObserver::~DocumentPrintedNotificationObserver() {
1199 if (automation_) {
1200 AutomationMsg_PrintNow::WriteReplyParams(reply_message_.get(), success_);
1201 automation_->Send(reply_message_.release());
1202 }
1203 }
1204
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1205 void DocumentPrintedNotificationObserver::Observe(
1206 NotificationType type, const NotificationSource& source,
1207 const NotificationDetails& details) {
1208 using namespace printing;
1209 DCHECK(type == NotificationType::PRINT_JOB_EVENT);
1210 switch (Details<JobEventDetails>(details)->type()) {
1211 case JobEventDetails::JOB_DONE: {
1212 // Succeeded.
1213 success_ = true;
1214 delete this;
1215 break;
1216 }
1217 case JobEventDetails::USER_INIT_CANCELED:
1218 case JobEventDetails::FAILED: {
1219 // Failed.
1220 delete this;
1221 break;
1222 }
1223 case JobEventDetails::NEW_DOC:
1224 case JobEventDetails::USER_INIT_DONE:
1225 case JobEventDetails::DEFAULT_INIT_DONE:
1226 case JobEventDetails::NEW_PAGE:
1227 case JobEventDetails::PAGE_DONE:
1228 case JobEventDetails::DOC_DONE:
1229 case JobEventDetails::ALL_PAGES_REQUESTED: {
1230 // Don't care.
1231 break;
1232 }
1233 default: {
1234 NOTREACHED();
1235 break;
1236 }
1237 }
1238 }
1239
MetricEventDurationObserver()1240 MetricEventDurationObserver::MetricEventDurationObserver() {
1241 registrar_.Add(this, NotificationType::METRIC_EVENT_DURATION,
1242 NotificationService::AllSources());
1243 }
1244
~MetricEventDurationObserver()1245 MetricEventDurationObserver::~MetricEventDurationObserver() {}
1246
GetEventDurationMs(const std::string & event_name)1247 int MetricEventDurationObserver::GetEventDurationMs(
1248 const std::string& event_name) {
1249 EventDurationMap::const_iterator it = durations_.find(event_name);
1250 if (it == durations_.end())
1251 return -1;
1252 return it->second;
1253 }
1254
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1255 void MetricEventDurationObserver::Observe(NotificationType type,
1256 const NotificationSource& source, const NotificationDetails& details) {
1257 if (type != NotificationType::METRIC_EVENT_DURATION) {
1258 NOTREACHED();
1259 return;
1260 }
1261 MetricEventDurationDetails* metric_event_duration =
1262 Details<MetricEventDurationDetails>(details).ptr();
1263 durations_[metric_event_duration->event_name] =
1264 metric_event_duration->duration_ms;
1265 }
1266
PageTranslatedObserver(AutomationProvider * automation,IPC::Message * reply_message,TabContents * tab_contents)1267 PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation,
1268 IPC::Message* reply_message,
1269 TabContents* tab_contents)
1270 : automation_(automation->AsWeakPtr()),
1271 reply_message_(reply_message) {
1272 registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
1273 Source<TabContents>(tab_contents));
1274 }
1275
~PageTranslatedObserver()1276 PageTranslatedObserver::~PageTranslatedObserver() {}
1277
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1278 void PageTranslatedObserver::Observe(NotificationType type,
1279 const NotificationSource& source,
1280 const NotificationDetails& details) {
1281 if (!automation_) {
1282 delete this;
1283 return;
1284 }
1285
1286 DCHECK(type == NotificationType::PAGE_TRANSLATED);
1287 AutomationJSONReply reply(automation_, reply_message_.release());
1288
1289 PageTranslatedDetails* translated_details =
1290 Details<PageTranslatedDetails>(details).ptr();
1291 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1292 return_value->SetBoolean(
1293 "translation_success",
1294 translated_details->error_type == TranslateErrors::NONE);
1295 reply.SendSuccess(return_value.get());
1296 delete this;
1297 }
1298
TabLanguageDeterminedObserver(AutomationProvider * automation,IPC::Message * reply_message,TabContents * tab_contents,TranslateInfoBarDelegate * translate_bar)1299 TabLanguageDeterminedObserver::TabLanguageDeterminedObserver(
1300 AutomationProvider* automation, IPC::Message* reply_message,
1301 TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar)
1302 : automation_(automation->AsWeakPtr()),
1303 reply_message_(reply_message),
1304 tab_contents_(tab_contents),
1305 translate_bar_(translate_bar) {
1306 registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
1307 Source<TabContents>(tab_contents));
1308 }
1309
~TabLanguageDeterminedObserver()1310 TabLanguageDeterminedObserver::~TabLanguageDeterminedObserver() {}
1311
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1312 void TabLanguageDeterminedObserver::Observe(
1313 NotificationType type, const NotificationSource& source,
1314 const NotificationDetails& details) {
1315 DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED);
1316
1317 if (!automation_) {
1318 delete this;
1319 return;
1320 }
1321
1322 TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents(
1323 tab_contents_)->translate_tab_helper();
1324 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1325 return_value->SetBoolean("page_translated",
1326 helper->language_state().IsPageTranslated());
1327 return_value->SetBoolean(
1328 "can_translate_page", TranslatePrefs::CanTranslate(
1329 automation_->profile()->GetPrefs(),
1330 helper->language_state().original_language(),
1331 tab_contents_->GetURL()));
1332 return_value->SetString("original_language",
1333 helper->language_state().original_language());
1334 if (translate_bar_) {
1335 DictionaryValue* bar_info = new DictionaryValue;
1336 std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string;
1337 type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] =
1338 "BEFORE_TRANSLATE";
1339 type_to_string[TranslateInfoBarDelegate::TRANSLATING] =
1340 "TRANSLATING";
1341 type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] =
1342 "AFTER_TRANSLATE";
1343 type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] =
1344 "TRANSLATION_ERROR";
1345
1346 bar_info->SetBoolean("always_translate_lang_button_showing",
1347 translate_bar_->ShouldShowAlwaysTranslateButton());
1348 bar_info->SetBoolean("never_translate_lang_button_showing",
1349 translate_bar_->ShouldShowNeverTranslateButton());
1350 bar_info->SetString("bar_state", type_to_string[translate_bar_->type()]);
1351 bar_info->SetString("target_lang_code",
1352 translate_bar_->GetTargetLanguageCode());
1353 bar_info->SetString("original_lang_code",
1354 translate_bar_->GetOriginalLanguageCode());
1355 return_value->Set("translate_bar", bar_info);
1356 }
1357 AutomationJSONReply(automation_, reply_message_.release())
1358 .SendSuccess(return_value.get());
1359 delete this;
1360 }
1361
InfoBarCountObserver(AutomationProvider * automation,IPC::Message * reply_message,TabContents * tab_contents,size_t target_count)1362 InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
1363 IPC::Message* reply_message,
1364 TabContents* tab_contents,
1365 size_t target_count)
1366 : automation_(automation->AsWeakPtr()),
1367 reply_message_(reply_message),
1368 tab_contents_(tab_contents),
1369 target_count_(target_count) {
1370 Source<TabContents> source(tab_contents);
1371 registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
1372 registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
1373 CheckCount();
1374 }
1375
~InfoBarCountObserver()1376 InfoBarCountObserver::~InfoBarCountObserver() {}
1377
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1378 void InfoBarCountObserver::Observe(NotificationType type,
1379 const NotificationSource& source,
1380 const NotificationDetails& details) {
1381 DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED ||
1382 type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED);
1383 CheckCount();
1384 }
1385
CheckCount()1386 void InfoBarCountObserver::CheckCount() {
1387 if (tab_contents_->infobar_count() != target_count_)
1388 return;
1389
1390 if (automation_) {
1391 AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(),
1392 true);
1393 automation_->Send(reply_message_.release());
1394 }
1395 delete this;
1396 }
1397
1398 AutomationProviderBookmarkModelObserver::
AutomationProviderBookmarkModelObserver(AutomationProvider * provider,IPC::Message * reply_message,BookmarkModel * model)1399 AutomationProviderBookmarkModelObserver(
1400 AutomationProvider* provider,
1401 IPC::Message* reply_message,
1402 BookmarkModel* model)
1403 : automation_provider_(provider->AsWeakPtr()),
1404 reply_message_(reply_message),
1405 model_(model) {
1406 model_->AddObserver(this);
1407 }
1408
1409 AutomationProviderBookmarkModelObserver::
~AutomationProviderBookmarkModelObserver()1410 ~AutomationProviderBookmarkModelObserver() {
1411 model_->RemoveObserver(this);
1412 }
1413
Loaded(BookmarkModel * model)1414 void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model) {
1415 ReplyAndDelete(true);
1416 }
1417
BookmarkModelBeingDeleted(BookmarkModel * model)1418 void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted(
1419 BookmarkModel* model) {
1420 ReplyAndDelete(false);
1421 }
1422
ReplyAndDelete(bool success)1423 void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
1424 if (automation_provider_) {
1425 AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1426 reply_message_.get(), success);
1427 automation_provider_->Send(reply_message_.release());
1428 }
1429 delete this;
1430 }
1431
AutomationProviderDownloadItemObserver(AutomationProvider * provider,IPC::Message * reply_message,int downloads)1432 AutomationProviderDownloadItemObserver::AutomationProviderDownloadItemObserver(
1433 AutomationProvider* provider,
1434 IPC::Message* reply_message,
1435 int downloads)
1436 : provider_(provider->AsWeakPtr()),
1437 reply_message_(reply_message),
1438 downloads_(downloads),
1439 interrupted_(false) {
1440 }
1441
1442 AutomationProviderDownloadItemObserver::
~AutomationProviderDownloadItemObserver()1443 ~AutomationProviderDownloadItemObserver() {}
1444
OnDownloadUpdated(DownloadItem * download)1445 void AutomationProviderDownloadItemObserver::OnDownloadUpdated(
1446 DownloadItem* download) {
1447 interrupted_ |= download->IsInterrupted();
1448 // If any download was interrupted, on the next update each outstanding
1449 // download is cancelled.
1450 if (interrupted_) {
1451 // |Cancel()| does nothing if |download| is already interrupted.
1452 download->Cancel(true);
1453 RemoveAndCleanupOnLastEntry(download);
1454 }
1455
1456 if (download->IsComplete())
1457 RemoveAndCleanupOnLastEntry(download);
1458 }
1459
1460 // We don't want to send multiple messages, as the behavior is undefined.
1461 // Set |interrupted_| on error, and on the last download completed/
1462 // interrupted, send either an error or a success message.
RemoveAndCleanupOnLastEntry(DownloadItem * download)1463 void AutomationProviderDownloadItemObserver::RemoveAndCleanupOnLastEntry(
1464 DownloadItem* download) {
1465 // Forget about the download.
1466 download->RemoveObserver(this);
1467 if (--downloads_ == 0) {
1468 if (provider_) {
1469 if (interrupted_) {
1470 AutomationJSONReply(provider_, reply_message_.release()).SendError(
1471 "Download Interrupted");
1472 } else {
1473 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(
1474 NULL);
1475 }
1476 }
1477 delete this;
1478 }
1479 }
1480
OnDownloadOpened(DownloadItem * download)1481 void AutomationProviderDownloadItemObserver::OnDownloadOpened(
1482 DownloadItem* download) {
1483 }
1484
1485 AutomationProviderDownloadUpdatedObserver::
AutomationProviderDownloadUpdatedObserver(AutomationProvider * provider,IPC::Message * reply_message,bool wait_for_open)1486 AutomationProviderDownloadUpdatedObserver(
1487 AutomationProvider* provider,
1488 IPC::Message* reply_message,
1489 bool wait_for_open)
1490 : provider_(provider->AsWeakPtr()),
1491 reply_message_(reply_message),
1492 wait_for_open_(wait_for_open) {
1493 }
1494
1495 AutomationProviderDownloadUpdatedObserver::
~AutomationProviderDownloadUpdatedObserver()1496 ~AutomationProviderDownloadUpdatedObserver() {}
1497
OnDownloadUpdated(DownloadItem * download)1498 void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
1499 DownloadItem* download) {
1500 // If this observer is watching for open, only send the reply if the download
1501 // has been auto-opened.
1502 if (wait_for_open_ && !download->auto_opened())
1503 return;
1504
1505 download->RemoveObserver(this);
1506 scoped_ptr<DictionaryValue> return_value(
1507 provider_->GetDictionaryFromDownloadItem(download));
1508
1509 if (provider_) {
1510 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(
1511 return_value.get());
1512 }
1513 delete this;
1514 }
1515
OnDownloadOpened(DownloadItem * download)1516 void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
1517 DownloadItem* download) {
1518 download->RemoveObserver(this);
1519 scoped_ptr<DictionaryValue> return_value(
1520 provider_->GetDictionaryFromDownloadItem(download));
1521
1522 if (provider_) {
1523 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(
1524 return_value.get());
1525 }
1526 delete this;
1527 }
1528
1529 AutomationProviderDownloadModelChangedObserver::
AutomationProviderDownloadModelChangedObserver(AutomationProvider * provider,IPC::Message * reply_message,DownloadManager * download_manager)1530 AutomationProviderDownloadModelChangedObserver(
1531 AutomationProvider* provider,
1532 IPC::Message* reply_message,
1533 DownloadManager* download_manager)
1534 : provider_(provider->AsWeakPtr()),
1535 reply_message_(reply_message),
1536 download_manager_(download_manager) {
1537 }
1538
1539 AutomationProviderDownloadModelChangedObserver::
~AutomationProviderDownloadModelChangedObserver()1540 ~AutomationProviderDownloadModelChangedObserver() {}
1541
ModelChanged()1542 void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
1543 download_manager_->RemoveObserver(this);
1544
1545 if (provider_)
1546 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(NULL);
1547 delete this;
1548 }
1549
AutomationProviderSearchEngineObserver(AutomationProvider * provider,IPC::Message * reply_message)1550 AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver(
1551 AutomationProvider* provider,
1552 IPC::Message* reply_message)
1553 : provider_(provider->AsWeakPtr()),
1554 reply_message_(reply_message) {
1555 }
1556
1557 AutomationProviderSearchEngineObserver::
~AutomationProviderSearchEngineObserver()1558 ~AutomationProviderSearchEngineObserver() {}
1559
OnTemplateURLModelChanged()1560 void AutomationProviderSearchEngineObserver::OnTemplateURLModelChanged() {
1561 TemplateURLModel* url_model = provider_->profile()->GetTemplateURLModel();
1562 url_model->RemoveObserver(this);
1563
1564 if (provider_)
1565 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(NULL);
1566 delete this;
1567 }
1568
AutomationProviderHistoryObserver(AutomationProvider * provider,IPC::Message * reply_message)1569 AutomationProviderHistoryObserver::AutomationProviderHistoryObserver(
1570 AutomationProvider* provider,
1571 IPC::Message* reply_message)
1572 : provider_(provider->AsWeakPtr()),
1573 reply_message_(reply_message) {
1574 }
1575
~AutomationProviderHistoryObserver()1576 AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {}
1577
HistoryQueryComplete(HistoryService::Handle request_handle,history::QueryResults * results)1578 void AutomationProviderHistoryObserver::HistoryQueryComplete(
1579 HistoryService::Handle request_handle,
1580 history::QueryResults* results) {
1581 if (!provider_) {
1582 delete this;
1583 return;
1584 }
1585
1586 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1587
1588 ListValue* history_list = new ListValue;
1589 for (size_t i = 0; i < results->size(); ++i) {
1590 DictionaryValue* page_value = new DictionaryValue;
1591 history::URLResult const &page = (*results)[i];
1592 page_value->SetString("title", page.title());
1593 page_value->SetString("url", page.url().spec());
1594 page_value->SetDouble("time",
1595 static_cast<double>(page.visit_time().ToDoubleT()));
1596 page_value->SetString("snippet", page.snippet().text());
1597 page_value->SetBoolean(
1598 "starred",
1599 provider_->profile()->GetBookmarkModel()->IsBookmarked(page.url()));
1600 history_list->Append(page_value);
1601 }
1602
1603 return_value->Set("history", history_list);
1604 // Return history info.
1605 AutomationJSONReply reply(provider_, reply_message_.release());
1606 reply.SendSuccess(return_value.get());
1607 delete this;
1608 }
1609
1610 AutomationProviderImportSettingsObserver::
AutomationProviderImportSettingsObserver(AutomationProvider * provider,IPC::Message * reply_message)1611 AutomationProviderImportSettingsObserver(
1612 AutomationProvider* provider,
1613 IPC::Message* reply_message)
1614 : provider_(provider->AsWeakPtr()),
1615 reply_message_(reply_message) {
1616 }
1617
1618 AutomationProviderImportSettingsObserver::
~AutomationProviderImportSettingsObserver()1619 ~AutomationProviderImportSettingsObserver() {}
1620
ImportStarted()1621 void AutomationProviderImportSettingsObserver::ImportStarted() {
1622 }
1623
ImportItemStarted(importer::ImportItem item)1624 void AutomationProviderImportSettingsObserver::ImportItemStarted(
1625 importer::ImportItem item) {
1626 }
1627
ImportItemEnded(importer::ImportItem item)1628 void AutomationProviderImportSettingsObserver::ImportItemEnded(
1629 importer::ImportItem item) {
1630 }
1631
ImportEnded()1632 void AutomationProviderImportSettingsObserver::ImportEnded() {
1633 if (provider_)
1634 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(NULL);
1635 delete this;
1636 }
1637
AutomationProviderGetPasswordsObserver(AutomationProvider * provider,IPC::Message * reply_message)1638 AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver(
1639 AutomationProvider* provider,
1640 IPC::Message* reply_message)
1641 : provider_(provider->AsWeakPtr()),
1642 reply_message_(reply_message) {
1643 }
1644
1645 AutomationProviderGetPasswordsObserver::
~AutomationProviderGetPasswordsObserver()1646 ~AutomationProviderGetPasswordsObserver() {}
1647
OnPasswordStoreRequestDone(CancelableRequestProvider::Handle handle,const std::vector<webkit_glue::PasswordForm * > & result)1648 void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone(
1649 CancelableRequestProvider::Handle handle,
1650 const std::vector<webkit_glue::PasswordForm*>& result) {
1651 if (!provider_) {
1652 delete this;
1653 return;
1654 }
1655
1656 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1657
1658 ListValue* passwords = new ListValue;
1659 for (std::vector<webkit_glue::PasswordForm*>::const_iterator it =
1660 result.begin(); it != result.end(); ++it) {
1661 DictionaryValue* password_val = new DictionaryValue;
1662 webkit_glue::PasswordForm* password_form = *it;
1663 password_val->SetString("username_value", password_form->username_value);
1664 password_val->SetString("password_value", password_form->password_value);
1665 password_val->SetString("signon_realm", password_form->signon_realm);
1666 password_val->SetDouble(
1667 "time", static_cast<double>(password_form->date_created.ToDoubleT()));
1668 password_val->SetString("origin_url", password_form->origin.spec());
1669 password_val->SetString("username_element",
1670 password_form->username_element);
1671 password_val->SetString("password_element",
1672 password_form->password_element);
1673 password_val->SetString("submit_element",
1674 password_form->submit_element);
1675 password_val->SetString("action_target", password_form->action.spec());
1676 password_val->SetBoolean("blacklist", password_form->blacklisted_by_user);
1677 passwords->Append(password_val);
1678 }
1679
1680 return_value->Set("passwords", passwords);
1681 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(
1682 return_value.get());
1683 delete this;
1684 }
1685
AutomationProviderBrowsingDataObserver(AutomationProvider * provider,IPC::Message * reply_message)1686 AutomationProviderBrowsingDataObserver::AutomationProviderBrowsingDataObserver(
1687 AutomationProvider* provider,
1688 IPC::Message* reply_message)
1689 : provider_(provider->AsWeakPtr()),
1690 reply_message_(reply_message) {
1691 }
1692
1693 AutomationProviderBrowsingDataObserver::
~AutomationProviderBrowsingDataObserver()1694 ~AutomationProviderBrowsingDataObserver() {}
1695
OnBrowsingDataRemoverDone()1696 void AutomationProviderBrowsingDataObserver::OnBrowsingDataRemoverDone() {
1697 if (provider_)
1698 AutomationJSONReply(provider_, reply_message_.release()).SendSuccess(NULL);
1699 delete this;
1700 }
1701
OmniboxAcceptNotificationObserver(NavigationController * controller,AutomationProvider * automation,IPC::Message * reply_message)1702 OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver(
1703 NavigationController* controller,
1704 AutomationProvider* automation,
1705 IPC::Message* reply_message)
1706 : automation_(automation->AsWeakPtr()),
1707 reply_message_(reply_message),
1708 controller_(controller) {
1709 Source<NavigationController> source(controller_);
1710 registrar_.Add(this, NotificationType::LOAD_STOP, source);
1711 // Pages requiring auth don't send LOAD_STOP.
1712 registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
1713 }
1714
~OmniboxAcceptNotificationObserver()1715 OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() {
1716 }
1717
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1718 void OmniboxAcceptNotificationObserver::Observe(
1719 NotificationType type,
1720 const NotificationSource& source,
1721 const NotificationDetails& details) {
1722 if (type == NotificationType::LOAD_STOP ||
1723 type == NotificationType::AUTH_NEEDED) {
1724 if (automation_) {
1725 AutomationJSONReply(automation_,
1726 reply_message_.release()).SendSuccess(NULL);
1727 }
1728 delete this;
1729 } else {
1730 NOTREACHED();
1731 }
1732 }
1733
SavePackageNotificationObserver(SavePackage * save_package,AutomationProvider * automation,IPC::Message * reply_message)1734 SavePackageNotificationObserver::SavePackageNotificationObserver(
1735 SavePackage* save_package,
1736 AutomationProvider* automation,
1737 IPC::Message* reply_message)
1738 : automation_(automation->AsWeakPtr()),
1739 reply_message_(reply_message) {
1740 Source<SavePackage> source(save_package);
1741 registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
1742 source);
1743 }
1744
~SavePackageNotificationObserver()1745 SavePackageNotificationObserver::~SavePackageNotificationObserver() {}
1746
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1747 void SavePackageNotificationObserver::Observe(
1748 NotificationType type,
1749 const NotificationSource& source,
1750 const NotificationDetails& details) {
1751 if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) {
1752 if (automation_) {
1753 AutomationJSONReply(automation_,
1754 reply_message_.release()).SendSuccess(NULL);
1755 }
1756 delete this;
1757 } else {
1758 NOTREACHED();
1759 }
1760 }
1761
PageSnapshotTaker(AutomationProvider * automation,IPC::Message * reply_message,RenderViewHost * render_view,const FilePath & path)1762 PageSnapshotTaker::PageSnapshotTaker(AutomationProvider* automation,
1763 IPC::Message* reply_message,
1764 RenderViewHost* render_view,
1765 const FilePath& path)
1766 : automation_(automation->AsWeakPtr()),
1767 reply_message_(reply_message),
1768 render_view_(render_view),
1769 image_path_(path),
1770 received_width_(false) {}
1771
~PageSnapshotTaker()1772 PageSnapshotTaker::~PageSnapshotTaker() {}
1773
Start()1774 void PageSnapshotTaker::Start() {
1775 ExecuteScript(L"window.domAutomationController.send(document.width);");
1776 }
1777
OnDomOperationCompleted(const std::string & json)1778 void PageSnapshotTaker::OnDomOperationCompleted(const std::string& json) {
1779 int dimension;
1780 if (!base::StringToInt(json, &dimension)) {
1781 LOG(ERROR) << "Could not parse received dimensions: " << json;
1782 SendMessage(false);
1783 } else if (!received_width_) {
1784 received_width_ = true;
1785 entire_page_size_.set_width(dimension);
1786
1787 ExecuteScript(L"window.domAutomationController.send(document.height);");
1788 } else {
1789 entire_page_size_.set_height(dimension);
1790
1791 ThumbnailGenerator* generator =
1792 g_browser_process->GetThumbnailGenerator();
1793 ThumbnailGenerator::ThumbnailReadyCallback* callback =
1794 NewCallback(this, &PageSnapshotTaker::OnSnapshotTaken);
1795 // Don't actually start the thumbnail generator, this leads to crashes on
1796 // Mac, crbug.com/62986. Instead, just hook the generator to the
1797 // RenderViewHost manually.
1798
1799 generator->MonitorRenderer(render_view_, true);
1800 generator->AskForSnapshot(render_view_, false, callback,
1801 entire_page_size_, entire_page_size_);
1802 }
1803 }
1804
OnSnapshotTaken(const SkBitmap & bitmap)1805 void PageSnapshotTaker::OnSnapshotTaken(const SkBitmap& bitmap) {
1806 base::ThreadRestrictions::ScopedAllowIO allow_io;
1807 std::vector<unsigned char> png_data;
1808 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data);
1809 int bytes_written = file_util::WriteFile(image_path_,
1810 reinterpret_cast<char*>(&png_data[0]), png_data.size());
1811 SendMessage(bytes_written == static_cast<int>(png_data.size()));
1812 }
1813
ExecuteScript(const std::wstring & javascript)1814 void PageSnapshotTaker::ExecuteScript(const std::wstring& javascript) {
1815 std::wstring set_automation_id;
1816 base::SStringPrintf(
1817 &set_automation_id,
1818 L"window.domAutomationController.setAutomationId(%d);",
1819 reply_message_->routing_id());
1820
1821 render_view_->ExecuteJavascriptInWebFrame(string16(),
1822 WideToUTF16Hack(set_automation_id));
1823 render_view_->ExecuteJavascriptInWebFrame(string16(),
1824 WideToUTF16Hack(javascript));
1825 }
1826
SendMessage(bool success)1827 void PageSnapshotTaker::SendMessage(bool success) {
1828 if (automation_) {
1829 if (success) {
1830 AutomationJSONReply(automation_, reply_message_.release())
1831 .SendSuccess(NULL);
1832 } else {
1833 AutomationJSONReply(automation_, reply_message_.release())
1834 .SendError("Failed to take snapshot of page");
1835 }
1836 }
1837 delete this;
1838 }
1839
1840 namespace {
1841
1842 // Returns a vector of dictionaries containing information about installed apps,
1843 // as identified from a given list of extensions. The caller takes ownership
1844 // of the created vector.
GetAppInfoFromExtensions(const ExtensionList * extensions,ExtensionPrefs * ext_prefs)1845 std::vector<DictionaryValue*>* GetAppInfoFromExtensions(
1846 const ExtensionList* extensions,
1847 ExtensionPrefs* ext_prefs) {
1848 std::vector<DictionaryValue*>* apps_list =
1849 new std::vector<DictionaryValue*>();
1850 for (ExtensionList::const_iterator ext = extensions->begin();
1851 ext != extensions->end(); ++ext) {
1852 // Only return information about extensions that are actually apps.
1853 if ((*ext)->is_app()) {
1854 DictionaryValue* app_info = new DictionaryValue();
1855 AppLauncherHandler::CreateAppInfo(*ext, ext_prefs, app_info);
1856 app_info->SetBoolean("is_component_extension",
1857 (*ext)->location() == Extension::COMPONENT);
1858
1859 // Convert the launch_type integer into a more descriptive string.
1860 int launch_type;
1861 app_info->GetInteger("launch_type", &launch_type);
1862 if (launch_type == ExtensionPrefs::LAUNCH_PINNED) {
1863 app_info->SetString("launch_type", "pinned");
1864 } else if (launch_type == ExtensionPrefs::LAUNCH_REGULAR) {
1865 app_info->SetString("launch_type", "regular");
1866 } else if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN) {
1867 app_info->SetString("launch_type", "fullscreen");
1868 } else if (launch_type == ExtensionPrefs::LAUNCH_WINDOW) {
1869 app_info->SetString("launch_type", "window");
1870 } else {
1871 app_info->SetString("launch_type", "unknown");
1872 }
1873
1874 apps_list->push_back(app_info);
1875 }
1876 }
1877 return apps_list;
1878 }
1879
1880 } // namespace
1881
NTPInfoObserver(AutomationProvider * automation,IPC::Message * reply_message,CancelableRequestConsumer * consumer)1882 NTPInfoObserver::NTPInfoObserver(
1883 AutomationProvider* automation,
1884 IPC::Message* reply_message,
1885 CancelableRequestConsumer* consumer)
1886 : automation_(automation->AsWeakPtr()),
1887 reply_message_(reply_message),
1888 consumer_(consumer),
1889 request_(0),
1890 ntp_info_(new DictionaryValue) {
1891 top_sites_ = automation_->profile()->GetTopSites();
1892 if (!top_sites_) {
1893 AutomationJSONReply(automation_, reply_message_.release())
1894 .SendError("Profile does not have service for querying the top sites.");
1895 return;
1896 }
1897 TabRestoreService* service = automation_->profile()->GetTabRestoreService();
1898 if (!service) {
1899 AutomationJSONReply(automation_, reply_message_.release())
1900 .SendError("No TabRestoreService.");
1901 return;
1902 }
1903
1904 // Collect information about the apps in the new tab page.
1905 ExtensionService* ext_service = automation_->profile()->GetExtensionService();
1906 if (!ext_service) {
1907 AutomationJSONReply(automation_, reply_message_.release())
1908 .SendError("No ExtensionService.");
1909 return;
1910 }
1911 // Process enabled extensions.
1912 ExtensionPrefs* ext_prefs = ext_service->extension_prefs();
1913 ListValue* apps_list = new ListValue();
1914 const ExtensionList* extensions = ext_service->extensions();
1915 std::vector<DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions(
1916 extensions, ext_prefs);
1917 for (std::vector<DictionaryValue*>::const_iterator app =
1918 enabled_apps->begin(); app != enabled_apps->end(); ++app) {
1919 (*app)->SetBoolean("is_disabled", false);
1920 apps_list->Append(*app);
1921 }
1922 delete enabled_apps;
1923 // Process disabled extensions.
1924 const ExtensionList* disabled_extensions = ext_service->disabled_extensions();
1925 std::vector<DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions(
1926 disabled_extensions, ext_prefs);
1927 for (std::vector<DictionaryValue*>::const_iterator app =
1928 disabled_apps->begin(); app != disabled_apps->end(); ++app) {
1929 (*app)->SetBoolean("is_disabled", true);
1930 apps_list->Append(*app);
1931 }
1932 delete disabled_apps;
1933 ntp_info_->Set("apps", apps_list);
1934
1935 // Get the info that would be displayed in the recently closed section.
1936 ListValue* recently_closed_list = new ListValue;
1937 NewTabUI::AddRecentlyClosedEntries(service->entries(),
1938 recently_closed_list);
1939 ntp_info_->Set("recently_closed", recently_closed_list);
1940
1941 // Add default site URLs.
1942 ListValue* default_sites_list = new ListValue;
1943 std::vector<GURL> urls = MostVisitedHandler::GetPrePopulatedUrls();
1944 for (size_t i = 0; i < urls.size(); ++i) {
1945 default_sites_list->Append(Value::CreateStringValue(
1946 urls[i].possibly_invalid_spec()));
1947 }
1948 ntp_info_->Set("default_sites", default_sites_list);
1949
1950 registrar_.Add(this, NotificationType::TOP_SITES_UPDATED,
1951 Source<history::TopSites>(top_sites_));
1952 if (top_sites_->loaded()) {
1953 OnTopSitesLoaded();
1954 } else {
1955 registrar_.Add(this, NotificationType::TOP_SITES_LOADED,
1956 Source<Profile>(automation_->profile()));
1957 }
1958 }
1959
~NTPInfoObserver()1960 NTPInfoObserver::~NTPInfoObserver() {}
1961
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1962 void NTPInfoObserver::Observe(NotificationType type,
1963 const NotificationSource& source,
1964 const NotificationDetails& details) {
1965 if (type == NotificationType::TOP_SITES_LOADED) {
1966 OnTopSitesLoaded();
1967 } else if (type == NotificationType::TOP_SITES_UPDATED) {
1968 Details<CancelableRequestProvider::Handle> request_details(details);
1969 if (request_ == *request_details.ptr()) {
1970 top_sites_->GetMostVisitedURLs(
1971 consumer_,
1972 NewCallback(this, &NTPInfoObserver::OnTopSitesReceived));
1973 }
1974 }
1975 }
1976
OnTopSitesLoaded()1977 void NTPInfoObserver::OnTopSitesLoaded() {
1978 request_ = top_sites_->StartQueryForMostVisited();
1979 }
1980
OnTopSitesReceived(const history::MostVisitedURLList & visited_list)1981 void NTPInfoObserver::OnTopSitesReceived(
1982 const history::MostVisitedURLList& visited_list) {
1983 if (!automation_) {
1984 delete this;
1985 return;
1986 }
1987
1988 ListValue* list_value = new ListValue;
1989 for (size_t i = 0; i < visited_list.size(); ++i) {
1990 const history::MostVisitedURL& visited = visited_list[i];
1991 if (visited.url.spec().empty())
1992 break; // This is the signal that there are no more real visited sites.
1993 DictionaryValue* dict = new DictionaryValue;
1994 dict->SetString("url", visited.url.spec());
1995 dict->SetString("title", visited.title);
1996 dict->SetBoolean("is_pinned", top_sites_->IsURLPinned(visited.url));
1997 list_value->Append(dict);
1998 }
1999 ntp_info_->Set("most_visited", list_value);
2000 AutomationJSONReply(automation_,
2001 reply_message_.release()).SendSuccess(ntp_info_.get());
2002 delete this;
2003 }
2004
AppLaunchObserver(NavigationController * controller,AutomationProvider * automation,IPC::Message * reply_message,extension_misc::LaunchContainer launch_container)2005 AppLaunchObserver::AppLaunchObserver(
2006 NavigationController* controller,
2007 AutomationProvider* automation,
2008 IPC::Message* reply_message,
2009 extension_misc::LaunchContainer launch_container)
2010 : controller_(controller),
2011 automation_(automation->AsWeakPtr()),
2012 reply_message_(reply_message),
2013 launch_container_(launch_container),
2014 new_window_id_(extension_misc::kUnknownWindowId) {
2015 if (launch_container_ == extension_misc::LAUNCH_TAB) {
2016 // Need to wait for the currently-active tab to reload.
2017 Source<NavigationController> source(controller_);
2018 registrar_.Add(this, NotificationType::LOAD_STOP, source);
2019 } else {
2020 // Need to wait for a new tab in a new window to load.
2021 registrar_.Add(this, NotificationType::LOAD_STOP,
2022 NotificationService::AllSources());
2023 registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY,
2024 NotificationService::AllSources());
2025 }
2026 }
2027
~AppLaunchObserver()2028 AppLaunchObserver::~AppLaunchObserver() {}
2029
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2030 void AppLaunchObserver::Observe(NotificationType type,
2031 const NotificationSource& source,
2032 const NotificationDetails& details) {
2033 if (type.value == NotificationType::LOAD_STOP) {
2034 if (launch_container_ == extension_misc::LAUNCH_TAB) {
2035 // The app has been launched in the new tab.
2036 if (automation_) {
2037 AutomationJSONReply(automation_,
2038 reply_message_.release()).SendSuccess(NULL);
2039 }
2040 delete this;
2041 return;
2042 } else {
2043 // The app has launched only if the loaded tab is in the new window.
2044 int window_id = Source<NavigationController>(source)->window_id().id();
2045 if (window_id == new_window_id_) {
2046 if (automation_) {
2047 AutomationJSONReply(automation_,
2048 reply_message_.release()).SendSuccess(NULL);
2049 }
2050 delete this;
2051 return;
2052 }
2053 }
2054 } else if (type.value == NotificationType::BROWSER_WINDOW_READY) {
2055 new_window_id_ = ExtensionTabUtil::GetWindowId(
2056 Source<Browser>(source).ptr());
2057 } else {
2058 NOTREACHED();
2059 }
2060 }
2061
AutocompleteEditFocusedObserver(AutomationProvider * automation,AutocompleteEditModel * autocomplete_edit,IPC::Message * reply_message)2062 AutocompleteEditFocusedObserver::AutocompleteEditFocusedObserver(
2063 AutomationProvider* automation,
2064 AutocompleteEditModel* autocomplete_edit,
2065 IPC::Message* reply_message)
2066 : automation_(automation->AsWeakPtr()),
2067 reply_message_(reply_message),
2068 autocomplete_edit_model_(autocomplete_edit) {
2069 Source<AutocompleteEditModel> source(autocomplete_edit);
2070 registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, source);
2071 }
2072
~AutocompleteEditFocusedObserver()2073 AutocompleteEditFocusedObserver::~AutocompleteEditFocusedObserver() {}
2074
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2075 void AutocompleteEditFocusedObserver::Observe(
2076 NotificationType type,
2077 const NotificationSource& source,
2078 const NotificationDetails& details) {
2079 DCHECK(type == NotificationType::AUTOCOMPLETE_EDIT_FOCUSED);
2080 if (automation_) {
2081 AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams(
2082 reply_message_.get(), true);
2083 automation_->Send(reply_message_.release());
2084 }
2085 delete this;
2086 }
2087
2088 namespace {
2089
2090 // Returns whether the notification's host has a non-null process handle.
IsNotificationProcessReady(Balloon * balloon)2091 bool IsNotificationProcessReady(Balloon* balloon) {
2092 return balloon->view() &&
2093 balloon->view()->GetHost() &&
2094 balloon->view()->GetHost()->render_view_host() &&
2095 balloon->view()->GetHost()->render_view_host()->process()->GetHandle();
2096 }
2097
2098 // Returns whether all active notifications have an associated process ID.
AreActiveNotificationProcessesReady()2099 bool AreActiveNotificationProcessesReady() {
2100 NotificationUIManager* manager = g_browser_process->notification_ui_manager();
2101 const BalloonCollection::Balloons& balloons =
2102 manager->balloon_collection()->GetActiveBalloons();
2103 BalloonCollection::Balloons::const_iterator iter;
2104 for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
2105 if (!IsNotificationProcessReady(*iter))
2106 return false;
2107 }
2108 return true;
2109 }
2110
2111 } // namespace
2112
GetActiveNotificationsObserver(AutomationProvider * automation,IPC::Message * reply_message)2113 GetActiveNotificationsObserver::GetActiveNotificationsObserver(
2114 AutomationProvider* automation,
2115 IPC::Message* reply_message)
2116 : reply_(automation, reply_message) {
2117 if (AreActiveNotificationProcessesReady()) {
2118 SendMessage();
2119 } else {
2120 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED,
2121 NotificationService::AllSources());
2122 }
2123 }
2124
~GetActiveNotificationsObserver()2125 GetActiveNotificationsObserver::~GetActiveNotificationsObserver() {}
2126
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2127 void GetActiveNotificationsObserver::Observe(
2128 NotificationType type,
2129 const NotificationSource& source,
2130 const NotificationDetails& details) {
2131 if (AreActiveNotificationProcessesReady())
2132 SendMessage();
2133 }
2134
SendMessage()2135 void GetActiveNotificationsObserver::SendMessage() {
2136 NotificationUIManager* manager =
2137 g_browser_process->notification_ui_manager();
2138 const BalloonCollection::Balloons& balloons =
2139 manager->balloon_collection()->GetActiveBalloons();
2140 scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2141 ListValue* list = new ListValue;
2142 return_value->Set("notifications", list);
2143 BalloonCollection::Balloons::const_iterator iter;
2144 for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
2145 const Notification& notification = (*iter)->notification();
2146 DictionaryValue* balloon = new DictionaryValue;
2147 balloon->SetString("content_url", notification.content_url().spec());
2148 balloon->SetString("origin_url", notification.origin_url().spec());
2149 balloon->SetString("display_source", notification.display_source());
2150 BalloonView* view = (*iter)->view();
2151 balloon->SetInteger("pid", base::GetProcId(
2152 view->GetHost()->render_view_host()->process()->GetHandle()));
2153 list->Append(balloon);
2154 }
2155 reply_.SendSuccess(return_value.get());
2156 delete this;
2157 }
2158
OnNotificationBalloonCountObserver(AutomationProvider * provider,IPC::Message * reply_message,BalloonCollection * collection,int count)2159 OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver(
2160 AutomationProvider* provider,
2161 IPC::Message* reply_message,
2162 BalloonCollection* collection,
2163 int count)
2164 : reply_(provider, reply_message),
2165 collection_(collection),
2166 count_(count) {
2167 collection->set_on_collection_changed_callback(NewCallback(
2168 this, &OnNotificationBalloonCountObserver::OnBalloonCollectionChanged));
2169 }
2170
OnBalloonCollectionChanged()2171 void OnNotificationBalloonCountObserver::OnBalloonCollectionChanged() {
2172 if (static_cast<int>(collection_->GetActiveBalloons().size()) == count_) {
2173 collection_->set_on_collection_changed_callback(NULL);
2174 reply_.SendSuccess(NULL);
2175 delete this;
2176 }
2177 }
2178
RendererProcessClosedObserver(AutomationProvider * automation,IPC::Message * reply_message)2179 RendererProcessClosedObserver::RendererProcessClosedObserver(
2180 AutomationProvider* automation,
2181 IPC::Message* reply_message)
2182 : automation_(automation->AsWeakPtr()),
2183 reply_message_(reply_message) {
2184 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED,
2185 NotificationService::AllSources());
2186 }
2187
~RendererProcessClosedObserver()2188 RendererProcessClosedObserver::~RendererProcessClosedObserver() {}
2189
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2190 void RendererProcessClosedObserver::Observe(
2191 NotificationType type,
2192 const NotificationSource& source,
2193 const NotificationDetails& details) {
2194 if (automation_) {
2195 AutomationJSONReply(automation_,
2196 reply_message_.release()).SendSuccess(NULL);
2197 }
2198 delete this;
2199 }
2200
InputEventAckNotificationObserver(AutomationProvider * automation,IPC::Message * reply_message,int event_type)2201 InputEventAckNotificationObserver::InputEventAckNotificationObserver(
2202 AutomationProvider* automation,
2203 IPC::Message* reply_message,
2204 int event_type)
2205 : automation_(automation->AsWeakPtr()),
2206 reply_message_(reply_message),
2207 event_type_(event_type) {
2208 registrar_.Add(
2209 this, NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
2210 NotificationService::AllSources());
2211 }
2212
~InputEventAckNotificationObserver()2213 InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {}
2214
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2215 void InputEventAckNotificationObserver::Observe(
2216 NotificationType type,
2217 const NotificationSource& source,
2218 const NotificationDetails& details) {
2219 Details<int> request_details(details);
2220 if (event_type_ == *request_details.ptr()) {
2221 if (automation_) {
2222 AutomationJSONReply(automation_,
2223 reply_message_.release()).SendSuccess(NULL);
2224 }
2225 delete this;
2226 } else {
2227 LOG(WARNING) << "Ignoring unexpected event types.";
2228 }
2229 }
2230
AllTabsStoppedLoadingObserver(AutomationProvider * automation,IPC::Message * reply_message)2231 AllTabsStoppedLoadingObserver::AllTabsStoppedLoadingObserver(
2232 AutomationProvider* automation,
2233 IPC::Message* reply_message)
2234 : automation_(automation->AsWeakPtr()),
2235 reply_message_(reply_message) {
2236 for (BrowserList::const_iterator iter = BrowserList::begin();
2237 iter != BrowserList::end();
2238 ++iter) {
2239 Browser* browser = *iter;
2240 for (int i = 0; i < browser->tab_count(); ++i) {
2241 TabContentsWrapper* contents_wrapper =
2242 browser->GetTabContentsWrapperAt(i);
2243 StartObserving(contents_wrapper->automation_tab_helper());
2244 if (contents_wrapper->automation_tab_helper()->has_pending_loads())
2245 pending_tabs_.insert(contents_wrapper->tab_contents());
2246 }
2247 }
2248 CheckIfNoMorePendingLoads();
2249 }
2250
~AllTabsStoppedLoadingObserver()2251 AllTabsStoppedLoadingObserver::~AllTabsStoppedLoadingObserver() {
2252 }
2253
OnFirstPendingLoad(TabContents * tab_contents)2254 void AllTabsStoppedLoadingObserver::OnFirstPendingLoad(
2255 TabContents* tab_contents) {
2256 pending_tabs_.insert(tab_contents);
2257 }
2258
OnNoMorePendingLoads(TabContents * tab_contents)2259 void AllTabsStoppedLoadingObserver::OnNoMorePendingLoads(
2260 TabContents* tab_contents) {
2261 if (!automation_) {
2262 delete this;
2263 return;
2264 }
2265
2266 TabSet::iterator iter = pending_tabs_.find(tab_contents);
2267 if (iter == pending_tabs_.end()) {
2268 LOG(ERROR) << "Received OnNoMorePendingLoads for tab without "
2269 << "OnFirstPendingLoad.";
2270 return;
2271 }
2272 pending_tabs_.erase(iter);
2273 CheckIfNoMorePendingLoads();
2274 }
2275
CheckIfNoMorePendingLoads()2276 void AllTabsStoppedLoadingObserver::CheckIfNoMorePendingLoads() {
2277 if (!automation_) {
2278 delete this;
2279 return;
2280 }
2281
2282 if (pending_tabs_.empty()) {
2283 AutomationJSONReply(automation_,
2284 reply_message_.release()).SendSuccess(NULL);
2285 delete this;
2286 }
2287 }
2288
NewTabObserver(AutomationProvider * automation,IPC::Message * reply_message)2289 NewTabObserver::NewTabObserver(AutomationProvider* automation,
2290 IPC::Message* reply_message)
2291 : automation_(automation->AsWeakPtr()),
2292 reply_message_(reply_message) {
2293 // Use TAB_PARENTED to detect the new tab.
2294 registrar_.Add(this,
2295 NotificationType::TAB_PARENTED,
2296 NotificationService::AllSources());
2297 }
2298
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)2299 void NewTabObserver::Observe(NotificationType type,
2300 const NotificationSource& source,
2301 const NotificationDetails& details) {
2302 DCHECK_EQ(NotificationType::TAB_PARENTED, type.value);
2303 NavigationController* controller = Source<NavigationController>(source).ptr();
2304 if (automation_) {
2305 // TODO(phajdan.jr): Clean up this hack. We write the correct return type
2306 // here, but don't send the message. NavigationNotificationObserver
2307 // will wait properly for the load to finish, and send the message,
2308 // but it will also append its own return value at the end of the reply.
2309 AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(),
2310 true);
2311 new NavigationNotificationObserver(controller, automation_,
2312 reply_message_.release(),
2313 1, false, false);
2314 }
2315 delete this;
2316 }
2317
~NewTabObserver()2318 NewTabObserver::~NewTabObserver() {
2319 }
2320
2321 WaitForProcessLauncherThreadToGoIdleObserver::
WaitForProcessLauncherThreadToGoIdleObserver(AutomationProvider * automation,IPC::Message * reply_message)2322 WaitForProcessLauncherThreadToGoIdleObserver(
2323 AutomationProvider* automation, IPC::Message* reply_message)
2324 : automation_(automation->AsWeakPtr()),
2325 reply_message_(reply_message) {
2326 // Balanced in RunOnUIThread.
2327 AddRef();
2328 BrowserThread::PostTask(
2329 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2330 NewRunnableMethod(
2331 this,
2332 &WaitForProcessLauncherThreadToGoIdleObserver::
2333 RunOnProcessLauncherThread));
2334 }
2335
2336 WaitForProcessLauncherThreadToGoIdleObserver::
~WaitForProcessLauncherThreadToGoIdleObserver()2337 ~WaitForProcessLauncherThreadToGoIdleObserver() {
2338 }
2339
2340 void WaitForProcessLauncherThreadToGoIdleObserver::
RunOnProcessLauncherThread()2341 RunOnProcessLauncherThread() {
2342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2343 BrowserThread::PostTask(
2344 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
2345 NewRunnableMethod(
2346 this,
2347 &WaitForProcessLauncherThreadToGoIdleObserver::
2348 RunOnProcessLauncherThread2));
2349 }
2350
2351 void WaitForProcessLauncherThreadToGoIdleObserver::
RunOnProcessLauncherThread2()2352 RunOnProcessLauncherThread2() {
2353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
2354 BrowserThread::PostTask(
2355 BrowserThread::UI, FROM_HERE,
2356 NewRunnableMethod(
2357 this,
2358 &WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread));
2359 }
2360
RunOnUIThread()2361 void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() {
2362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2363 if (automation_)
2364 automation_->Send(reply_message_.release());
2365 Release();
2366 }
2367