Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(874)

Side by Side Diff: chrome/browser/extensions/extension_omnibox_api.cc

Issue 10265022: Moving extensions inside chrome/browser/extensions/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Re-synced with the current trunk Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/extensions/extension_omnibox_api.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/lazy_instance.h"
9 #include "base/metrics/histogram.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/extension_event_router.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search_engines/template_url.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
19 #include "chrome/common/chrome_notification_types.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "content/public/browser/notification_service.h"
22
23 namespace events {
24 const char kOnInputStarted[] = "omnibox.onInputStarted";
25 const char kOnInputChanged[] = "omnibox.onInputChanged";
26 const char kOnInputEntered[] = "omnibox.onInputEntered";
27 const char kOnInputCancelled[] = "omnibox.onInputCancelled";
28 }; // namespace events
29
30 namespace {
31 const char kDescriptionStylesOrderError[] =
32 "Suggestion descriptionStyles must be in increasing non-overlapping order.";
33 const char kDescriptionStylesLengthError[] =
34 "Suggestion descriptionStyles contains an offset longer than the"
35 " description text";
36
37 const char kSuggestionContent[] = "content";
38 const char kSuggestionDescription[] = "description";
39 const char kSuggestionDescriptionStyles[] = "descriptionStyles";
40 const char kDescriptionStylesType[] = "type";
41 const char kDescriptionStylesOffset[] = "offset";
42 const char kDescriptionStylesLength[] = "length";
43
44 static base::LazyInstance<base::PropertyAccessor<ExtensionOmniboxSuggestion> >
45 g_extension_omnibox_suggestion_property_accessor =
46 LAZY_INSTANCE_INITIALIZER;
47
48 base::PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() {
49 return g_extension_omnibox_suggestion_property_accessor.Get();
50 }
51
52 // Returns the suggestion object set by the extension via the
53 // omnibox.setDefaultSuggestion call, or NULL if it was never set.
54 const ExtensionOmniboxSuggestion* GetDefaultSuggestionForExtension(
55 Profile* profile, const std::string& extension_id) {
56 const Extension* extension =
57 profile->GetExtensionService()->GetExtensionById(extension_id, false);
58 if (!extension)
59 return NULL;
60 return GetPropertyAccessor().GetProperty(
61 profile->GetExtensionService()->GetPropertyBag(extension));
62 }
63
64 }; // namespace
65
66 // static
67 void ExtensionOmniboxEventRouter::OnInputStarted(
68 Profile* profile, const std::string& extension_id) {
69 profile->GetExtensionEventRouter()->DispatchEventToExtension(
70 extension_id, events::kOnInputStarted, "[]", profile, GURL());
71 }
72
73 // static
74 bool ExtensionOmniboxEventRouter::OnInputChanged(
75 Profile* profile, const std::string& extension_id,
76 const std::string& input, int suggest_id) {
77 if (!profile->GetExtensionEventRouter()->ExtensionHasEventListener(
78 extension_id, events::kOnInputChanged))
79 return false;
80
81 ListValue args;
82 args.Set(0, Value::CreateStringValue(input));
83 args.Set(1, Value::CreateIntegerValue(suggest_id));
84 std::string json_args;
85 base::JSONWriter::Write(&args, &json_args);
86
87 profile->GetExtensionEventRouter()->DispatchEventToExtension(
88 extension_id, events::kOnInputChanged, json_args, profile, GURL());
89 return true;
90 }
91
92 // static
93 void ExtensionOmniboxEventRouter::OnInputEntered(
94 Profile* profile, const std::string& extension_id,
95 const std::string& input) {
96 ListValue args;
97 args.Set(0, Value::CreateStringValue(input));
98 std::string json_args;
99 base::JSONWriter::Write(&args, &json_args);
100
101 profile->GetExtensionEventRouter()->DispatchEventToExtension(
102 extension_id, events::kOnInputEntered, json_args, profile, GURL());
103
104 content::NotificationService::current()->Notify(
105 chrome::NOTIFICATION_EXTENSION_OMNIBOX_INPUT_ENTERED,
106 content::Source<Profile>(profile),
107 content::NotificationService::NoDetails());
108 }
109
110 // static
111 void ExtensionOmniboxEventRouter::OnInputCancelled(
112 Profile* profile, const std::string& extension_id) {
113 profile->GetExtensionEventRouter()->DispatchEventToExtension(
114 extension_id, events::kOnInputCancelled, "[]", profile, GURL());
115 }
116
117 bool OmniboxSendSuggestionsFunction::RunImpl() {
118 ExtensionOmniboxSuggestions suggestions;
119 ListValue* suggestions_value;
120 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &suggestions.request_id));
121 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &suggestions_value));
122
123 suggestions.suggestions.resize(suggestions_value->GetSize());
124 for (size_t i = 0; i < suggestions_value->GetSize(); ++i) {
125 ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i];
126 DictionaryValue* suggestion_value;
127 EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary(
128 i, &suggestion_value));
129 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
130 kSuggestionContent, &suggestion.content));
131 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
132 kSuggestionDescription, &suggestion.description));
133
134 if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) {
135 ListValue* styles;
136 EXTENSION_FUNCTION_VALIDATE(
137 suggestion_value->GetList(kSuggestionDescriptionStyles, &styles));
138 EXTENSION_FUNCTION_VALIDATE(suggestion.ReadStylesFromValue(*styles));
139 } else {
140 suggestion.description_styles.clear();
141 suggestion.description_styles.push_back(
142 ACMatchClassification(0, ACMatchClassification::NONE));
143 }
144 }
145
146 content::NotificationService::current()->Notify(
147 chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
148 content::Source<Profile>(profile_->GetOriginalProfile()),
149 content::Details<ExtensionOmniboxSuggestions>(&suggestions));
150
151 return true;
152 }
153
154 bool OmniboxSetDefaultSuggestionFunction::RunImpl() {
155 ExtensionOmniboxSuggestion suggestion;
156 DictionaryValue* suggestion_value;
157 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &suggestion_value));
158 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
159 kSuggestionDescription, &suggestion.description));
160
161 if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) {
162 ListValue* styles;
163 EXTENSION_FUNCTION_VALIDATE(
164 suggestion_value->GetList(kSuggestionDescriptionStyles, &styles));
165 EXTENSION_FUNCTION_VALIDATE(suggestion.ReadStylesFromValue(*styles));
166 } else {
167 suggestion.description_styles.clear();
168 suggestion.description_styles.push_back(
169 ACMatchClassification(0, ACMatchClassification::NONE));
170 }
171
172 // Store the suggestion in the extension's runtime data.
173 GetPropertyAccessor().SetProperty(
174 profile_->GetExtensionService()->GetPropertyBag(GetExtension()),
175 suggestion);
176
177 content::NotificationService::current()->Notify(
178 chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
179 content::Source<Profile>(profile_->GetOriginalProfile()),
180 content::NotificationService::NoDetails());
181
182 return true;
183 }
184
185 ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {}
186
187 ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {}
188
189 bool ExtensionOmniboxSuggestion::ReadStylesFromValue(
190 const ListValue& styles_value) {
191 description_styles.clear();
192
193 // Step 1: Build a vector of styles, 1 per character of description text.
194 std::vector<int> styles;
195 styles.resize(description.length()); // sets all styles to 0
196
197 for (size_t i = 0; i < styles_value.GetSize(); ++i) {
198 DictionaryValue* style;
199 std::string type;
200 int offset;
201 int length;
202 if (!styles_value.GetDictionary(i, &style))
203 return false;
204 if (!style->GetString(kDescriptionStylesType, &type))
205 return false;
206 if (!style->GetInteger(kDescriptionStylesOffset, &offset))
207 return false;
208 if (!style->GetInteger(kDescriptionStylesLength, &length) || length < 0)
209 length = description.length();
210
211 if (offset < 0)
212 offset = std::max(0, static_cast<int>(description.length()) + offset);
213
214 int type_class =
215 (type == "url") ? ACMatchClassification::URL :
216 (type == "match") ? ACMatchClassification::MATCH :
217 (type == "dim") ? ACMatchClassification::DIM : -1;
218 if (type_class == -1)
219 return false;
220
221 for (int j = offset;
222 j < offset + length && j < static_cast<int>(styles.size()); ++j)
223 styles[j] |= type_class;
224 }
225
226 // Step 2: Convert the vector into continuous runs of common styles.
227 for (size_t i = 0; i < styles.size(); ++i) {
228 if (i == 0 || styles[i] != styles[i-1])
229 description_styles.push_back(ACMatchClassification(i, styles[i]));
230 }
231
232 return true;
233 }
234
235 ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {}
236
237 ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {}
238
239 void ApplyDefaultSuggestionForExtensionKeyword(
240 Profile* profile,
241 const TemplateURL* keyword,
242 const string16& remaining_input,
243 AutocompleteMatch* match) {
244 DCHECK(keyword->IsExtensionKeyword());
245 const ExtensionOmniboxSuggestion* suggestion =
246 GetDefaultSuggestionForExtension(profile, keyword->GetExtensionId());
247 if (!suggestion)
248 return; // fall back to the universal default
249
250 const string16 kPlaceholderText(ASCIIToUTF16("%s"));
251 const string16 kReplacementText(ASCIIToUTF16("<input>"));
252
253 string16 description = suggestion->description;
254 ACMatchClassifications& description_styles = match->contents_class;
255 description_styles = suggestion->description_styles;
256
257 // Replace "%s" with the user's input and adjust the style offsets to the
258 // new length of the description.
259 size_t placeholder(suggestion->description.find(kPlaceholderText, 0));
260 if (placeholder != string16::npos) {
261 string16 replacement =
262 remaining_input.empty() ? kReplacementText : remaining_input;
263 description.replace(placeholder, kPlaceholderText.length(), replacement);
264
265 for (size_t i = 0; i < description_styles.size(); ++i) {
266 if (description_styles[i].offset > placeholder)
267 description_styles[i].offset += replacement.length() - 2;
268 }
269 }
270
271 match->contents.assign(description);
272 }
273
274 void LaunchAppFromOmnibox(const AutocompleteMatch& match,
275 Profile* profile,
276 WindowOpenDisposition disposition) {
277 ExtensionService* service = profile->GetExtensionService();
278 const Extension* extension =
279 service->GetInstalledApp(match.destination_url);
280 // While the Omnibox popup is open, the extension can be updated, changing
281 // its URL and leaving us with no extension being found. In this case, we
282 // ignore the request.
283 if (!extension)
284 return;
285
286 AppLauncherHandler::RecordAppLaunchType(
287 extension_misc::APP_LAUNCH_OMNIBOX_APP);
288
289 // Look at the preferences to find the right launch container. If no
290 // preference is set, launch as a regular tab.
291 extension_misc::LaunchContainer launch_container =
292 service->extension_prefs()->GetLaunchContainer(
293 extension, ExtensionPrefs::LAUNCH_REGULAR);
294
295 Browser::OpenApplication(profile, extension, launch_container, GURL(),
296 disposition);
297 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_omnibox_api.h ('k') | chrome/browser/extensions/extension_omnibox_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698