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 "components/google/core/browser/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 // static 16 void GoogleSearchCounter::RegisterForNotifications() { 17 GoogleSearchCounter::GetInstance()->RegisterForNotificationsInternal(); 18 } 19 20 // static 21 GoogleSearchCounter* GoogleSearchCounter::GetInstance() { 22 return Singleton<GoogleSearchCounter>::get(); 23 } 24 25 GoogleSearchMetrics::AccessPoint 26 GoogleSearchCounter::GetGoogleSearchAccessPointForSearchNavEntry( 27 const content::NavigationEntry& entry) const { 28 DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL())); 29 30 // If the |entry| is FROM_ADDRESS_BAR, it comes from the omnibox; if it's 31 // GENERATED, the user was doing a search, rather than doing a navigation to a 32 // search URL (e.g. from hisotry, or pasted in). 33 if (entry.GetTransitionType() == (content::PAGE_TRANSITION_GENERATED | 34 content::PAGE_TRANSITION_FROM_ADDRESS_BAR)) { 35 return GoogleSearchMetrics::AP_OMNIBOX; 36 } 37 38 // The string "source=search_app" in the |entry| URL represents a Google 39 // search from the Google Search App. 40 if (entry.GetURL().query().find("source=search_app") != std::string::npos) 41 return GoogleSearchMetrics::AP_SEARCH_APP; 42 43 // For all other cases that we have not yet implemented or care to measure, we 44 // log a generic "catch-all" metric. 45 return GoogleSearchMetrics::AP_OTHER; 46 } 47 48 bool GoogleSearchCounter::ShouldRecordCommittedDetails( 49 const content::NotificationDetails& details) const { 50 const content::LoadCommittedDetails* commit = 51 content::Details<content::LoadCommittedDetails>(details).ptr(); 52 return google_util::IsGoogleSearchUrl(commit->entry->GetURL()); 53 } 54 55 GoogleSearchCounter::GoogleSearchCounter() 56 : search_metrics_(new GoogleSearchMetrics) { 57 } 58 59 GoogleSearchCounter::~GoogleSearchCounter() { 60 } 61 62 void GoogleSearchCounter::ProcessCommittedEntry( 63 const content::NotificationSource& source, 64 const content::NotificationDetails& details) { 65 // Note that GoogleSearchMetrics logs metrics through UMA, which will only 66 // transmit these counts to the server if the user has opted into sending 67 // usage stats. 68 const content::LoadCommittedDetails* commit = 69 content::Details<content::LoadCommittedDetails>(details).ptr(); 70 const content::NavigationEntry& entry = *commit->entry; 71 if (ShouldRecordCommittedDetails(details)) { 72 search_metrics_->RecordGoogleSearch( 73 GetGoogleSearchAccessPointForSearchNavEntry(entry)); 74 } 75 } 76 77 void GoogleSearchCounter::SetSearchMetricsForTesting( 78 GoogleSearchMetrics* search_metrics) { 79 DCHECK(search_metrics); 80 search_metrics_.reset(search_metrics); 81 } 82 83 void GoogleSearchCounter::RegisterForNotificationsInternal() { 84 // We always listen for all COMMITTED navigations from all sources, as any 85 // one of them could be a navigation of interest. 86 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 87 content::NotificationService::AllSources()); 88 } 89 90 void GoogleSearchCounter::Observe(int type, 91 const content::NotificationSource& source, 92 const content::NotificationDetails& details) { 93 switch (type) { 94 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: 95 ProcessCommittedEntry(source, details); 96 break; 97 default: 98 NOTREACHED(); 99 } 100 } 101