• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notification_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