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/ui/webui/ntp/new_tab_page_handler.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/metrics/histogram.h"
11#include "base/prefs/pref_service.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/sync/profile_sync_service.h"
14#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
15#include "chrome/browser/web_resource/notification_promo.h"
16#include "chrome/common/pref_names.h"
17#include "components/user_prefs/pref_registry_syncable.h"
18#include "content/public/browser/notification_service.h"
19#include "content/public/browser/web_ui.h"
20#include "grit/chromium_strings.h"
21#include "grit/generated_resources.h"
22#include "ui/base/l10n/l10n_util.h"
23
24namespace {
25
26const char kDefaultPageTypeHistogram[] = "NewTabPage.DefaultPageType";
27
28enum PromoAction {
29  PROMO_VIEWED = 0,
30  PROMO_CLOSED,
31  PROMO_LINK_CLICKED,
32  PROMO_ACTION_MAX,
33};
34
35}  // namespace
36
37NewTabPageHandler::NewTabPageHandler() : page_switch_count_(0) {
38}
39
40NewTabPageHandler::~NewTabPageHandler() {
41  HISTOGRAM_COUNTS_100("NewTabPage.SingleSessionPageSwitches",
42                       page_switch_count_);
43}
44
45void NewTabPageHandler::RegisterMessages() {
46  // Record an open of the NTP with its default page type.
47  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
48  int shown_page_type = prefs->GetInteger(prefs::kNtpShownPage) >>
49      kPageIdOffset;
50  UMA_HISTOGRAM_ENUMERATION(kDefaultPageTypeHistogram,
51                            shown_page_type, kHistogramEnumerationMax);
52
53  web_ui()->RegisterMessageCallback("notificationPromoClosed",
54      base::Bind(&NewTabPageHandler::HandleNotificationPromoClosed,
55                 base::Unretained(this)));
56  web_ui()->RegisterMessageCallback("notificationPromoViewed",
57      base::Bind(&NewTabPageHandler::HandleNotificationPromoViewed,
58                 base::Unretained(this)));
59  web_ui()->RegisterMessageCallback("notificationPromoLinkClicked",
60      base::Bind(&NewTabPageHandler::HandleNotificationPromoLinkClicked,
61                 base::Unretained(this)));
62  web_ui()->RegisterMessageCallback("bubblePromoClosed",
63      base::Bind(&NewTabPageHandler::HandleBubblePromoClosed,
64                 base::Unretained(this)));
65  web_ui()->RegisterMessageCallback("bubblePromoViewed",
66      base::Bind(&NewTabPageHandler::HandleBubblePromoViewed,
67                 base::Unretained(this)));
68  web_ui()->RegisterMessageCallback("bubblePromoLinkClicked",
69      base::Bind(&NewTabPageHandler::HandleBubblePromoLinkClicked,
70                 base::Unretained(this)));
71  web_ui()->RegisterMessageCallback("pageSelected",
72      base::Bind(&NewTabPageHandler::HandlePageSelected,
73                 base::Unretained(this)));
74  web_ui()->RegisterMessageCallback("logTimeToClick",
75      base::Bind(&NewTabPageHandler::HandleLogTimeToClick,
76                 base::Unretained(this)));
77}
78
79void NewTabPageHandler::HandleNotificationPromoClosed(const ListValue* args) {
80  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
81                            PROMO_CLOSED, PROMO_ACTION_MAX);
82  NotificationPromo::HandleClosed(NotificationPromo::NTP_NOTIFICATION_PROMO);
83  Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
84}
85
86void NewTabPageHandler::HandleNotificationPromoViewed(const ListValue* args) {
87  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
88                            PROMO_VIEWED, PROMO_ACTION_MAX);
89  if (NotificationPromo::HandleViewed(
90          NotificationPromo::NTP_NOTIFICATION_PROMO)) {
91    Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
92  }
93}
94
95void NewTabPageHandler::HandleNotificationPromoLinkClicked(
96    const ListValue* args) {
97  DVLOG(1) << "HandleNotificationPromoLinkClicked";
98  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
99                            PROMO_LINK_CLICKED, PROMO_ACTION_MAX);
100}
101
102void NewTabPageHandler::HandleBubblePromoClosed(const ListValue* args) {
103  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Bubble",
104                            PROMO_CLOSED, PROMO_ACTION_MAX);
105  NotificationPromo::HandleClosed(NotificationPromo::NTP_BUBBLE_PROMO);
106  Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
107}
108
109void NewTabPageHandler::HandleBubblePromoViewed(const ListValue* args) {
110  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Bubble",
111                            PROMO_VIEWED, PROMO_ACTION_MAX);
112  if (NotificationPromo::HandleViewed(NotificationPromo::NTP_BUBBLE_PROMO))
113    Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
114}
115
116void NewTabPageHandler::HandleBubblePromoLinkClicked(const ListValue* args) {
117  DVLOG(1) << "HandleBubblePromoLinkClicked";
118  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Bubble",
119                            PROMO_LINK_CLICKED, PROMO_ACTION_MAX);
120}
121
122void NewTabPageHandler::HandlePageSelected(const ListValue* args) {
123  page_switch_count_++;
124
125  double page_id_double;
126  CHECK(args->GetDouble(0, &page_id_double));
127  int page_id = static_cast<int>(page_id_double);
128
129  double index_double;
130  CHECK(args->GetDouble(1, &index_double));
131  int index = static_cast<int>(index_double);
132
133  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
134  int previous_shown_page =
135      prefs->GetInteger(prefs::kNtpShownPage) >> kPageIdOffset;
136  UMA_HISTOGRAM_ENUMERATION("NewTabPage.PreviousSelectedPageType",
137                            previous_shown_page, kHistogramEnumerationMax);
138
139  prefs->SetInteger(prefs::kNtpShownPage, page_id | index);
140
141  int shown_page_type = page_id >> kPageIdOffset;
142  UMA_HISTOGRAM_ENUMERATION("NewTabPage.SelectedPageType",
143                            shown_page_type, kHistogramEnumerationMax);
144}
145
146void NewTabPageHandler::HandleLogTimeToClick(const ListValue* args) {
147  std::string histogram_name;
148  double duration;
149  if (!args->GetString(0, &histogram_name) || !args->GetDouble(1, &duration)) {
150    NOTREACHED();
151    return;
152  }
153
154  base::TimeDelta delta = base::TimeDelta::FromMilliseconds(duration);
155
156  if (histogram_name == "NewTabPage.TimeToClickMostVisited") {
157    UMA_HISTOGRAM_LONG_TIMES("NewTabPage.TimeToClickMostVisited", delta);
158  } else if (histogram_name == "NewTabPage.TimeToClickRecentlyClosed") {
159    UMA_HISTOGRAM_LONG_TIMES("NewTabPage.TimeToClickRecentlyClosed", delta);
160  } else if (histogram_name == "ExtendedNewTabPage.TimeToClickMostVisited") {
161    UMA_HISTOGRAM_LONG_TIMES(
162        "ExtendedNewTabPage.TimeToClickMostVisited", delta);
163  } else if (histogram_name == "ExtendedNewTabPage.TimeToClickRecentlyClosed") {
164    UMA_HISTOGRAM_LONG_TIMES(
165        "ExtendedNewTabPage.TimeToClickRecentlyClosed", delta);
166  } else {
167    NOTREACHED();
168  }
169}
170
171// static
172void NewTabPageHandler::RegisterProfilePrefs(
173    user_prefs::PrefRegistrySyncable* registry) {
174  // TODO(estade): should be syncable.
175  registry->RegisterIntegerPref(
176      prefs::kNtpShownPage,
177      APPS_PAGE_ID,
178      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
179}
180
181// static
182void NewTabPageHandler::GetLocalizedValues(Profile* profile,
183                                           DictionaryValue* values) {
184  values->SetInteger("most_visited_page_id", MOST_VISITED_PAGE_ID);
185  values->SetInteger("apps_page_id", APPS_PAGE_ID);
186  values->SetInteger("suggestions_page_id", SUGGESTIONS_PAGE_ID);
187
188  PrefService* prefs = profile->GetPrefs();
189  int shown_page = prefs->GetInteger(prefs::kNtpShownPage);
190  values->SetInteger("shown_page_type", shown_page & ~INDEX_MASK);
191  values->SetInteger("shown_page_index", shown_page & INDEX_MASK);
192}
193
194void NewTabPageHandler::Notify(chrome::NotificationType notification_type) {
195  content::NotificationService* service =
196      content::NotificationService::current();
197  service->Notify(notification_type,
198                  content::Source<NewTabPageHandler>(this),
199                  content::NotificationService::NoDetails());
200}
201