1// Copyright 2013 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#ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
6#define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
7
8#include <map>
9#include <string>
10
11#include "base/basictypes.h"
12#include "base/compiler_specific.h"
13#include "chrome/browser/extensions/api/tabs/tabs_api.h"
14#include "chrome/browser/ui/browser_list_observer.h"
15#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
16#include "chrome/browser/ui/zoom/zoom_observer.h"
17#include "content/public/browser/notification_registrar.h"
18#include "extensions/browser/event_router.h"
19
20namespace content {
21class WebContents;
22}
23
24namespace extensions {
25
26// The TabsEventRouter listens to tab events and routes them to listeners inside
27// extension process renderers.
28// TabsEventRouter will only route events from windows/tabs within a profile to
29// extension processes in the same profile.
30class TabsEventRouter : public TabStripModelObserver,
31                        public chrome::BrowserListObserver,
32                        public content::NotificationObserver,
33                        public ZoomObserver {
34 public:
35  explicit TabsEventRouter(Profile* profile);
36  virtual ~TabsEventRouter();
37
38  // chrome::BrowserListObserver
39  virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
40  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
41  virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
42
43  // TabStripModelObserver
44  virtual void TabInsertedAt(content::WebContents* contents, int index,
45                             bool active) OVERRIDE;
46  virtual void TabClosingAt(TabStripModel* tab_strip_model,
47                            content::WebContents* contents,
48                            int index) OVERRIDE;
49  virtual void TabDetachedAt(content::WebContents* contents,
50                             int index) OVERRIDE;
51  virtual void ActiveTabChanged(content::WebContents* old_contents,
52                                content::WebContents* new_contents,
53                                int index,
54                                int reason) OVERRIDE;
55  virtual void TabSelectionChanged(
56      TabStripModel* tab_strip_model,
57      const ui::ListSelectionModel& old_model) OVERRIDE;
58  virtual void TabMoved(content::WebContents* contents,
59                        int from_index,
60                        int to_index) OVERRIDE;
61  virtual void TabChangedAt(content::WebContents* contents,
62                            int index,
63                            TabChangeType change_type) OVERRIDE;
64  virtual void TabReplacedAt(TabStripModel* tab_strip_model,
65                             content::WebContents* old_contents,
66                             content::WebContents* new_contents,
67                             int index) OVERRIDE;
68  virtual void TabPinnedStateChanged(content::WebContents* contents,
69                                     int index) OVERRIDE;
70
71  // content::NotificationObserver.
72  virtual void Observe(int type,
73                       const content::NotificationSource& source,
74                       const content::NotificationDetails& details) OVERRIDE;
75
76  // ZoomObserver.
77  virtual void OnZoomChanged(
78      const ZoomController::ZoomChangedEventData& data) OVERRIDE;
79
80 private:
81  // "Synthetic" event. Called from TabInsertedAt if new tab is detected.
82  void TabCreatedAt(content::WebContents* contents, int index, bool active);
83
84  // Internal processing of tab updated events. Is called by both TabChangedAt
85  // and Observe/NAV_ENTRY_COMMITTED.
86  void TabUpdated(content::WebContents* contents, bool did_navigate);
87
88  // Triggers a tab updated event if the favicon URL changes.
89  void FaviconUrlUpdated(content::WebContents* contents);
90
91  // The DispatchEvent methods forward events to the |profile|'s event router.
92  // The TabsEventRouter listens to events for all profiles,
93  // so we avoid duplication by dropping events destined for other profiles.
94  void DispatchEvent(Profile* profile,
95                     const std::string& event_name,
96                     scoped_ptr<base::ListValue> args,
97                     EventRouter::UserGestureState user_gesture);
98
99  void DispatchEventsAcrossIncognito(
100      Profile* profile,
101      const std::string& event_name,
102      scoped_ptr<base::ListValue> event_args,
103      scoped_ptr<base::ListValue> cross_incognito_args);
104
105  void DispatchSimpleBrowserEvent(Profile* profile,
106                                  const int window_id,
107                                  const std::string& event_name);
108
109  // Packages |changed_properties| as a tab updated event for the tab |contents|
110  // and dispatches the event to the extension.
111  void DispatchTabUpdatedEvent(
112      content::WebContents* contents,
113      scoped_ptr<base::DictionaryValue> changed_properties);
114
115  // Register ourselves to receive the various notifications we are interested
116  // in for a browser.
117  void RegisterForBrowserNotifications(Browser* browser);
118
119  // Register ourselves to receive the various notifications we are interested
120  // in for a tab.
121  void RegisterForTabNotifications(content::WebContents* contents);
122
123  // Removes notifications added in RegisterForTabNotifications.
124  void UnregisterForTabNotifications(content::WebContents* contents);
125
126  content::NotificationRegistrar registrar_;
127
128  // Maintain some information about known tabs, so we can:
129  //
130  //  - distinguish between tab creation and tab insertion
131  //  - not send tab-detached after tab-removed
132  //  - reduce the "noise" of TabChangedAt() when sending events to extensions
133  class TabEntry {
134   public:
135    // Create a new tab entry whose initial state is TAB_COMPLETE.  This
136    // constructor is required because TabEntry objects placed inside an
137    // std::map<> by value.
138    TabEntry();
139
140    // Update the load state of the tab based on its WebContents.  Returns true
141    // if the state changed, false otherwise.  Whether the state has changed or
142    // not is used to determine if events needs to be sent to extensions during
143    // processing of TabChangedAt(). This method will "hold" a state-change
144    // to "loading", until the DidNavigate() method which should always follow
145    // it. Returns NULL if no updates should be sent.
146    base::DictionaryValue* UpdateLoadState(
147        const content::WebContents* contents);
148
149    // Indicates that a tab load has resulted in a navigation and the
150    // destination url is available for inspection. Returns NULL if no updates
151    // should be sent.
152    base::DictionaryValue* DidNavigate(const content::WebContents* contents);
153
154   private:
155    // Whether we are waiting to fire the 'complete' status change. This will
156    // occur the first time the WebContents stops loading after the
157    // NAV_ENTRY_COMMITTED was fired. The tab may go back into and out of the
158    // loading state subsequently, but we will ignore those changes.
159    bool complete_waiting_on_load_;
160
161    GURL url_;
162  };
163
164  // Gets the TabEntry for the given |contents|. Returns TabEntry* if
165  // found, NULL if not.
166  TabEntry* GetTabEntry(content::WebContents* contents);
167
168  std::map<int, TabEntry> tab_entries_;
169
170  // The main profile that owns this event router.
171  Profile* profile_;
172
173  DISALLOW_COPY_AND_ASSIGN(TabsEventRouter);
174};
175
176}  // namespace extensions
177
178#endif  // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
179