OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/speech/speech_input_extension_api.h" | |
6 | |
7 #include "base/values.h" | |
8 #include "chrome/browser/browser_process.h" | |
9 #include "chrome/browser/profiles/profile.h" | |
10 #include "chrome/browser/speech/speech_input_extension_manager.h" | |
11 #include "chrome/common/chrome_notification_types.h" | |
12 #include "content/public/browser/notification_details.h" | |
13 #include "content/public/browser/notification_source.h" | |
14 | |
15 namespace { | |
16 | |
17 const char kLanguageKey[] = "language"; | |
18 const char kGrammarKey[] = "grammar"; | |
19 const char kFilterProfanitiesKey[] = "filterProfanities"; | |
20 | |
21 const char kDefaultGrammar[] = "builtin:dictation"; | |
22 const bool kDefaultFilterProfanities = true; | |
23 | |
24 } // anonymous namespace | |
25 | |
26 SpeechInputAsyncFunction::SpeechInputAsyncFunction( | |
27 int start_state, | |
28 int transition_state, | |
29 int end_state, | |
30 int transition_notification) | |
31 : start_state_(start_state), | |
32 transition_state_(transition_state), | |
33 end_state_(end_state), | |
34 transition_notification_(transition_notification), | |
35 expecting_transition_(false), | |
36 failed_(false) { | |
37 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, | |
38 content::Source<Profile>(profile())); | |
39 } | |
40 | |
41 SpeechInputAsyncFunction::~SpeechInputAsyncFunction() { | |
42 } | |
43 | |
44 void SpeechInputAsyncFunction::Run() { | |
45 if (failed_) { | |
46 registrar_.RemoveAll(); | |
47 SendResponse(false); | |
48 return; | |
49 } | |
50 | |
51 SpeechInputExtensionManager::State state = | |
52 SpeechInputExtensionManager::GetForProfile(profile())->state(); | |
53 | |
54 // RunImpl should be always called once independently of the state we're in, | |
55 // otherwise we might miss requestDenied error situations. | |
56 if (!expecting_transition_) { | |
57 SpeechInputExtensionManager::State state_before_call = state; | |
58 | |
59 // Register before RunImpl to ensure it's received if generated. | |
60 if (state_before_call == start_state_) { | |
61 registrar_.Add(this, transition_notification_, | |
62 content::Source<Profile>(profile())); | |
63 AddRef(); // Balanced in Observe(). | |
64 } | |
65 | |
66 if (!RunImpl()) { | |
67 registrar_.RemoveAll(); | |
68 SendResponse(false); | |
69 return; | |
70 } | |
71 | |
72 // RunImpl should always return false and set the appropriate error code | |
73 // when called in a state different to the start one. | |
74 DCHECK_EQ(state_before_call, start_state_); | |
75 | |
76 state = SpeechInputExtensionManager::GetForProfile(profile())->state(); | |
77 DCHECK_EQ(state, transition_state_); | |
78 expecting_transition_ = true; | |
79 } | |
80 | |
81 if (state == transition_state_) | |
82 return; | |
83 | |
84 DCHECK_EQ(state, end_state_); | |
85 registrar_.RemoveAll(); | |
86 SendResponse(true); | |
87 } | |
88 | |
89 void SpeechInputAsyncFunction::Observe( | |
90 int type, | |
91 const content::NotificationSource& source, | |
92 const content::NotificationDetails& details) { | |
93 DCHECK_EQ(profile(), content::Source<Profile>(source).ptr()); | |
94 | |
95 if (type == chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED) { | |
96 SpeechInputExtensionManager::ExtensionError* error_details = | |
97 content::Details<SpeechInputExtensionManager::ExtensionError>( | |
98 details).ptr(); | |
99 if (error_details->extension_id_ != extension_id()) | |
100 return; | |
101 | |
102 error_ = error_details->error_; | |
103 failed_ = true; | |
104 } else { | |
105 DCHECK_EQ(type, transition_notification_); | |
106 if (*content::Details<std::string>(details).ptr() != extension_id()) | |
107 return; | |
108 DCHECK(expecting_transition_); | |
109 } | |
110 | |
111 Run(); | |
112 Release(); // Balanced in Run(). | |
113 } | |
114 | |
115 StartSpeechInputFunction::StartSpeechInputFunction() | |
116 : SpeechInputAsyncFunction(SpeechInputExtensionManager::kIdle, | |
117 SpeechInputExtensionManager::kStarting, | |
118 SpeechInputExtensionManager::kRecording, | |
119 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED) { | |
120 } | |
121 | |
122 bool StartSpeechInputFunction::RunImpl() { | |
123 std::string language; | |
124 std::string grammar = kDefaultGrammar; | |
125 bool filter_profanities = kDefaultFilterProfanities; | |
126 | |
127 if (!args_->empty()) { | |
128 DictionaryValue *options; | |
129 if (!args_->GetDictionary(0, &options)) | |
130 return false; | |
131 DCHECK(options); | |
132 | |
133 if (options->HasKey(kLanguageKey)) | |
134 options->GetString(kLanguageKey, &language); | |
135 if (options->HasKey(kGrammarKey)) | |
136 options->GetString(kGrammarKey, &grammar); | |
137 | |
138 if (options->HasKey(kFilterProfanitiesKey)) { | |
139 options->GetBoolean(kFilterProfanitiesKey, | |
140 &filter_profanities); | |
141 } | |
142 } | |
143 | |
144 // Use the application locale if the language is empty or not provided. | |
145 if (language.empty()) { | |
146 language = g_browser_process->GetApplicationLocale(); | |
147 VLOG(1) << "Language not specified. Using application locale " << language; | |
148 } | |
149 | |
150 return SpeechInputExtensionManager::GetForProfile(profile())->Start( | |
151 extension_id(), language, grammar, filter_profanities, &error_); | |
152 } | |
153 | |
154 StopSpeechInputFunction::StopSpeechInputFunction() | |
155 : SpeechInputAsyncFunction(SpeechInputExtensionManager::kRecording, | |
156 SpeechInputExtensionManager::kStopping, | |
157 SpeechInputExtensionManager::kIdle, | |
158 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED) { | |
159 } | |
160 | |
161 bool StopSpeechInputFunction::RunImpl() { | |
162 return SpeechInputExtensionManager::GetForProfile( | |
163 profile())->Stop(extension_id(), &error_); | |
164 } | |
165 | |
166 bool IsRecordingSpeechInputFunction::RunImpl() { | |
167 // Do not access the AudioManager directly here to ensure the proper | |
168 // IsRecording behaviour in the API tests. | |
169 result_.reset(Value::CreateBooleanValue( | |
170 SpeechInputExtensionManager::GetForProfile(profile())->IsRecording())); | |
171 return true; | |
172 } | |
OLD | NEW |