automation_provider_observers.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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 "base/basictypes.h"
8#include "base/json/json_writer.h"
9#include "base/scoped_ptr.h"
10#include "base/string_util.h"
11#include "base/values.h"
12#include "chrome/app/chrome_dll_resource.h"
13#include "chrome/browser/automation/automation_provider.h"
14#include "chrome/browser/automation/automation_provider_json.h"
15#include "chrome/browser/bookmarks/bookmark_model.h"
16#include "chrome/browser/browser.h"
17#include "chrome/browser/browser_list.h"
18#include "chrome/browser/dom_operation_notification_details.h"
19#include "chrome/browser/download/download_item.h"
20#include "chrome/browser/download/save_package.h"
21#include "chrome/browser/extensions/extension_host.h"
22#include "chrome/browser/extensions/extension_process_manager.h"
23#include "chrome/browser/extensions/extension_updater.h"
24#include "chrome/browser/login_prompt.h"
25#include "chrome/browser/metrics/metric_event_duration_details.h"
26#include "chrome/browser/printing/print_job.h"
27#include "chrome/browser/profile.h"
28#include "chrome/browser/search_engines/template_url_model.h"
29#include "chrome/browser/tab_contents/navigation_controller.h"
30#include "chrome/browser/tab_contents/tab_contents.h"
31#include "chrome/browser/translate/page_translated_details.h"
32#include "chrome/browser/translate/translate_infobar_delegate.h"
33#include "chrome/common/extensions/extension.h"
34#include "chrome/common/notification_service.h"
35#include "chrome/test/automation/automation_constants.h"
36#include "gfx/rect.h"
37
38#if defined(OS_CHROMEOS)
39#include "chrome/browser/chromeos/login/authentication_notification_details.h"
40#endif
41
42// Holds onto start and stop timestamps for a particular tab
43class InitialLoadObserver::TabTime {
44 public:
45  explicit TabTime(base::TimeTicks started)
46      : load_start_time_(started) {
47  }
48  void set_stop_time(base::TimeTicks stopped) {
49    load_stop_time_ = stopped;
50  }
51  base::TimeTicks stop_time() const {
52    return load_stop_time_;
53  }
54  base::TimeTicks start_time() const {
55    return load_start_time_;
56  }
57 private:
58  base::TimeTicks load_start_time_;
59  base::TimeTicks load_stop_time_;
60};
61
62InitialLoadObserver::InitialLoadObserver(size_t tab_count,
63                                         AutomationProvider* automation)
64    : automation_(automation),
65      outstanding_tab_count_(tab_count),
66      init_time_(base::TimeTicks::Now()) {
67  if (outstanding_tab_count_ > 0) {
68    registrar_.Add(this, NotificationType::LOAD_START,
69                   NotificationService::AllSources());
70    registrar_.Add(this, NotificationType::LOAD_STOP,
71                   NotificationService::AllSources());
72  }
73}
74
75InitialLoadObserver::~InitialLoadObserver() {
76}
77
78void InitialLoadObserver::Observe(NotificationType type,
79                                  const NotificationSource& source,
80                                  const NotificationDetails& details) {
81  if (type == NotificationType::LOAD_START) {
82    if (outstanding_tab_count_ > loading_tabs_.size())
83      loading_tabs_.insert(TabTimeMap::value_type(
84          source.map_key(),
85          TabTime(base::TimeTicks::Now())));
86  } else if (type == NotificationType::LOAD_STOP) {
87    if (outstanding_tab_count_ > finished_tabs_.size()) {
88      TabTimeMap::iterator iter = loading_tabs_.find(source.map_key());
89      if (iter != loading_tabs_.end()) {
90        finished_tabs_.insert(source.map_key());
91        iter->second.set_stop_time(base::TimeTicks::Now());
92      }
93      if (outstanding_tab_count_ == finished_tabs_.size())
94        ConditionMet();
95    }
96  } else {
97    NOTREACHED();
98  }
99}
100
101DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
102  ListValue* items = new ListValue;
103  for (TabTimeMap::const_iterator it = loading_tabs_.begin();
104       it != loading_tabs_.end();
105       ++it) {
106    DictionaryValue* item = new DictionaryValue;
107    base::TimeDelta delta_start = it->second.start_time() - init_time_;
108
109    item->SetReal("load_start_ms", delta_start.InMillisecondsF());
110    if (it->second.stop_time().is_null()) {
111      item->Set("load_stop_ms", Value::CreateNullValue());
112    } else {
113      base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
114      item->SetReal("load_stop_ms", delta_stop.InMillisecondsF());
115    }
116    items->Append(item);
117  }
118  DictionaryValue* return_value = new DictionaryValue;
119  return_value->Set("tabs", items);
120  return return_value;
121}
122
123void InitialLoadObserver::ConditionMet() {
124  registrar_.RemoveAll();
125  automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
126}
127
128NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation)
129    : automation_(automation) {
130  registrar_.Add(this, NotificationType::INITIAL_NEW_TAB_UI_LOAD,
131                 NotificationService::AllSources());
132}
133
134NewTabUILoadObserver::~NewTabUILoadObserver() {
135}
136
137void NewTabUILoadObserver::Observe(NotificationType type,
138                                   const NotificationSource& source,
139                                   const NotificationDetails& details) {
140  if (type == NotificationType::INITIAL_NEW_TAB_UI_LOAD) {
141    Details<int> load_time(details);
142    automation_->Send(
143        new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
144  } else {
145    NOTREACHED();
146  }
147}
148
149NavigationControllerRestoredObserver::NavigationControllerRestoredObserver(
150    AutomationProvider* automation,
151    NavigationController* controller,
152    IPC::Message* reply_message)
153    : automation_(automation),
154      controller_(controller),
155      reply_message_(reply_message) {
156  if (FinishedRestoring()) {
157    SendDone();
158  } else {
159    registrar_.Add(this, NotificationType::LOAD_STOP,
160                   NotificationService::AllSources());
161  }
162}
163
164NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() {
165}
166
167void NavigationControllerRestoredObserver::Observe(
168    NotificationType type, const NotificationSource& source,
169    const NotificationDetails& details) {
170  if (FinishedRestoring()) {
171    SendDone();
172    registrar_.RemoveAll();
173  }
174}
175
176bool NavigationControllerRestoredObserver::FinishedRestoring() {
177  return (!controller_->needs_reload() && !controller_->pending_entry() &&
178          !controller_->tab_contents()->is_loading());
179}
180
181void NavigationControllerRestoredObserver::SendDone() {
182  DCHECK(reply_message_ != NULL);
183  automation_->Send(reply_message_);
184}
185
186NavigationNotificationObserver::NavigationNotificationObserver(
187    NavigationController* controller,
188    AutomationProvider* automation,
189    IPC::Message* reply_message,
190    int number_of_navigations,
191    bool include_current_navigation)
192  : automation_(automation),
193    reply_message_(reply_message),
194    controller_(controller),
195    navigations_remaining_(number_of_navigations),
196    navigation_started_(false) {
197  DCHECK_LT(0, navigations_remaining_);
198  Source<NavigationController> source(controller_);
199  registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, source);
200  registrar_.Add(this, NotificationType::LOAD_START, source);
201  registrar_.Add(this, NotificationType::LOAD_STOP, source);
202  registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
203  registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source);
204  registrar_.Add(this, NotificationType::AUTH_CANCELLED, source);
205
206  if (include_current_navigation && controller->tab_contents()->is_loading())
207    navigation_started_ = true;
208}
209
210NavigationNotificationObserver::~NavigationNotificationObserver() {
211  if (reply_message_) {
212    // This means we did not receive a notification for this navigation.
213    // Send over a failed navigation status back to the caller to ensure that
214    // the caller does not hang waiting for the response.
215    IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::Write(
216        reply_message_, AUTOMATION_MSG_NAVIGATION_ERROR);
217    automation_->Send(reply_message_);
218    reply_message_ = NULL;
219  }
220
221  automation_->RemoveNavigationStatusListener(this);
222}
223
224void NavigationNotificationObserver::Observe(
225    NotificationType type, const NotificationSource& source,
226    const NotificationDetails& details) {
227  // We listen for 2 events to determine when the navigation started because:
228  // - when this is used by the WaitForNavigation method, we might be invoked
229  // afer the load has started (but not after the entry was committed, as
230  // WaitForNavigation compares times of the last navigation).
231  // - when this is used with a page requiring authentication, we will not get
232  // a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so
233  // we need the NotificationType::LOAD_START.
234  if (type == NotificationType::NAV_ENTRY_COMMITTED ||
235      type == NotificationType::LOAD_START) {
236    navigation_started_ = true;
237  } else if (type == NotificationType::LOAD_STOP) {
238    if (navigation_started_) {
239      navigation_started_ = false;
240      if (--navigations_remaining_ == 0)
241        ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
242    }
243  } else if (type == NotificationType::AUTH_SUPPLIED ||
244             type == NotificationType::AUTH_CANCELLED) {
245    // The LoginHandler for this tab is no longer valid.
246    automation_->RemoveLoginHandler(controller_);
247
248    // Treat this as if navigation started again, since load start/stop don't
249    // occur while authentication is ongoing.
250    navigation_started_ = true;
251  } else if (type == NotificationType::AUTH_NEEDED) {
252    // Remember the login handler that wants authentication.
253    // We do this in all cases (not just when navigation_started_ == true) so
254    // tests can still wait for auth dialogs outside of navigation.
255    LoginHandler* handler =
256        Details<LoginNotificationDetails>(details)->handler();
257    automation_->AddLoginHandler(controller_, handler);
258
259    // Respond that authentication is needed.
260    navigation_started_ = false;
261    ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
262  } else {
263    NOTREACHED();
264  }
265}
266
267void NavigationNotificationObserver::ConditionMet(
268    AutomationMsg_NavigationResponseValues navigation_result) {
269  DCHECK(reply_message_ != NULL);
270
271  IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::Write(
272      reply_message_, navigation_result);
273  automation_->Send(reply_message_);
274  reply_message_ = NULL;
275
276  delete this;
277}
278
279TabStripNotificationObserver::TabStripNotificationObserver(
280    NotificationType notification, AutomationProvider* automation)
281    : automation_(automation),
282      notification_(notification) {
283  registrar_.Add(this, notification_, NotificationService::AllSources());
284}
285
286TabStripNotificationObserver::~TabStripNotificationObserver() {
287}
288
289void TabStripNotificationObserver::Observe(NotificationType type,
290                                           const NotificationSource& source,
291                                           const NotificationDetails& details) {
292  if (type == notification_) {
293    ObserveTab(Source<NavigationController>(source).ptr());
294
295    // If verified, no need to observe anymore
296    automation_->RemoveTabStripObserver(this);
297    delete this;
298  } else {
299    NOTREACHED();
300  }
301}
302
303TabAppendedNotificationObserver::TabAppendedNotificationObserver(
304    Browser* parent, AutomationProvider* automation,
305    IPC::Message* reply_message)
306    : TabStripNotificationObserver(NotificationType::TAB_PARENTED, automation),
307      parent_(parent),
308      reply_message_(reply_message) {
309}
310
311void TabAppendedNotificationObserver::ObserveTab(
312    NavigationController* controller) {
313  if (automation_->GetIndexForNavigationController(controller, parent_) ==
314      TabStripModel::kNoTab) {
315    // This tab notification doesn't belong to the parent_.
316    return;
317  }
318
319  automation_->AddNavigationStatusListener(controller, reply_message_, 1,
320                                           false);
321}
322
323TabClosedNotificationObserver::TabClosedNotificationObserver(
324    AutomationProvider* automation, bool wait_until_closed,
325    IPC::Message* reply_message)
326    : TabStripNotificationObserver(wait_until_closed ?
327          NotificationType::TAB_CLOSED : NotificationType::TAB_CLOSING,
328          automation),
329      reply_message_(reply_message),
330      for_browser_command_(false) {
331}
332
333void TabClosedNotificationObserver::ObserveTab(
334    NavigationController* controller) {
335  if (for_browser_command_) {
336    AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
337                                                         true);
338  } else {
339    AutomationMsg_CloseTab::WriteReplyParams(reply_message_, true);
340  }
341  automation_->Send(reply_message_);
342}
343
344void TabClosedNotificationObserver::set_for_browser_command(
345    bool for_browser_command) {
346  for_browser_command_ = for_browser_command;
347}
348
349TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation,
350                                               Browser* browser,
351                                               IPC::Message* reply_message,
352                                               int target_tab_count)
353    : automation_(automation),
354      reply_message_(reply_message),
355      tab_strip_model_(browser->tabstrip_model()),
356      target_tab_count_(target_tab_count) {
357  tab_strip_model_->AddObserver(this);
358  CheckTabCount();
359}
360
361TabCountChangeObserver::~TabCountChangeObserver() {
362  tab_strip_model_->RemoveObserver(this);
363}
364
365void TabCountChangeObserver::TabInsertedAt(TabContents* contents,
366                                           int index,
367                                           bool foreground) {
368  CheckTabCount();
369}
370
371void TabCountChangeObserver::TabDetachedAt(TabContents* contents, int index) {
372  CheckTabCount();
373}
374
375void TabCountChangeObserver::TabStripModelDeleted() {
376  AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_,
377                                                          false);
378  automation_->Send(reply_message_);
379  delete this;
380}
381
382void TabCountChangeObserver::CheckTabCount() {
383  if (tab_strip_model_->count() != target_tab_count_)
384    return;
385
386  AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_,
387                                                          true);
388  automation_->Send(reply_message_);
389  delete this;
390}
391
392bool DidExtensionHostsStopLoading(ExtensionProcessManager* manager) {
393  for (ExtensionProcessManager::const_iterator iter = manager->begin();
394       iter != manager->end(); ++iter) {
395    if (!(*iter)->did_stop_loading())
396      return false;
397  }
398  return true;
399}
400
401ExtensionInstallNotificationObserver::ExtensionInstallNotificationObserver(
402    AutomationProvider* automation, int id, IPC::Message* reply_message)
403    : automation_(automation),
404      id_(id),
405      reply_message_(reply_message) {
406  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
407                 NotificationService::AllSources());
408  registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR,
409                 NotificationService::AllSources());
410  registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
411                 NotificationService::AllSources());
412}
413
414ExtensionInstallNotificationObserver::~ExtensionInstallNotificationObserver() {
415}
416
417void ExtensionInstallNotificationObserver::Observe(
418    NotificationType type, const NotificationSource& source,
419    const NotificationDetails& details) {
420  switch (type.value) {
421    case NotificationType::EXTENSION_LOADED:
422      SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED);
423      break;
424    case NotificationType::EXTENSION_INSTALL_ERROR:
425    case NotificationType::EXTENSION_UPDATE_DISABLED:
426      SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
427      break;
428    default:
429      NOTREACHED();
430      break;
431  }
432
433  delete this;
434}
435
436void ExtensionInstallNotificationObserver::SendResponse(
437    AutomationMsg_ExtensionResponseValues response) {
438  if (reply_message_ != NULL) {
439    switch (id_) {
440      case AutomationMsg_InstallExtension::ID:
441        AutomationMsg_InstallExtension::WriteReplyParams(reply_message_,
442                                                         response);
443        break;
444      case AutomationMsg_LoadExpandedExtension::ID:
445        AutomationMsg_LoadExpandedExtension::WriteReplyParams(reply_message_,
446                                                              response);
447        break;
448      default:
449        NOTREACHED();
450        break;
451    }
452
453    automation_->Send(reply_message_);
454    reply_message_ = NULL;
455  }
456}
457
458ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver(
459    ExtensionProcessManager* manager, AutomationProvider* automation, int id,
460    IPC::Message* reply_message)
461    : manager_(manager),
462      automation_(automation),
463      id_(id),
464      reply_message_(reply_message),
465      extension_(NULL) {
466  registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
467                 NotificationService::AllSources());
468  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
469                 NotificationService::AllSources());
470  registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR,
471                 NotificationService::AllSources());
472  registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
473                 NotificationService::AllSources());
474}
475
476ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() {
477}
478
479void ExtensionReadyNotificationObserver::Observe(
480    NotificationType type, const NotificationSource& source,
481    const NotificationDetails& details) {
482  bool success = false;
483  switch (type.value) {
484    case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
485      // Only continue on with this method if our extension has been loaded
486      // and all the extension hosts have stopped loading.
487      if (!extension_ || !DidExtensionHostsStopLoading(manager_))
488        return;
489      success = true;
490      break;
491    case NotificationType::EXTENSION_LOADED:
492      extension_ = Details<Extension>(details).ptr();
493      if (!DidExtensionHostsStopLoading(manager_))
494        return;
495      success = true;
496      break;
497    case NotificationType::EXTENSION_INSTALL_ERROR:
498    case NotificationType::EXTENSION_UPDATE_DISABLED:
499      success = false;
500      break;
501    default:
502      NOTREACHED();
503      break;
504  }
505
506  if (id_ == AutomationMsg_InstallExtensionAndGetHandle::ID) {
507    // A handle of zero indicates an error.
508    int extension_handle = 0;
509    if (extension_)
510      extension_handle = automation_->AddExtension(extension_);
511    AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams(
512        reply_message_, extension_handle);
513  } else if (id_ == AutomationMsg_EnableExtension::ID) {
514    AutomationMsg_EnableExtension::WriteReplyParams(reply_message_, true);
515  } else {
516    NOTREACHED();
517    LOG(ERROR) << "Cannot write reply params for unknown message id.";
518  }
519
520  automation_->Send(reply_message_);
521  delete this;
522}
523
524ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
525    : did_receive_unload_notification_(false) {
526  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
527                 NotificationService::AllSources());
528  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
529                 NotificationService::AllSources());
530}
531
532ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
533}
534
535void ExtensionUnloadNotificationObserver::Observe(
536    NotificationType type, const NotificationSource& source,
537    const NotificationDetails& details) {
538  if (type.value == NotificationType::EXTENSION_UNLOADED ||
539      type.value == NotificationType::EXTENSION_UNLOADED_DISABLED) {
540    did_receive_unload_notification_ = true;
541  } else {
542    NOTREACHED();
543  }
544}
545
546ExtensionTestResultNotificationObserver::
547    ExtensionTestResultNotificationObserver(AutomationProvider* automation)
548    : automation_(automation) {
549  registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
550                 NotificationService::AllSources());
551  registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
552                 NotificationService::AllSources());
553}
554
555ExtensionTestResultNotificationObserver::
556    ~ExtensionTestResultNotificationObserver() {
557}
558
559void ExtensionTestResultNotificationObserver::Observe(
560    NotificationType type, const NotificationSource& source,
561    const NotificationDetails& details) {
562  switch (type.value) {
563    case NotificationType::EXTENSION_TEST_PASSED:
564      results_.push_back(true);
565      messages_.push_back("");
566      break;
567
568    case NotificationType::EXTENSION_TEST_FAILED:
569      results_.push_back(false);
570      messages_.push_back(*(Details<std::string>(details).ptr()));
571      break;
572
573    default:
574      NOTREACHED();
575  }
576  // There may be a reply message waiting for this event, so check.
577  MaybeSendResult();
578}
579
580void ExtensionTestResultNotificationObserver::MaybeSendResult() {
581  if (results_.size() > 0) {
582    // This release method should return the automation's current
583    // reply message, or NULL if there is no current one. If it is not
584    // NULL, we are stating that we will handle this reply message.
585    IPC::Message* reply_message = automation_->reply_message_release();
586    // Send the result back if we have a reply message.
587    if (reply_message) {
588      AutomationMsg_WaitForExtensionTestResult::WriteReplyParams(
589          reply_message, results_.front(), messages_.front());
590      results_.pop_front();
591      messages_.pop_front();
592      automation_->Send(reply_message);
593    }
594  }
595}
596
597BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver(
598    AutomationProvider* automation, IPC::Message* reply_message)
599    : automation_(automation),
600      reply_message_(reply_message),
601      for_browser_command_(false) {
602  registrar_.Add(this, NotificationType::BROWSER_OPENED,
603                 NotificationService::AllSources());
604}
605
606BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() {
607}
608
609void BrowserOpenedNotificationObserver::Observe(
610    NotificationType type, const NotificationSource& source,
611    const NotificationDetails& details) {
612  if (type == NotificationType::BROWSER_OPENED) {
613    if (for_browser_command_) {
614      AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
615                                                           true);
616    }
617    automation_->Send(reply_message_);
618    delete this;
619  } else {
620    NOTREACHED();
621  }
622}
623
624void BrowserOpenedNotificationObserver::set_for_browser_command(
625    bool for_browser_command) {
626  for_browser_command_ = for_browser_command;
627}
628
629BrowserClosedNotificationObserver::BrowserClosedNotificationObserver(
630    Browser* browser,
631    AutomationProvider* automation,
632    IPC::Message* reply_message)
633    : automation_(automation),
634      reply_message_(reply_message),
635      for_browser_command_(false) {
636  registrar_.Add(this, NotificationType::BROWSER_CLOSED,
637                 Source<Browser>(browser));
638}
639
640void BrowserClosedNotificationObserver::Observe(
641    NotificationType type, const NotificationSource& source,
642    const NotificationDetails& details) {
643  DCHECK(type == NotificationType::BROWSER_CLOSED);
644  Details<bool> close_app(details);
645  DCHECK(reply_message_ != NULL);
646  if (for_browser_command_) {
647    AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
648                                                         true);
649  } else {
650    AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_, true,
651                                                 *(close_app.ptr()));
652  }
653  automation_->Send(reply_message_);
654  reply_message_ = NULL;
655  delete this;
656}
657
658void BrowserClosedNotificationObserver::set_for_browser_command(
659    bool for_browser_command) {
660  for_browser_command_ = for_browser_command;
661}
662
663BrowserCountChangeNotificationObserver::BrowserCountChangeNotificationObserver(
664    int target_count,
665    AutomationProvider* automation,
666    IPC::Message* reply_message)
667    : target_count_(target_count),
668      automation_(automation),
669      reply_message_(reply_message) {
670  registrar_.Add(this, NotificationType::BROWSER_OPENED,
671                 NotificationService::AllSources());
672  registrar_.Add(this, NotificationType::BROWSER_CLOSED,
673                 NotificationService::AllSources());
674}
675
676void BrowserCountChangeNotificationObserver::Observe(
677    NotificationType type, const NotificationSource& source,
678    const NotificationDetails& details) {
679  DCHECK(type == NotificationType::BROWSER_OPENED ||
680         type == NotificationType::BROWSER_CLOSED);
681  int current_count = static_cast<int>(BrowserList::size());
682  if (type == NotificationType::BROWSER_CLOSED) {
683    // At the time of the notification the browser being closed is not removed
684    // from the list. The real count is one less than the reported count.
685    DCHECK_LT(0, current_count);
686    current_count--;
687  }
688  if (current_count == target_count_) {
689    AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
690        reply_message_, true);
691    automation_->Send(reply_message_);
692    reply_message_ = NULL;
693    delete this;
694  }
695}
696
697AppModalDialogShownObserver::AppModalDialogShownObserver(
698    AutomationProvider* automation, IPC::Message* reply_message)
699    : automation_(automation),
700      reply_message_(reply_message) {
701  registrar_.Add(this, NotificationType::APP_MODAL_DIALOG_SHOWN,
702                 NotificationService::AllSources());
703}
704
705AppModalDialogShownObserver::~AppModalDialogShownObserver() {
706}
707
708void AppModalDialogShownObserver::Observe(
709    NotificationType type, const NotificationSource& source,
710    const NotificationDetails& details) {
711  DCHECK(type == NotificationType::APP_MODAL_DIALOG_SHOWN);
712
713  AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
714      reply_message_, true);
715  automation_->Send(reply_message_);
716  reply_message_ = NULL;
717  delete this;
718}
719
720namespace {
721
722// Define mapping from command to notification
723struct CommandNotification {
724  int command;
725  NotificationType::Type notification_type;
726};
727
728const struct CommandNotification command_notifications[] = {
729  {IDC_DUPLICATE_TAB, NotificationType::TAB_PARENTED},
730  {IDC_NEW_TAB, NotificationType::INITIAL_NEW_TAB_UI_LOAD},
731
732  // Returns as soon as the restored tab is created. To further wait until
733  // the content page is loaded, use WaitForTabToBeRestored.
734  {IDC_RESTORE_TAB, NotificationType::TAB_PARENTED},
735
736  // For the following commands, we need to wait for a new tab to be created,
737  // load to finish, and title to change.
738  {IDC_MANAGE_EXTENSIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
739  {IDC_OPTIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
740  {IDC_SHOW_DOWNLOADS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
741  {IDC_SHOW_HISTORY, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
742};
743
744}  // namespace
745
746ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() {
747}
748
749// static
750bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
751    AutomationProvider* automation, Browser* browser, int command,
752    IPC::Message* reply_message) {
753  bool result = true;
754  switch (command) {
755    case IDC_NEW_WINDOW:
756    case IDC_NEW_INCOGNITO_WINDOW: {
757      BrowserOpenedNotificationObserver* observer =
758          new BrowserOpenedNotificationObserver(automation, reply_message);
759      observer->set_for_browser_command(true);
760      break;
761    }
762    case IDC_CLOSE_WINDOW: {
763      BrowserClosedNotificationObserver* observer =
764          new BrowserClosedNotificationObserver(browser, automation,
765                                                reply_message);
766      observer->set_for_browser_command(true);
767      break;
768    }
769    case IDC_CLOSE_TAB: {
770      TabClosedNotificationObserver* observer =
771          new TabClosedNotificationObserver(automation, true, reply_message);
772      observer->set_for_browser_command(true);
773      break;
774    }
775    case IDC_BACK:
776    case IDC_FORWARD:
777    case IDC_RELOAD: {
778      automation->AddNavigationStatusListener(
779          &browser->GetSelectedTabContents()->controller(),
780          reply_message, 1, false);
781      break;
782    }
783    default: {
784      ExecuteBrowserCommandObserver* observer =
785          new ExecuteBrowserCommandObserver(automation, reply_message);
786      if (!observer->Register(command)) {
787        delete observer;
788        result = false;
789      }
790      break;
791    }
792  }
793  return result;
794}
795
796void ExecuteBrowserCommandObserver::Observe(
797    NotificationType type, const NotificationSource& source,
798    const NotificationDetails& details) {
799  if (type == notification_type_) {
800    AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
801                                                         true);
802    automation_->Send(reply_message_);
803    delete this;
804  } else {
805    NOTREACHED();
806  }
807}
808
809ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
810    AutomationProvider* automation, IPC::Message* reply_message)
811    : automation_(automation),
812      notification_type_(NotificationType::ALL),
813      reply_message_(reply_message) {
814}
815
816bool ExecuteBrowserCommandObserver::Register(int command) {
817  if (!GetNotificationType(command, &notification_type_))
818    return false;
819  registrar_.Add(this, notification_type_, NotificationService::AllSources());
820  return true;
821}
822
823bool ExecuteBrowserCommandObserver::GetNotificationType(
824    int command, NotificationType::Type* type) {
825  if (!type)
826    return false;
827  bool found = false;
828  for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
829    if (command_notifications[i].command == command) {
830      *type = command_notifications[i].notification_type;
831      found = true;
832      break;
833    }
834  }
835  return found;
836}
837
838FindInPageNotificationObserver::FindInPageNotificationObserver(
839    AutomationProvider* automation, TabContents* parent_tab,
840    bool reply_with_json, IPC::Message* reply_message)
841    : automation_(automation),
842      active_match_ordinal_(-1),
843      reply_with_json_(reply_with_json),
844      reply_message_(reply_message) {
845  registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE,
846                 Source<TabContents>(parent_tab));
847}
848
849FindInPageNotificationObserver::~FindInPageNotificationObserver() {
850}
851
852void FindInPageNotificationObserver::Observe(
853    NotificationType type, const NotificationSource& source,
854    const NotificationDetails& details) {
855  Details<FindNotificationDetails> find_details(details);
856  if (!(find_details->final_update() && reply_message_ != NULL)) {
857    DLOG(INFO) << "Ignoring, since we only care about the final message";
858    return;
859  }
860  // We get multiple responses and one of those will contain the ordinal.
861  // This message comes to us before the final update is sent.
862  if (find_details->request_id() == kFindInPageRequestId) {
863    if (reply_with_json_) {
864      scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
865      return_value->SetInteger("match_count",
866          find_details->number_of_matches());
867      gfx::Rect rect = find_details->selection_rect();
868      // If MatchCount is > 0, then rect should not be Empty.
869      // We dont guard it here because we want to let the test
870      // code catch this invalid case if needed.
871      if (!rect.IsEmpty()) {
872        return_value->SetInteger("match_left", rect.x());
873        return_value->SetInteger("match_top", rect.y());
874        return_value->SetInteger("match_right", rect.right());
875        return_value->SetInteger("match_bottom", rect.bottom());
876      }
877      AutomationJSONReply(automation_, reply_message_)
878          .SendSuccess(return_value.get());
879      delete this;
880    } else {
881      if (find_details->active_match_ordinal() > -1) {
882        active_match_ordinal_ = find_details->active_match_ordinal();
883        AutomationMsg_Find::WriteReplyParams(reply_message_,
884            active_match_ordinal_, find_details->number_of_matches());
885        automation_->Send(reply_message_);
886        reply_message_ = NULL;
887      }
888    }
889  }
890}
891
892// static
893const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
894
895DomOperationNotificationObserver::DomOperationNotificationObserver(
896    AutomationProvider* automation)
897    : automation_(automation) {
898  registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
899                 NotificationService::AllSources());
900}
901
902DomOperationNotificationObserver::~DomOperationNotificationObserver() {
903}
904
905void DomOperationNotificationObserver::Observe(
906    NotificationType type, const NotificationSource& source,
907    const NotificationDetails& details) {
908  if (NotificationType::DOM_OPERATION_RESPONSE == type) {
909    Details<DomOperationNotificationDetails> dom_op_details(details);
910
911    IPC::Message* reply_message = automation_->reply_message_release();
912    if (reply_message) {
913      AutomationMsg_DomOperation::WriteReplyParams(reply_message,
914                                                   dom_op_details->json());
915      automation_->Send(reply_message);
916    }
917  }
918}
919
920DocumentPrintedNotificationObserver::DocumentPrintedNotificationObserver(
921    AutomationProvider* automation, IPC::Message* reply_message)
922    : automation_(automation),
923      success_(false),
924      reply_message_(reply_message) {
925  registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
926                 NotificationService::AllSources());
927}
928
929DocumentPrintedNotificationObserver::~DocumentPrintedNotificationObserver() {
930  DCHECK(reply_message_ != NULL);
931  AutomationMsg_PrintNow::WriteReplyParams(reply_message_, success_);
932  automation_->Send(reply_message_);
933  automation_->RemoveNavigationStatusListener(this);
934}
935
936void DocumentPrintedNotificationObserver::Observe(
937    NotificationType type, const NotificationSource& source,
938    const NotificationDetails& details) {
939  using namespace printing;
940  DCHECK(type == NotificationType::PRINT_JOB_EVENT);
941  switch (Details<JobEventDetails>(details)->type()) {
942    case JobEventDetails::JOB_DONE: {
943      // Succeeded.
944      success_ = true;
945      delete this;
946      break;
947    }
948    case JobEventDetails::USER_INIT_CANCELED:
949    case JobEventDetails::FAILED: {
950      // Failed.
951      delete this;
952      break;
953    }
954    case JobEventDetails::NEW_DOC:
955    case JobEventDetails::USER_INIT_DONE:
956    case JobEventDetails::DEFAULT_INIT_DONE:
957    case JobEventDetails::NEW_PAGE:
958    case JobEventDetails::PAGE_DONE:
959    case JobEventDetails::DOC_DONE:
960    case JobEventDetails::ALL_PAGES_REQUESTED: {
961      // Don't care.
962      break;
963    }
964    default: {
965      NOTREACHED();
966      break;
967    }
968  }
969}
970
971MetricEventDurationObserver::MetricEventDurationObserver() {
972  registrar_.Add(this, NotificationType::METRIC_EVENT_DURATION,
973                 NotificationService::AllSources());
974}
975
976MetricEventDurationObserver::~MetricEventDurationObserver() {}
977
978int MetricEventDurationObserver::GetEventDurationMs(
979    const std::string& event_name) {
980  EventDurationMap::const_iterator it = durations_.find(event_name);
981  if (it == durations_.end())
982    return -1;
983  return it->second;
984}
985
986void MetricEventDurationObserver::Observe(NotificationType type,
987    const NotificationSource& source, const NotificationDetails& details) {
988  if (type != NotificationType::METRIC_EVENT_DURATION) {
989    NOTREACHED();
990    return;
991  }
992  MetricEventDurationDetails* metric_event_duration =
993      Details<MetricEventDurationDetails>(details).ptr();
994  durations_[metric_event_duration->event_name] =
995      metric_event_duration->duration_ms;
996}
997
998PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation,
999                                               IPC::Message* reply_message,
1000                                               TabContents* tab_contents)
1001  : automation_(automation),
1002    reply_message_(reply_message) {
1003  registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
1004                 Source<TabContents>(tab_contents));
1005}
1006
1007PageTranslatedObserver::~PageTranslatedObserver() {}
1008
1009void PageTranslatedObserver::Observe(NotificationType type,
1010                                     const NotificationSource& source,
1011                                     const NotificationDetails& details) {
1012  DCHECK(type == NotificationType::PAGE_TRANSLATED);
1013  AutomationJSONReply reply(automation_, reply_message_);
1014
1015  PageTranslatedDetails* translated_details =
1016      Details<PageTranslatedDetails>(details).ptr();
1017  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1018  return_value->SetBoolean(
1019      "translation_success",
1020      translated_details->error_type == TranslateErrors::NONE);
1021  reply.SendSuccess(return_value.get());
1022  delete this;
1023}
1024
1025TabLanguageDeterminedObserver::TabLanguageDeterminedObserver(
1026    AutomationProvider* automation, IPC::Message* reply_message,
1027    TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar)
1028  : automation_(automation),
1029    reply_message_(reply_message),
1030    tab_contents_(tab_contents),
1031    translate_bar_(translate_bar) {
1032  registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
1033                 Source<TabContents>(tab_contents));
1034}
1035
1036void TabLanguageDeterminedObserver::Observe(
1037    NotificationType type, const NotificationSource& source,
1038    const NotificationDetails& details) {
1039  DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED);
1040
1041  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1042  return_value->SetBoolean("page_translated",
1043                           tab_contents_->language_state().IsPageTranslated());
1044  return_value->SetBoolean(
1045      "can_translate_page", TranslatePrefs::CanTranslate(
1046          automation_->profile()->GetPrefs(),
1047          tab_contents_->language_state().original_language(),
1048          tab_contents_->GetURL()));
1049  return_value->SetString(
1050      "original_language",
1051      tab_contents_->language_state().original_language());
1052  if (translate_bar_) {
1053    DictionaryValue* bar_info = new DictionaryValue;
1054    std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string;
1055    type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] =
1056        "BEFORE_TRANSLATE";
1057    type_to_string[TranslateInfoBarDelegate::TRANSLATING] =
1058        "TRANSLATING";
1059    type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] =
1060        "AFTER_TRANSLATE";
1061    type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] =
1062        "TRANSLATION_ERROR";
1063
1064    bar_info->SetBoolean("always_translate_lang_button_showing",
1065                         translate_bar_->ShouldShowAlwaysTranslateButton());
1066    bar_info->SetBoolean("never_translate_lang_button_showing",
1067                         translate_bar_->ShouldShowNeverTranslateButton());
1068    bar_info->SetString("bar_state", type_to_string[translate_bar_->type()]);
1069    bar_info->SetString("target_lang_code",
1070                        translate_bar_->GetTargetLanguageCode());
1071    bar_info->SetString("original_lang_code",
1072                        translate_bar_->GetOriginalLanguageCode());
1073    return_value->Set("translate_bar", bar_info);
1074  }
1075  AutomationJSONReply(automation_, reply_message_)
1076      .SendSuccess(return_value.get());
1077  delete this;
1078}
1079
1080InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
1081                                           IPC::Message* reply_message,
1082                                           TabContents* tab_contents,
1083                                           int target_count)
1084    : automation_(automation),
1085      reply_message_(reply_message),
1086      tab_contents_(tab_contents),
1087      target_count_(target_count) {
1088  Source<TabContents> source(tab_contents);
1089  registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
1090  registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
1091  CheckCount();
1092}
1093
1094void InfoBarCountObserver::Observe(NotificationType type,
1095                                   const NotificationSource& source,
1096                                   const NotificationDetails& details) {
1097  DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED ||
1098         type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED);
1099  CheckCount();
1100}
1101
1102void InfoBarCountObserver::CheckCount() {
1103  if (tab_contents_->infobar_delegate_count() != target_count_)
1104    return;
1105
1106  AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, true);
1107  automation_->Send(reply_message_);
1108  delete this;
1109}
1110
1111#if defined(OS_CHROMEOS)
1112LoginManagerObserver::LoginManagerObserver(
1113    AutomationProvider* automation,
1114    IPC::Message* reply_message)
1115    : automation_(automation),
1116      reply_message_(reply_message) {
1117
1118  registrar_.Add(this, NotificationType::LOGIN_AUTHENTICATION,
1119                 NotificationService::AllSources());
1120}
1121
1122void LoginManagerObserver::Observe(NotificationType type,
1123                                   const NotificationSource& source,
1124                                   const NotificationDetails& details) {
1125  DCHECK(type == NotificationType::LOGIN_AUTHENTICATION);
1126  Details<AuthenticationNotificationDetails> auth_details(details);
1127  AutomationMsg_LoginWithUserAndPass::WriteReplyParams(reply_message_,
1128      auth_details->success());
1129  automation_->Send(reply_message_);
1130  delete this;
1131}
1132#endif
1133
1134AutomationProviderBookmarkModelObserver::
1135AutomationProviderBookmarkModelObserver(
1136    AutomationProvider* provider,
1137    IPC::Message* reply_message,
1138    BookmarkModel* model) {
1139  automation_provider_ = provider;
1140  reply_message_ = reply_message;
1141  model_ = model;
1142  model_->AddObserver(this);
1143}
1144
1145AutomationProviderBookmarkModelObserver::
1146~AutomationProviderBookmarkModelObserver() {
1147  model_->RemoveObserver(this);
1148}
1149
1150void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
1151  AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1152      reply_message_, success);
1153  automation_provider_->Send(reply_message_);
1154  delete this;
1155}
1156
1157void AutomationProviderDownloadItemObserver::OnDownloadFileCompleted(
1158    DownloadItem* download) {
1159  download->RemoveObserver(this);
1160  if (--downloads_ == 0) {
1161    AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
1162    delete this;
1163  }
1164}
1165
1166void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
1167    DownloadItem* download) {
1168  // If this observer is watching for open, only send the reply if the download
1169  // has been auto-opened.
1170  if (wait_for_open_ && !download->auto_opened())
1171    return;
1172
1173  download->RemoveObserver(this);
1174  scoped_ptr<DictionaryValue> return_value(
1175      provider_->GetDictionaryFromDownloadItem(download));
1176  AutomationJSONReply(provider_, reply_message_).SendSuccess(
1177      return_value.get());
1178  delete this;
1179}
1180
1181void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
1182    DownloadItem* download) {
1183  download->RemoveObserver(this);
1184  scoped_ptr<DictionaryValue> return_value(
1185      provider_->GetDictionaryFromDownloadItem(download));
1186  AutomationJSONReply(provider_, reply_message_).SendSuccess(
1187      return_value.get());
1188  delete this;
1189}
1190
1191void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
1192  AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
1193  download_manager_->RemoveObserver(this);
1194  delete this;
1195}
1196
1197void AutomationProviderSearchEngineObserver::OnTemplateURLModelChanged() {
1198  TemplateURLModel* url_model = provider_->profile()->GetTemplateURLModel();
1199  url_model->RemoveObserver(this);
1200  AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
1201  delete this;
1202}
1203
1204void AutomationProviderHistoryObserver::HistoryQueryComplete(
1205    HistoryService::Handle request_handle,
1206    history::QueryResults* results) {
1207  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1208
1209  ListValue* history_list = new ListValue;
1210  for (size_t i = 0; i < results->size(); ++i) {
1211    DictionaryValue* page_value = new DictionaryValue;
1212    history::URLResult const &page = (*results)[i];
1213    page_value->SetString("title", page.title());
1214    page_value->SetString("url", page.url().spec());
1215    page_value->SetReal("time",
1216                        static_cast<double>(page.visit_time().ToDoubleT()));
1217    page_value->SetString("snippet", page.snippet().text());
1218    page_value->SetBoolean(
1219        "starred",
1220        provider_->profile()->GetBookmarkModel()->IsBookmarked(page.url()));
1221    history_list->Append(page_value);
1222  }
1223
1224  return_value->Set("history", history_list);
1225  // Return history info.
1226  AutomationJSONReply reply(provider_, reply_message_);
1227  reply.SendSuccess(return_value.get());
1228  delete this;
1229}
1230
1231void AutomationProviderImportSettingsObserver::ImportEnded() {
1232  // Send back an empty success message.
1233  AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
1234  delete this;
1235}
1236
1237void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone(
1238    int handle, const std::vector<webkit_glue::PasswordForm*>& result) {
1239  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1240
1241  ListValue* passwords = new ListValue;
1242  for (std::vector<webkit_glue::PasswordForm*>::const_iterator it =
1243          result.begin(); it != result.end(); ++it) {
1244    DictionaryValue* password_val = new DictionaryValue;
1245    webkit_glue::PasswordForm* password_form = *it;
1246    password_val->SetString("username_value", password_form->username_value);
1247    password_val->SetString("password_value", password_form->password_value);
1248    password_val->SetString("signon_realm", password_form->signon_realm);
1249    password_val->SetReal(
1250        "time", static_cast<double>(password_form->date_created.ToDoubleT()));
1251    password_val->SetString("origin_url", password_form->origin.spec());
1252    password_val->SetString("username_element",
1253                            password_form->username_element);
1254    password_val->SetString("password_element",
1255                            password_form->password_element);
1256    password_val->SetString("submit_element",
1257                                     password_form->submit_element);
1258    password_val->SetString("action_target", password_form->action.spec());
1259    password_val->SetBoolean("blacklist", password_form->blacklisted_by_user);
1260    passwords->Append(password_val);
1261  }
1262
1263  return_value->Set("passwords", passwords);
1264  AutomationJSONReply(provider_, reply_message_).SendSuccess(
1265      return_value.get());
1266  delete this;
1267}
1268
1269void AutomationProviderBrowsingDataObserver::OnBrowsingDataRemoverDone() {
1270  // Send back an empty success message
1271  AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
1272  delete this;
1273}
1274
1275OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver(
1276    NavigationController* controller,
1277    AutomationProvider* automation,
1278    IPC::Message* reply_message)
1279  : automation_(automation),
1280    reply_message_(reply_message),
1281    controller_(controller) {
1282  Source<NavigationController> source(controller_);
1283  registrar_.Add(this, NotificationType::LOAD_STOP, source);
1284  // Pages requiring auth don't send LOAD_STOP.
1285  registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
1286}
1287
1288OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() {
1289  automation_->RemoveNavigationStatusListener(this);
1290}
1291
1292void OmniboxAcceptNotificationObserver::Observe(
1293    NotificationType type,
1294    const NotificationSource& source,
1295    const NotificationDetails& details) {
1296  if (type == NotificationType::LOAD_STOP ||
1297      type == NotificationType::AUTH_NEEDED) {
1298    AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL);
1299    delete this;
1300  } else {
1301    NOTREACHED();
1302  }
1303}
1304
1305SavePackageNotificationObserver::SavePackageNotificationObserver(
1306    SavePackage* save_package,
1307    AutomationProvider* automation,
1308    IPC::Message* reply_message) : automation_(automation),
1309                                   reply_message_(reply_message) {
1310  Source<SavePackage> source(save_package);
1311  registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
1312                 source);
1313}
1314
1315void SavePackageNotificationObserver::Observe(
1316    NotificationType type,
1317    const NotificationSource& source,
1318    const NotificationDetails& details) {
1319  if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) {
1320    AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL);
1321    delete this;
1322  } else {
1323    NOTREACHED();
1324  }
1325}
1326
1327AutocompleteEditFocusedObserver::AutocompleteEditFocusedObserver(
1328    AutomationProvider* automation,
1329    AutocompleteEditModel* autocomplete_edit,
1330    IPC::Message* reply_message)
1331    : automation_(automation),
1332      reply_message_(reply_message),
1333      autocomplete_edit_model_(autocomplete_edit) {
1334  Source<AutocompleteEditModel> source(autocomplete_edit);
1335  registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, source);
1336}
1337
1338void AutocompleteEditFocusedObserver::Observe(
1339    NotificationType type,
1340    const NotificationSource& source,
1341    const NotificationDetails& details) {
1342  DCHECK(type == NotificationType::AUTOCOMPLETE_EDIT_FOCUSED);
1343  AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams(
1344      reply_message_, true);
1345  automation_->Send(reply_message_);
1346  delete this;
1347}
1348
1349