hotword_service.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2013 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/search/hotword_service.h"
6
7#include "base/i18n/case_conversion.h"
8#include "base/metrics/field_trial.h"
9#include "base/metrics/histogram.h"
10#include "base/prefs/pref_service.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/extensions/extension_service.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/common/extensions/extension_constants.h"
15#include "chrome/common/pref_names.h"
16#include "extensions/browser/extension_system.h"
17#include "extensions/common/extension.h"
18#include "ui/base/l10n/l10n_util.h"
19
20namespace {
21const int kMaxTimesToShowOptInPopup = 10;
22
23// Enum describing the state of the hotword preference.
24// This is used for UMA stats -- do not reorder or delete items; only add to
25// the end.
26enum HotwordEnabled {
27  UNSET = 0,  // The hotword preference has not been set.
28  ENABLED,    // The hotword preference is enabled.
29  DISABLED,   // The hotword preference is disabled.
30  NUM_HOTWORD_ENABLED_METRICS
31};
32
33// Enum describing the availability state of the hotword extension.
34// This is used for UMA stats -- do not reorder or delete items; only add to
35// the end.
36enum HotwordExtensionAvailability {
37  UNAVAILABLE = 0,
38  AVAILABLE,
39  PENDING_DOWNLOAD,
40  DISABLED_EXTENSION,
41  NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS
42};
43
44void RecordAvailabilityMetrics(
45    ExtensionService* service,
46    const extensions::Extension* extension) {
47  HotwordExtensionAvailability availability_state = UNAVAILABLE;
48  if (extension) {
49    availability_state = AVAILABLE;
50  } else if (service->pending_extension_manager() &&
51             service->pending_extension_manager()->IsIdPending(
52                 extension_misc::kHotwordExtensionId)) {
53    availability_state = PENDING_DOWNLOAD;
54  } else if (!service->IsExtensionEnabled(
55      extension_misc::kHotwordExtensionId)) {
56    availability_state = DISABLED_EXTENSION;
57  }
58  UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability",
59                            availability_state,
60                            NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS);
61}
62
63}  // namespace
64
65namespace hotword_internal {
66// Constants for the hotword field trial.
67const char kHotwordFieldTrialName[] = "VoiceTrigger";
68const char kHotwordFieldTrialDisabledGroupName[] = "Disabled";
69}  // namespace hotword_internal
70
71// static
72bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) {
73  std::string locale =
74#if defined(OS_CHROMEOS)
75      // On ChromeOS locale is per-profile.
76      profile->GetPrefs()->GetString(prefs::kApplicationLocale);
77#else
78      g_browser_process->GetApplicationLocale();
79#endif
80  // Only available for English now.
81  std::string normalized_locale = l10n_util::NormalizeLocale(locale);
82  return normalized_locale == "en" || normalized_locale == "en_us" ||
83      normalized_locale =="en_US";
84}
85
86HotwordService::HotwordService(Profile* profile)
87    : profile_(profile) {
88  // This will be called during profile initialization which is a good time
89  // to check the user's hotword state.
90  HotwordEnabled enabled_state = UNSET;
91  if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) {
92    if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
93      enabled_state = ENABLED;
94    else
95      enabled_state = DISABLED;
96  }
97  UMA_HISTOGRAM_ENUMERATION("Hotword.Enabled", enabled_state,
98                            NUM_HOTWORD_ENABLED_METRICS);
99}
100
101HotwordService::~HotwordService() {
102}
103
104bool HotwordService::ShouldShowOptInPopup() {
105  if (profile_->IsOffTheRecord())
106    return false;
107
108  // Profile is not off the record.
109  if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled))
110    return false;  // Already opted in or opted out;
111
112  int number_shown = profile_->GetPrefs()->GetInteger(
113      prefs::kHotwordOptInPopupTimesShown);
114  return number_shown < MaxNumberTimesToShowOptInPopup();
115}
116
117int HotwordService::MaxNumberTimesToShowOptInPopup() {
118  return kMaxTimesToShowOptInPopup;
119}
120
121void HotwordService::ShowOptInPopup() {
122  int number_shown = profile_->GetPrefs()->GetInteger(
123      prefs::kHotwordOptInPopupTimesShown);
124  profile_->GetPrefs()->SetInteger(prefs::kHotwordOptInPopupTimesShown,
125                                   ++number_shown);
126  // TODO(rlp): actually show opt in popup when linked up to extension.
127}
128
129bool HotwordService::IsServiceAvailable() {
130  extensions::ExtensionSystem* system =
131      extensions::ExtensionSystem::Get(profile_);
132  ExtensionService* service = system->extension_service();
133  // Do not include disabled extension (false parameter) because if the
134  // extension is disabled, it's not available.
135  const extensions::Extension* extension =
136      service->GetExtensionById(extension_misc::kHotwordExtensionId, false);
137
138  RecordAvailabilityMetrics(service, extension);
139
140  return extension && IsHotwordAllowed();
141}
142
143bool HotwordService::IsHotwordAllowed() {
144  std::string group = base::FieldTrialList::FindFullName(
145      hotword_internal::kHotwordFieldTrialName);
146  return !group.empty() &&
147      group != hotword_internal::kHotwordFieldTrialDisabledGroupName &&
148      DoesHotwordSupportLanguage(profile_);
149}
150