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/pref_registry/pref_registry_syncable.h"
18#include "content/public/browser/notification_service.h"
19#include "content/public/browser/web_ui.h"
20
21namespace {
22
23const char kDefaultPageTypeHistogram[] = "NewTabPage.DefaultPageType";
24
25enum PromoAction {
26  PROMO_VIEWED = 0,
27  PROMO_CLOSED,
28  PROMO_LINK_CLICKED,
29  PROMO_ACTION_MAX,
30};
31
32}  // namespace
33
34NewTabPageHandler::NewTabPageHandler() : page_switch_count_(0) {
35}
36
37NewTabPageHandler::~NewTabPageHandler() {
38  LOCAL_HISTOGRAM_COUNTS_100("NewTabPage.SingleSessionPageSwitches",
39                             page_switch_count_);
40}
41
42void NewTabPageHandler::RegisterMessages() {
43  // Record an open of the NTP with its default page type.
44  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
45  int shown_page_type = prefs->GetInteger(prefs::kNtpShownPage) >>
46      kPageIdOffset;
47  UMA_HISTOGRAM_ENUMERATION(kDefaultPageTypeHistogram,
48                            shown_page_type, kHistogramEnumerationMax);
49
50  web_ui()->RegisterMessageCallback("notificationPromoClosed",
51      base::Bind(&NewTabPageHandler::HandleNotificationPromoClosed,
52                 base::Unretained(this)));
53  web_ui()->RegisterMessageCallback("notificationPromoViewed",
54      base::Bind(&NewTabPageHandler::HandleNotificationPromoViewed,
55                 base::Unretained(this)));
56  web_ui()->RegisterMessageCallback("notificationPromoLinkClicked",
57      base::Bind(&NewTabPageHandler::HandleNotificationPromoLinkClicked,
58                 base::Unretained(this)));
59  web_ui()->RegisterMessageCallback("bubblePromoClosed",
60      base::Bind(&NewTabPageHandler::HandleBubblePromoClosed,
61                 base::Unretained(this)));
62  web_ui()->RegisterMessageCallback("bubblePromoViewed",
63      base::Bind(&NewTabPageHandler::HandleBubblePromoViewed,
64                 base::Unretained(this)));
65  web_ui()->RegisterMessageCallback("bubblePromoLinkClicked",
66      base::Bind(&NewTabPageHandler::HandleBubblePromoLinkClicked,
67                 base::Unretained(this)));
68  web_ui()->RegisterMessageCallback("pageSelected",
69      base::Bind(&NewTabPageHandler::HandlePageSelected,
70                 base::Unretained(this)));
71  web_ui()->RegisterMessageCallback("logTimeToClick",
72      base::Bind(&NewTabPageHandler::HandleLogTimeToClick,
73                 base::Unretained(this)));
74}
75
76void NewTabPageHandler::HandleNotificationPromoClosed(
77    const base::ListValue* args) {
78  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
79                            PROMO_CLOSED, PROMO_ACTION_MAX);
80  NotificationPromo::HandleClosed(NotificationPromo::NTP_NOTIFICATION_PROMO);
81  Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
82}
83
84void NewTabPageHandler::HandleNotificationPromoViewed(
85    const base::ListValue* args) {
86  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
87                            PROMO_VIEWED, PROMO_ACTION_MAX);
88  if (NotificationPromo::HandleViewed(
89          NotificationPromo::NTP_NOTIFICATION_PROMO)) {
90    Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
91  }
92}
93
94void NewTabPageHandler::HandleNotificationPromoLinkClicked(
95    const base::ListValue* args) {
96  DVLOG(1) << "HandleNotificationPromoLinkClicked";
97  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Notification",
98                            PROMO_LINK_CLICKED, PROMO_ACTION_MAX);
99}
100
101void NewTabPageHandler::HandleBubblePromoClosed(const base::ListValue* args) {
102  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Bubble",
103                            PROMO_CLOSED, PROMO_ACTION_MAX);
104  NotificationPromo::HandleClosed(NotificationPromo::NTP_BUBBLE_PROMO);
105  Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
106}
107
108void NewTabPageHandler::HandleBubblePromoViewed(const base::ListValue* args) {
109  UMA_HISTOGRAM_ENUMERATION("NewTabPage.Promo.Bubble",
110                            PROMO_VIEWED, PROMO_ACTION_MAX);
111  if (NotificationPromo::HandleViewed(NotificationPromo::NTP_BUBBLE_PROMO))
112    Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
113}
114
115void NewTabPageHandler::HandleBubblePromoLinkClicked(
116    const base::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 base::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 base::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                                           base::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