Home | History | Annotate | Download | only in google
      1 // Copyright (c) 2012 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 
      8 #include <map>
      9 #include <string>
     10 #include <utility>
     11 
     12 #include "base/callback_forward.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/memory/weak_ptr.h"
     16 #include "chrome/browser/google/google_url_tracker_map_entry.h"
     17 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
     18 #include "net/base/network_change_notifier.h"
     19 #include "net/url_request/url_fetcher.h"
     20 #include "net/url_request/url_fetcher_delegate.h"
     21 #include "url/gurl.h"
     22 
     23 class GoogleURLTrackerNavigationHelper;
     24 class PrefService;
     25 class Profile;
     26 
     27 namespace content {
     28 class NavigationController;
     29 }
     30 
     31 // This object is responsible for checking the Google URL once per network
     32 // change, and if necessary prompting the user to see if they want to change to
     33 // using it.  The current and last prompted values are saved to prefs.
     34 //
     35 // Most consumers should only call GoogleURL(), which is guaranteed to
     36 // synchronously return a value at all times (even during startup or in unittest
     37 // mode).  Consumers who need to be notified when things change should listen to
     38 // the notification service for NOTIFICATION_GOOGLE_URL_UPDATED, which provides
     39 // the original and updated values.
     40 //
     41 // To protect users' privacy and reduce server load, no updates will be
     42 // performed (ever) unless at least one consumer registers interest by calling
     43 // RequestServerCheck().
     44 class GoogleURLTracker : public net::URLFetcherDelegate,
     45                          public net::NetworkChangeNotifier::IPAddressObserver,
     46                          public BrowserContextKeyedService {
     47  public:
     48   // The contents of the Details for a NOTIFICATION_GOOGLE_URL_UPDATED.
     49   typedef std::pair<GURL, GURL> UpdatedDetails;
     50 
     51   // The constructor does different things depending on which of these values
     52   // you pass it.  Hopefully these are self-explanatory.
     53   enum Mode {
     54     NORMAL_MODE,
     55     UNIT_TEST_MODE,
     56   };
     57 
     58   // Only the GoogleURLTrackerFactory and tests should call this.  No code other
     59   // than the GoogleURLTracker itself should actually use
     60   // GoogleURLTrackerFactory::GetForProfile().
     61   GoogleURLTracker(Profile* profile,
     62                    scoped_ptr<GoogleURLTrackerNavigationHelper> nav_helper,
     63                    Mode mode);
     64 
     65   virtual ~GoogleURLTracker();
     66 
     67   // Returns the current Google URL.  This will return a valid URL even if
     68   // |profile| is NULL or a testing profile.
     69   //
     70   // This is the only function most code should ever call.
     71   static GURL GoogleURL(Profile* profile);
     72 
     73   // Requests that the tracker perform a server check to update the Google URL
     74   // as necessary.  If |force| is false, this will happen at most once per
     75   // network change, not sooner than five seconds after startup (checks
     76   // requested before that time will occur then; checks requested afterwards
     77   // will occur immediately, if no other checks have been made during this run).
     78   // If |force| is true, and the tracker has already performed any requested
     79   // check, it will check again.
     80   //
     81   // When |profile| is NULL or a testing profile, this function does nothing.
     82   static void RequestServerCheck(Profile* profile, bool force);
     83 
     84   // Notifies the tracker that the user has started a Google search.
     85   // If prompting is necessary, we then listen for the subsequent pending
     86   // navigation to get the appropriate NavigationController. When the load
     87   // commits, we'll show the infobar.
     88   //
     89   // When |profile| is NULL or a testing profile, this function does nothing.
     90   static void GoogleURLSearchCommitted(Profile* profile);
     91 
     92   // No one but GoogleURLTrackerInfoBarDelegate or test code should call these.
     93   void AcceptGoogleURL(bool redo_searches);
     94   void CancelGoogleURL();
     95   const GURL& google_url() const { return google_url_; }
     96   const GURL& fetched_google_url() const { return fetched_google_url_; }
     97 
     98   // No one but GoogleURLTrackerMapEntry should call this.
     99   void DeleteMapEntryForService(const InfoBarService* infobar_service);
    100 
    101   // Called by the navigation observer after SearchCommitted() registers
    102   // listeners, to indicate that we've received the "load now pending"
    103   // notification.  |navigation_controller| is the NavigationController for this
    104   // load; |infobar_service| is the InfoBarService of the associated tab; and
    105   // |pending_id| is the unique ID of the newly pending NavigationEntry.
    106   // If there is already a visible GoogleURLTracker infobar for this tab, this
    107   // function resets its associated pending entry ID to the new ID.  Otherwise
    108   // this function creates a map entry for the associated tab.
    109   virtual void OnNavigationPending(
    110       content::NavigationController* navigation_controller,
    111       InfoBarService* infobar_service,
    112       int pending_id);
    113 
    114   // Called by the navigation observer once a load we're watching commits.
    115   // |infobar_service| is the same as for OnNavigationPending();
    116   // |search_url| is guaranteed to be valid.
    117   virtual void OnNavigationCommitted(InfoBarService* infobar_service,
    118                                      const GURL& search_url);
    119 
    120   // Called by the navigation observer when a tab closes.
    121   virtual void OnTabClosed(
    122       content::NavigationController* navigation_controller);
    123 
    124   static const char kDefaultGoogleHomepage[];
    125   static const char kSearchDomainCheckURL[];
    126 
    127  private:
    128   friend class GoogleURLTrackerTest;
    129 
    130   typedef std::map<const InfoBarService*, GoogleURLTrackerMapEntry*> EntryMap;
    131 
    132   // net::URLFetcherDelegate:
    133   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
    134 
    135   // NetworkChangeNotifier::IPAddressObserver:
    136   virtual void OnIPAddressChanged() OVERRIDE;
    137 
    138   // BrowserContextKeyedService:
    139   virtual void Shutdown() OVERRIDE;
    140 
    141   // Registers consumer interest in getting an updated URL from the server.
    142   // Observe chrome::NOTIFICATION_GOOGLE_URL_UPDATED to be notified when the URL
    143   // changes.
    144   void SetNeedToFetch();
    145 
    146   // Called when the five second startup sleep has finished.  Runs any pending
    147   // fetch.
    148   void FinishSleep();
    149 
    150   // Starts the fetch of the up-to-date Google URL if we actually want to fetch
    151   // it and can currently do so.
    152   void StartFetchIfDesirable();
    153 
    154   // Called each time the user performs a search.  This checks whether we need
    155   // to prompt the user about a domain change, and if so, starts listening for
    156   // the notifications sent when the actual load is triggered.
    157   void SearchCommitted();
    158 
    159   // Closes all map entries.  If |redo_searches| is true, this also triggers
    160   // each tab with an infobar to re-perform the user's search, but on the new
    161   // Google TLD.
    162   void CloseAllEntries(bool redo_searches);
    163 
    164   // Unregisters any listeners for the navigation controller in |map_entry|.
    165   // This sanity-DCHECKs that these are registered (or not) in the specific
    166   // cases we expect.  (|must_be_listening_for_commit| is used purely for this
    167   // sanity-checking.)  This also unregisters the global navigation pending
    168   // listener if there are no remaining listeners for navigation commits, as we
    169   // no longer need them until another search is committed.
    170   void UnregisterForEntrySpecificNotifications(
    171       const GoogleURLTrackerMapEntry& map_entry,
    172       bool must_be_listening_for_commit);
    173 
    174   Profile* profile_;
    175 
    176   scoped_ptr<GoogleURLTrackerNavigationHelper> nav_helper_;
    177 
    178   // Creates an infobar delegate and adds it to the provided InfoBarService.
    179   // Returns the delegate pointer on success or NULL on failure.  The caller
    180   // does not own the returned object, the InfoBarService does.
    181   base::Callback<GoogleURLTrackerInfoBarDelegate*(
    182       InfoBarService*,
    183       GoogleURLTracker*,
    184       const GURL&)> infobar_creator_;
    185 
    186   GURL google_url_;
    187   GURL fetched_google_url_;
    188   base::WeakPtrFactory<GoogleURLTracker> weak_ptr_factory_;
    189   scoped_ptr<net::URLFetcher> fetcher_;
    190   int fetcher_id_;
    191   bool in_startup_sleep_;  // True if we're in the five-second "no fetching"
    192                            // period that begins at browser start.
    193   bool already_fetched_;   // True if we've already fetched a URL once this run;
    194                            // we won't fetch again until after a restart.
    195   bool need_to_fetch_;     // True if a consumer actually wants us to fetch an
    196                            // updated URL.  If this is never set, we won't
    197                            // bother to fetch anything.
    198                            // Consumers should observe
    199                            // chrome::NOTIFICATION_GOOGLE_URL_UPDATED.
    200   bool need_to_prompt_;    // True if the last fetched Google URL is not
    201                            // matched with current user's default Google URL
    202                            // nor the last prompted Google URL.
    203   bool search_committed_;  // True when we're expecting a notification of a new
    204                            // pending search navigation.
    205   EntryMap entry_map_;
    206 
    207   DISALLOW_COPY_AND_ASSIGN(GoogleURLTracker);
    208 };
    209 
    210 #endif  // CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_
    211