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