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 16void GoogleSearchCounter::RegisterForNotifications() { 17 GoogleSearchCounter::GetInstance()->RegisterForNotificationsInternal(); 18} 19 20// static 21GoogleSearchCounter* GoogleSearchCounter::GetInstance() { 22 return Singleton<GoogleSearchCounter>::get(); 23} 24 25GoogleSearchMetrics::AccessPoint 26GoogleSearchCounter::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() == (ui::PAGE_TRANSITION_GENERATED | 34 ui::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 48bool 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 55GoogleSearchCounter::GoogleSearchCounter() 56 : search_metrics_(new GoogleSearchMetrics) { 57} 58 59GoogleSearchCounter::~GoogleSearchCounter() { 60} 61 62void 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 77void GoogleSearchCounter::SetSearchMetricsForTesting( 78 GoogleSearchMetrics* search_metrics) { 79 DCHECK(search_metrics); 80 search_metrics_.reset(search_metrics); 81} 82 83void 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 90void 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