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

Side by Side Diff: chrome/browser/extensions/api/omnibox/omnibox_api.cc

Issue 10306015: Persist the extension omnibox default suggestion to Prefs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: empty.list 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" 5 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
6 6
7 #include "base/json/json_writer.h" 7 #include "base/json/json_writer.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "base/values.h" 12 #include "base/values.h"
13 #include "chrome/browser/extensions/extension_event_router.h" 13 #include "chrome/browser/extensions/extension_event_router.h"
14 #include "chrome/browser/extensions/extension_prefs.h"
14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h"
15 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search_engines/template_url.h" 18 #include "chrome/browser/search_engines/template_url.h"
17 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" 20 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
19 #include "chrome/common/chrome_notification_types.h" 21 #include "chrome/common/chrome_notification_types.h"
20 #include "chrome/common/extensions/extension_constants.h" 22 #include "chrome/common/extensions/extension_constants.h"
21 #include "content/public/browser/notification_service.h" 23 #include "content/public/browser/notification_service.h"
22 24
23 namespace events { 25 namespace events {
24 const char kOnInputStarted[] = "omnibox.onInputStarted"; 26 const char kOnInputStarted[] = "omnibox.onInputStarted";
25 const char kOnInputChanged[] = "omnibox.onInputChanged"; 27 const char kOnInputChanged[] = "omnibox.onInputChanged";
26 const char kOnInputEntered[] = "omnibox.onInputEntered"; 28 const char kOnInputEntered[] = "omnibox.onInputEntered";
27 const char kOnInputCancelled[] = "omnibox.onInputCancelled"; 29 const char kOnInputCancelled[] = "omnibox.onInputCancelled";
28 } // namespace events 30 } // namespace events
29 31
30 namespace extensions { 32 namespace extensions {
31 33
32 namespace { 34 namespace {
33 const char kDescriptionStylesOrderError[] = 35 const char kDescriptionStylesOrderError[] =
34 "Suggestion descriptionStyles must be in increasing non-overlapping order."; 36 "Suggestion descriptionStyles must be in increasing non-overlapping order.";
35 const char kDescriptionStylesLengthError[] = 37 const char kDescriptionStylesLengthError[] =
36 "Suggestion descriptionStyles contains an offset longer than the" 38 "Suggestion descriptionStyles contains an offset longer than the"
37 " description text"; 39 " description text";
38 40
39 const char kSuggestionContent[] = "content"; 41 const char kSuggestionContent[] = "content";
40 const char kSuggestionDescription[] = "description"; 42 const char kSuggestionDescription[] = "description";
41 const char kSuggestionDescriptionStyles[] = "descriptionStyles"; 43 const char kSuggestionDescriptionStyles[] = "descriptionStyles";
44 const char kSuggestionDescriptionStylesRaw[] = "descriptionStylesRaw";
42 const char kDescriptionStylesType[] = "type"; 45 const char kDescriptionStylesType[] = "type";
43 const char kDescriptionStylesOffset[] = "offset"; 46 const char kDescriptionStylesOffset[] = "offset";
44 const char kDescriptionStylesLength[] = "length"; 47 const char kDescriptionStylesLength[] = "length";
45 48
46 static base::LazyInstance<base::PropertyAccessor<ExtensionOmniboxSuggestion> >
47 g_extension_omnibox_suggestion_property_accessor =
48 LAZY_INSTANCE_INITIALIZER;
49
50 base::PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() {
51 return g_extension_omnibox_suggestion_property_accessor.Get();
52 }
53
54 // Returns the suggestion object set by the extension via the
55 // omnibox.setDefaultSuggestion call, or NULL if it was never set.
56 const ExtensionOmniboxSuggestion* GetDefaultSuggestionForExtension(
57 Profile* profile, const std::string& extension_id) {
58 const Extension* extension =
59 profile->GetExtensionService()->GetExtensionById(extension_id, false);
60 if (!extension)
61 return NULL;
62 return GetPropertyAccessor().GetProperty(
63 profile->GetExtensionService()->GetPropertyBag(extension));
64 }
65
66 } // namespace 49 } // namespace
67 50
68 // static 51 // static
69 void ExtensionOmniboxEventRouter::OnInputStarted( 52 void ExtensionOmniboxEventRouter::OnInputStarted(
70 Profile* profile, const std::string& extension_id) { 53 Profile* profile, const std::string& extension_id) {
71 profile->GetExtensionEventRouter()->DispatchEventToExtension( 54 profile->GetExtensionEventRouter()->DispatchEventToExtension(
72 extension_id, events::kOnInputStarted, "[]", profile, GURL()); 55 extension_id, events::kOnInputStarted, "[]", profile, GURL());
73 } 56 }
74 57
75 // static 58 // static
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 ListValue* suggestions_value; 104 ListValue* suggestions_value;
122 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &suggestions.request_id)); 105 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &suggestions.request_id));
123 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &suggestions_value)); 106 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &suggestions_value));
124 107
125 suggestions.suggestions.resize(suggestions_value->GetSize()); 108 suggestions.suggestions.resize(suggestions_value->GetSize());
126 for (size_t i = 0; i < suggestions_value->GetSize(); ++i) { 109 for (size_t i = 0; i < suggestions_value->GetSize(); ++i) {
127 ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i]; 110 ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i];
128 DictionaryValue* suggestion_value; 111 DictionaryValue* suggestion_value;
129 EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary( 112 EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary(
130 i, &suggestion_value)); 113 i, &suggestion_value));
131 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString( 114 EXTENSION_FUNCTION_VALIDATE(suggestion.Populate(*suggestion_value, true));
132 kSuggestionContent, &suggestion.content));
133 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
134 kSuggestionDescription, &suggestion.description));
135
136 if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) {
137 ListValue* styles;
138 EXTENSION_FUNCTION_VALIDATE(
139 suggestion_value->GetList(kSuggestionDescriptionStyles, &styles));
140 EXTENSION_FUNCTION_VALIDATE(suggestion.ReadStylesFromValue(*styles));
141 } else {
142 suggestion.description_styles.clear();
143 suggestion.description_styles.push_back(
144 ACMatchClassification(0, ACMatchClassification::NONE));
145 }
146 } 115 }
147 116
148 content::NotificationService::current()->Notify( 117 content::NotificationService::current()->Notify(
149 chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY, 118 chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
150 content::Source<Profile>(profile_->GetOriginalProfile()), 119 content::Source<Profile>(profile_->GetOriginalProfile()),
151 content::Details<ExtensionOmniboxSuggestions>(&suggestions)); 120 content::Details<ExtensionOmniboxSuggestions>(&suggestions));
152 121
153 return true; 122 return true;
154 } 123 }
155 124
156 bool OmniboxSetDefaultSuggestionFunction::RunImpl() { 125 bool OmniboxSetDefaultSuggestionFunction::RunImpl() {
157 ExtensionOmniboxSuggestion suggestion; 126 ExtensionOmniboxSuggestion suggestion;
158 DictionaryValue* suggestion_value; 127 DictionaryValue* suggestion_value;
159 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &suggestion_value)); 128 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &suggestion_value));
160 EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString( 129 EXTENSION_FUNCTION_VALIDATE(suggestion.Populate(*suggestion_value, false));
161 kSuggestionDescription, &suggestion.description));
162 130
163 if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) { 131 ExtensionPrefs* prefs =
164 ListValue* styles; 132 ExtensionSystem::Get(profile())->extension_service()->extension_prefs();
165 EXTENSION_FUNCTION_VALIDATE( 133 if (prefs)
166 suggestion_value->GetList(kSuggestionDescriptionStyles, &styles)); 134 prefs->SetOmniboxDefaultSuggestion(extension_id(), suggestion);
167 EXTENSION_FUNCTION_VALIDATE(suggestion.ReadStylesFromValue(*styles));
168 } else {
169 suggestion.description_styles.clear();
170 suggestion.description_styles.push_back(
171 ACMatchClassification(0, ACMatchClassification::NONE));
172 }
173
174 // Store the suggestion in the extension's runtime data.
175 GetPropertyAccessor().SetProperty(
176 profile_->GetExtensionService()->GetPropertyBag(GetExtension()),
177 suggestion);
178 135
179 content::NotificationService::current()->Notify( 136 content::NotificationService::current()->Notify(
180 chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED, 137 chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
181 content::Source<Profile>(profile_->GetOriginalProfile()), 138 content::Source<Profile>(profile_->GetOriginalProfile()),
182 content::NotificationService::NoDetails()); 139 content::NotificationService::NoDetails());
183 140
184 return true; 141 return true;
185 } 142 }
186 143
187 ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {} 144 ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {}
188 145
189 ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {} 146 ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {}
190 147
148 bool ExtensionOmniboxSuggestion::Populate(const base::DictionaryValue& value,
149 bool require_content) {
150 if (!value.GetString(kSuggestionContent, &content) && require_content)
151 return false;
152
153 if (!value.GetString(kSuggestionDescription, &description))
154 return false;
155
156 description_styles.clear();
157 if (value.HasKey(kSuggestionDescriptionStyles)) {
158 // This version comes from the extension.
159 ListValue* styles = NULL;
160 if (!value.GetList(kSuggestionDescriptionStyles, &styles) ||
161 !ReadStylesFromValue(*styles)) {
162 return false;
163 }
164 } else if (value.HasKey(kSuggestionDescriptionStylesRaw)) {
165 // This version comes from ToValue(), which we use to persist to disk.
166 ListValue* styles = NULL;
167 if (!value.GetList(kSuggestionDescriptionStylesRaw, &styles) ||
168 styles->empty()) {
169 return false;
170 }
171 for (size_t i = 0; i < styles->GetSize(); ++i) {
172 base::DictionaryValue* style = NULL;
173 int offset, type;
174 if (!styles->GetDictionary(i, &style))
175 return false;
176 if (!style->GetInteger(kDescriptionStylesType, &type))
177 return false;
178 if (!style->GetInteger(kDescriptionStylesOffset, &offset))
179 return false;
180 description_styles.push_back(ACMatchClassification(offset, type));
181 }
182 } else {
183 description_styles.push_back(
184 ACMatchClassification(0, ACMatchClassification::NONE));
185 }
186
187 return true;
188 }
189
191 bool ExtensionOmniboxSuggestion::ReadStylesFromValue( 190 bool ExtensionOmniboxSuggestion::ReadStylesFromValue(
192 const ListValue& styles_value) { 191 const ListValue& styles_value) {
193 description_styles.clear(); 192 description_styles.clear();
194 193
195 // Step 1: Build a vector of styles, 1 per character of description text. 194 // Step 1: Build a vector of styles, 1 per character of description text.
196 std::vector<int> styles; 195 std::vector<int> styles;
197 styles.resize(description.length()); // sets all styles to 0 196 styles.resize(description.length()); // sets all styles to 0
198 197
199 for (size_t i = 0; i < styles_value.GetSize(); ++i) { 198 for (size_t i = 0; i < styles_value.GetSize(); ++i) {
200 DictionaryValue* style; 199 DictionaryValue* style;
(...skipping 26 matching lines...) Expand all
227 226
228 // Step 2: Convert the vector into continuous runs of common styles. 227 // Step 2: Convert the vector into continuous runs of common styles.
229 for (size_t i = 0; i < styles.size(); ++i) { 228 for (size_t i = 0; i < styles.size(); ++i) {
230 if (i == 0 || styles[i] != styles[i-1]) 229 if (i == 0 || styles[i] != styles[i-1])
231 description_styles.push_back(ACMatchClassification(i, styles[i])); 230 description_styles.push_back(ACMatchClassification(i, styles[i]));
232 } 231 }
233 232
234 return true; 233 return true;
235 } 234 }
236 235
236 scoped_ptr<base::DictionaryValue> ExtensionOmniboxSuggestion::ToValue() const {
237 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
238
239 value->SetString(kSuggestionContent, content);
240 value->SetString(kSuggestionDescription, description);
241
242 if (description_styles.size() > 0) {
243 base::ListValue* styles_value = new base::ListValue();
244 for (size_t i = 0; i < description_styles.size(); ++i) {
245 base::DictionaryValue* style = new base::DictionaryValue();
246 style->SetInteger(kDescriptionStylesOffset, description_styles[i].offset);
247 style->SetInteger(kDescriptionStylesType, description_styles[i].style);
248 styles_value->Append(style);
249 }
250
251 value->Set(kSuggestionDescriptionStylesRaw, styles_value);
252 }
253
254 return value.Pass();
255 }
256
237 ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {} 257 ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {}
238 258
239 ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {} 259 ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {}
240 260
241 void ApplyDefaultSuggestionForExtensionKeyword( 261 void ApplyDefaultSuggestionForExtensionKeyword(
242 Profile* profile, 262 Profile* profile,
243 const TemplateURL* keyword, 263 const TemplateURL* keyword,
244 const string16& remaining_input, 264 const string16& remaining_input,
245 AutocompleteMatch* match) { 265 AutocompleteMatch* match) {
246 DCHECK(keyword->IsExtensionKeyword()); 266 DCHECK(keyword->IsExtensionKeyword());
247 const ExtensionOmniboxSuggestion* suggestion = 267
248 GetDefaultSuggestionForExtension(profile, keyword->GetExtensionId()); 268 ExtensionPrefs* prefs =
249 if (!suggestion) 269 ExtensionSystem::Get(profile)->extension_service()->extension_prefs();
270 if (!prefs)
271 return;
272
273 ExtensionOmniboxSuggestion suggestion =
274 prefs->GetOmniboxDefaultSuggestion(keyword->GetExtensionId());
275 if (suggestion.description.empty())
250 return; // fall back to the universal default 276 return; // fall back to the universal default
251 277
252 const string16 kPlaceholderText(ASCIIToUTF16("%s")); 278 const string16 kPlaceholderText(ASCIIToUTF16("%s"));
253 const string16 kReplacementText(ASCIIToUTF16("<input>")); 279 const string16 kReplacementText(ASCIIToUTF16("<input>"));
254 280
255 string16 description = suggestion->description; 281 string16 description = suggestion.description;
256 ACMatchClassifications& description_styles = match->contents_class; 282 ACMatchClassifications& description_styles = match->contents_class;
257 description_styles = suggestion->description_styles; 283 description_styles = suggestion.description_styles;
258 284
259 // Replace "%s" with the user's input and adjust the style offsets to the 285 // Replace "%s" with the user's input and adjust the style offsets to the
260 // new length of the description. 286 // new length of the description.
261 size_t placeholder(suggestion->description.find(kPlaceholderText, 0)); 287 size_t placeholder(suggestion.description.find(kPlaceholderText, 0));
262 if (placeholder != string16::npos) { 288 if (placeholder != string16::npos) {
263 string16 replacement = 289 string16 replacement =
264 remaining_input.empty() ? kReplacementText : remaining_input; 290 remaining_input.empty() ? kReplacementText : remaining_input;
265 description.replace(placeholder, kPlaceholderText.length(), replacement); 291 description.replace(placeholder, kPlaceholderText.length(), replacement);
266 292
267 for (size_t i = 0; i < description_styles.size(); ++i) { 293 for (size_t i = 0; i < description_styles.size(); ++i) {
268 if (description_styles[i].offset > placeholder) 294 if (description_styles[i].offset > placeholder)
269 description_styles[i].offset += replacement.length() - 2; 295 description_styles[i].offset += replacement.length() - 2;
270 } 296 }
271 } 297 }
(...skipping 20 matching lines...) Expand all
292 // preference is set, launch as a regular tab. 318 // preference is set, launch as a regular tab.
293 extension_misc::LaunchContainer launch_container = 319 extension_misc::LaunchContainer launch_container =
294 service->extension_prefs()->GetLaunchContainer( 320 service->extension_prefs()->GetLaunchContainer(
295 extension, ExtensionPrefs::LAUNCH_REGULAR); 321 extension, ExtensionPrefs::LAUNCH_REGULAR);
296 322
297 Browser::OpenApplication(profile, extension, launch_container, GURL(), 323 Browser::OpenApplication(profile, extension, launch_container, GURL(),
298 disposition); 324 disposition);
299 } 325 }
300 326
301 } // namespace extensions 327 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/omnibox/omnibox_api.h ('k') | chrome/browser/extensions/extension_prefs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698