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#ifndef CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_
6#define CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_
7#pragma once
8
9#include <string>
10
11#include "base/gtest_prod_util.h"
12#include "base/memory/scoped_ptr.h"
13#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
14#include "chrome/common/net/url_fetcher.h"
15#include "content/common/notification_observer.h"
16#include "content/common/notification_registrar.h"
17#include "googleurl/src/gurl.h"
18#include "net/base/network_change_notifier.h"
19
20class NavigationController;
21class PrefService;
22class TabContents;
23class TemplateURL;
24
25// This object is responsible for checking the Google URL once per network
26// change, and if necessary prompting the user to see if they want to change to
27// using it.  The current and last prompted values are saved to prefs.
28//
29// Most consumers should only call GoogleURL(), which is guaranteed to
30// synchronously return a value at all times (even during startup or in unittest
31// mode).  Consumers who need to be notified when things change should listen to
32// the notification service for NOTIFY_GOOGLE_URL_UPDATED, and call GoogleURL()
33// again after receiving it, in order to get the updated value.
34//
35// To protect users' privacy and reduce server load, no updates will be
36// performed (ever) unless at least one consumer registers interest by calling
37// RequestServerCheck().
38class GoogleURLTracker : public URLFetcher::Delegate,
39                         public NotificationObserver,
40                         public net::NetworkChangeNotifier::IPAddressObserver {
41 public:
42  // Only the main browser process loop should call this, when setting up
43  // g_browser_process->google_url_tracker_.  No code other than the
44  // GoogleURLTracker itself should actually use
45  // g_browser_process->google_url_tracker() (which shouldn't be hard, since
46  // there aren't useful public functions on this object for consumers to access
47  // anyway).
48  GoogleURLTracker();
49
50  virtual ~GoogleURLTracker();
51
52  // Returns the current Google URL.  This will return a valid URL even in
53  // unittest mode.
54  //
55  // This is the only function most code should ever call.
56  static GURL GoogleURL();
57
58  // Requests that the tracker perform a server check to update the Google URL
59  // as necessary.  This will happen at most once per network change, not
60  // sooner than five seconds after startup (checks requested before that time
61  // will occur then; checks requested afterwards will occur immediately, if
62  // no other checks have been made during this run).
63  //
64  // In unittest mode, this function does nothing.
65  static void RequestServerCheck();
66
67  static void RegisterPrefs(PrefService* prefs);
68
69  // Notifies the tracker that the user has started a Google search.
70  // If prompting is necessary, we then listen for the subsequent
71  // NAV_ENTRY_PENDING notification to get the appropriate NavigationController.
72  // When the load commits, we'll show the infobar.
73  static void GoogleURLSearchCommitted();
74
75  static const char kDefaultGoogleHomepage[];
76  static const char kSearchDomainCheckURL[];
77
78  // Methods called from InfoBar delegate.
79  void AcceptGoogleURL(const GURL& google_url);
80  void CancelGoogleURL(const GURL& google_url);
81  void InfoBarClosed();
82  void RedoSearch();
83
84 private:
85  friend class GoogleURLTrackerTest;
86
87  typedef InfoBarDelegate* (*InfobarCreator)(TabContents*,
88                                             GoogleURLTracker*,
89                                             const GURL&);
90
91  // Registers consumer interest in getting an updated URL from the server.
92  // It will be notified as NotificationType::GOOGLE_URL_UPDATED, so the
93  // consumer should observe this notification before calling this.
94  void SetNeedToFetch();
95
96  // Begins the five-second startup sleep period, unless a test has cleared
97  // |queue_wakeup_task_|.
98  void QueueWakeupTask();
99
100  // Called when the five second startup sleep has finished.  Runs any pending
101  // fetch.
102  void FinishSleep();
103
104  // Starts the fetch of the up-to-date Google URL if we actually want to fetch
105  // it and can currently do so.
106  void StartFetchIfDesirable();
107
108  // URLFetcher::Delegate
109  virtual void OnURLFetchComplete(const URLFetcher *source,
110                                  const GURL& url,
111                                  const net::URLRequestStatus& status,
112                                  int response_code,
113                                  const ResponseCookies& cookies,
114                                  const std::string& data);
115
116  // NotificationObserver
117  virtual void Observe(NotificationType type,
118                       const NotificationSource& source,
119                       const NotificationDetails& details);
120
121  // NetworkChangeNotifier::IPAddressObserver
122  virtual void OnIPAddressChanged();
123
124  void SearchCommitted();
125  void OnNavigationPending(const NotificationSource& source,
126                           const GURL& pending_url);
127  void OnNavigationCommittedOrTabClosed(TabContents* tab_contents,
128                                        NotificationType::Type type);
129  void ShowGoogleURLInfoBarIfNecessary(TabContents* tab_contents);
130
131  NotificationRegistrar registrar_;
132  InfobarCreator infobar_creator_;
133  // TODO(ukai): GoogleURLTracker should track google domain (e.g. google.co.uk)
134  // rather than URL (e.g. http://www.google.co.uk/), so that user could
135  // configure to use https in search engine templates.
136  GURL google_url_;
137  GURL fetched_google_url_;
138  ScopedRunnableMethodFactory<GoogleURLTracker> runnable_method_factory_;
139  scoped_ptr<URLFetcher> fetcher_;
140  int fetcher_id_;
141  bool queue_wakeup_task_;
142  bool in_startup_sleep_;  // True if we're in the five-second "no fetching"
143                           // period that begins at browser start.
144  bool already_fetched_;   // True if we've already fetched a URL once this run;
145                           // we won't fetch again until after a restart.
146  bool need_to_fetch_;     // True if a consumer actually wants us to fetch an
147                           // updated URL.  If this is never set, we won't
148                           // bother to fetch anything.
149                           // Consumers should observe
150                           // NotificationType::GOOGLE_URL_UPDATED.
151  bool need_to_prompt_;    // True if the last fetched Google URL is not
152                           // matched with current user's default Google URL
153                           // nor the last prompted Google URL.
154  NavigationController* controller_;
155  InfoBarDelegate* infobar_;
156  GURL search_url_;
157
158  DISALLOW_COPY_AND_ASSIGN(GoogleURLTracker);
159};
160
161
162// This infobar delegate is declared here (rather than in the .cc file) so test
163// code can subclass it.
164class GoogleURLTrackerInfoBarDelegate : public ConfirmInfoBarDelegate {
165 public:
166  GoogleURLTrackerInfoBarDelegate(TabContents* tab_contents,
167                                  GoogleURLTracker* google_url_tracker,
168                                  const GURL& new_google_url);
169
170  // ConfirmInfoBarDelegate:
171  virtual bool Accept();
172  virtual bool Cancel();
173  virtual void InfoBarClosed();
174
175 protected:
176  virtual ~GoogleURLTrackerInfoBarDelegate();
177
178  GoogleURLTracker* google_url_tracker_;
179  const GURL new_google_url_;
180
181 private:
182  // ConfirmInfoBarDelegate:
183  virtual string16 GetMessageText() const;
184  virtual string16 GetButtonLabel(InfoBarButton button) const;
185
186  DISALLOW_COPY_AND_ASSIGN(GoogleURLTrackerInfoBarDelegate);
187};
188
189#endif  // CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_
190