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 #include "chrome/browser/google/google_search_counter.h" 6 7 #include "base/logging.h" 8 #include "chrome/browser/google/google_util.h" 9 #include "content/public/browser/navigation_controller.h" 10 #include "content/public/browser/navigation_details.h" 11 #include "content/public/browser/navigation_entry.h" 12 #include "content/public/browser/notification_service.h" 13 #include "content/public/browser/notification_types.h" 14 15 namespace { 16 17 // Returns true iff |entry| represents a Google search from the Omnibox. 18 // This method assumes that we have already verified that |entry|'s URL is a 19 // Google search URL. 20 bool IsOmniboxGoogleSearchNavigation(const content::NavigationEntry& entry) { 21 const content::PageTransition stripped_transition = 22 PageTransitionStripQualifier(entry.GetTransitionType()); 23 DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL())); 24 return stripped_transition == content::PAGE_TRANSITION_GENERATED; 25 } 26 27 // Returns true iff |entry| represents a Google search from the Google Search 28 // App. This method assumes that we have already verified that |entry|'s URL is 29 // a Google search URL. 30 bool IsSearchAppGoogleSearchNavigation(const content::NavigationEntry& entry) { 31 DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL())); 32 return entry.GetURL().query().find("source=search_app") != 33 std::string::npos; 34 } 35 36 } // namespace 37 38 // static 39 void GoogleSearchCounter::RegisterForNotifications() { 40 GoogleSearchCounter::GetInstance()->RegisterForNotificationsInternal(); 41 } 42 43 // static 44 GoogleSearchCounter* GoogleSearchCounter::GetInstance() { 45 return Singleton<GoogleSearchCounter>::get(); 46 } 47 48 GoogleSearchCounter::GoogleSearchCounter() 49 : search_metrics_(new GoogleSearchMetrics) { 50 } 51 52 GoogleSearchCounter::~GoogleSearchCounter() { 53 } 54 55 void GoogleSearchCounter::ProcessCommittedEntry( 56 const content::NotificationSource& source, 57 const content::NotificationDetails& details) { 58 const content::LoadCommittedDetails* commit = 59 content::Details<content::LoadCommittedDetails>(details).ptr(); 60 const content::NavigationEntry& entry = *commit->entry; 61 62 // First see if this is a Google search URL at all. 63 if (!google_util::IsGoogleSearchUrl(entry.GetURL())) 64 return; 65 66 // If the commit is a GENERATED commit with a Google search URL, we know it's 67 // an Omnibox search. 68 if (IsOmniboxGoogleSearchNavigation(entry)) { 69 // Note that GoogleSearchMetrics logs metrics through UMA, which will only 70 // transmit these counts to the server if the user has opted into sending 71 // usage stats. 72 search_metrics_->RecordGoogleSearch(GoogleSearchMetrics::AP_OMNIBOX); 73 } else if (IsSearchAppGoogleSearchNavigation(entry)) { 74 search_metrics_->RecordGoogleSearch(GoogleSearchMetrics::AP_SEARCH_APP); 75 } else { 76 // For all other cases that we have not yet implemented or care to measure, 77 // we log a generic "catch-all" metric. 78 search_metrics_->RecordGoogleSearch(GoogleSearchMetrics::AP_OTHER); 79 } 80 } 81 82 void GoogleSearchCounter::SetSearchMetricsForTesting( 83 GoogleSearchMetrics* search_metrics) { 84 DCHECK(search_metrics); 85 search_metrics_.reset(search_metrics); 86 } 87 88 void GoogleSearchCounter::RegisterForNotificationsInternal() { 89 // We always listen for all COMMITTED navigations from all sources, as any 90 // one of them could be a navigation of interest. 91 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 92 content::NotificationService::AllSources()); 93 } 94 95 void GoogleSearchCounter::Observe(int type, 96 const content::NotificationSource& source, 97 const content::NotificationDetails& details) { 98 switch (type) { 99 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: 100 ProcessCommittedEntry(source, details); 101 break; 102 default: 103 NOTREACHED(); 104 } 105 } 106