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

Side by Side Diff: chrome/browser/extensions/api/notifications/notifications_api.cc

Issue 291193009: Reland: Allow high-res bitmaps to be passed in from notifications API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix test post-rebase. Created 6 years, 6 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
« no previous file with comments | « no previous file | chrome/browser/extensions/api/notifications/notifications_apitest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/notifications/notifications_api.h" 5 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/guid.h" 8 #include "base/guid.h"
9 #include "base/rand_util.h" 9 #include "base/rand_util.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h" 12 #include "base/time/time.h"
13 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/notifications/desktop_notification_service.h" 14 #include "chrome/browser/notifications/desktop_notification_service.h"
15 #include "chrome/browser/notifications/desktop_notification_service_factory.h" 15 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
16 #include "chrome/browser/notifications/notification.h" 16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/notification_ui_manager.h" 17 #include "chrome/browser/notifications/notification_ui_manager.h"
18 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_version_info.h" 19 #include "chrome/common/chrome_version_info.h"
20 #include "chrome/common/extensions/api/notifications/notification_style.h"
20 #include "content/public/browser/render_process_host.h" 21 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h" 22 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h" 23 #include "content/public/browser/web_contents.h"
23 #include "extensions/browser/event_router.h" 24 #include "extensions/browser/event_router.h"
24 #include "extensions/common/extension.h" 25 #include "extensions/common/extension.h"
25 #include "extensions/common/features/feature.h" 26 #include "extensions/common/features/feature.h"
26 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "ui/base/layout.h"
27 #include "ui/gfx/image/image.h" 29 #include "ui/gfx/image/image.h"
28 #include "ui/gfx/image/image_skia.h" 30 #include "ui/gfx/image/image_skia.h"
29 #include "ui/gfx/image/image_skia_rep.h" 31 #include "ui/gfx/image/image_skia_rep.h"
30 #include "ui/message_center/message_center_style.h" 32 #include "ui/message_center/message_center_style.h"
31 #include "ui/message_center/notifier_settings.h" 33 #include "ui/message_center/notifier_settings.h"
32 #include "url/gurl.h" 34 #include "url/gurl.h"
33 35
34 namespace extensions { 36 namespace extensions {
35 37
36 namespace notifications = api::notifications; 38 namespace notifications = api::notifications;
37 39
38 namespace { 40 namespace {
39 41
40 const char kMissingRequiredPropertiesForCreateNotification[] = 42 const char kMissingRequiredPropertiesForCreateNotification[] =
41 "Some of the required properties are missing: type, iconUrl, title and " 43 "Some of the required properties are missing: type, iconUrl, title and "
42 "message."; 44 "message.";
45 const char kUnableToDecodeIconError[] =
46 "Unable to successfully use the provided image.";
43 const char kUnexpectedProgressValueForNonProgressType[] = 47 const char kUnexpectedProgressValueForNonProgressType[] =
44 "The progress value should not be specified for non-progress notification"; 48 "The progress value should not be specified for non-progress notification";
45 const char kInvalidProgressValue[] = 49 const char kInvalidProgressValue[] =
46 "The progress value should range from 0 to 100"; 50 "The progress value should range from 0 to 100";
51 const char kExtraListItemsProvided[] =
52 "List items provided for notification type != list";
53 const char kExtraImageProvided[] =
54 "Image resource provided for notification type != image";
47 55
48 // Converts an object with width, height, and data in RGBA format into an 56 // Converts an object with width, height, and data in RGBA format into an
49 // gfx::Image (in ARGB format). 57 // gfx::Image (in ARGB format).
50 bool NotificationBitmapToGfxImage( 58 bool NotificationBitmapToGfxImage(
59 float max_scale,
60 const gfx::Size& target_size_dips,
51 api::notifications::NotificationBitmap* notification_bitmap, 61 api::notifications::NotificationBitmap* notification_bitmap,
52 gfx::Image* return_image) { 62 gfx::Image* return_image) {
53 if (!notification_bitmap) 63 if (!notification_bitmap)
54 return false; 64 return false;
55 65
56 // Ensure a sane set of dimensions. 66 const int max_device_pixel_width = target_size_dips.width() * max_scale;
57 const int max_width = message_center::kNotificationPreferredImageWidth; 67 const int max_device_pixel_height = target_size_dips.height() * max_scale;
58 const int max_height = message_center::kNotificationPreferredImageHeight; 68
59 const int BYTES_PER_PIXEL = 4; 69 const int BYTES_PER_PIXEL = 4;
60 70
61 const int width = notification_bitmap->width; 71 const int width = notification_bitmap->width;
62 const int height = notification_bitmap->height; 72 const int height = notification_bitmap->height;
63 73
64 if (width < 0 || height < 0 || width > max_width || height > max_height) 74 if (width < 0 || height < 0 || width > max_device_pixel_width ||
75 height > max_device_pixel_height)
65 return false; 76 return false;
66 77
67 // Ensure we have rgba data. 78 // Ensure we have rgba data.
68 std::string* rgba_data = notification_bitmap->data.get(); 79 std::string* rgba_data = notification_bitmap->data.get();
69 if (!rgba_data) 80 if (!rgba_data)
70 return false; 81 return false;
71 82
72 const size_t rgba_data_length = rgba_data->length(); 83 const size_t rgba_data_length = rgba_data->length();
73 const size_t rgba_area = width * height; 84 const size_t rgba_area = width * height;
74 85
(...skipping 18 matching lines...) Expand all
93 for (size_t t = 0; t < rgba_area; ++t) { 104 for (size_t t = 0; t < rgba_area; ++t) {
94 // |c_rgba_data| is RGBA, pixels is ARGB. 105 // |c_rgba_data| is RGBA, pixels is ARGB.
95 size_t rgba_index = t * BYTES_PER_PIXEL; 106 size_t rgba_index = t * BYTES_PER_PIXEL;
96 pixels[t] = SkPreMultiplyColor( 107 pixels[t] = SkPreMultiplyColor(
97 ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) | 108 ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) |
98 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) | 109 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) |
99 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) | 110 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) |
100 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); 111 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0));
101 } 112 }
102 113
103 // TODO(dewittj): Handle HiDPI images. 114 // TODO(dewittj): Handle HiDPI images with more than one scale factor
115 // representation.
104 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); 116 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f));
105 *return_image = gfx::Image(skia); 117 *return_image = gfx::Image(skia);
106 return true; 118 return true;
107 } 119 }
108 120
109 // Given an extension id and another id, returns an id that is unique 121 // Given an extension id and another id, returns an id that is unique
110 // relative to other extensions. 122 // relative to other extensions.
111 std::string CreateScopedIdentifier(const std::string& extension_id, 123 std::string CreateScopedIdentifier(const std::string& extension_id,
112 const std::string& id) { 124 const std::string& id) {
113 return extension_id + "-" + id; 125 return extension_id + "-" + id;
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 // First, make sure the required fields exist: type, title, message, icon. 259 // First, make sure the required fields exist: type, title, message, icon.
248 // These fields are defined as optional in IDL such that they can be used as 260 // These fields are defined as optional in IDL such that they can be used as
249 // optional for notification updates. But for notification creations, they 261 // optional for notification updates. But for notification creations, they
250 // should be present. 262 // should be present.
251 if (options->type == api::notifications::TEMPLATE_TYPE_NONE || 263 if (options->type == api::notifications::TEMPLATE_TYPE_NONE ||
252 !options->icon_url || !options->title || !options->message) { 264 !options->icon_url || !options->title || !options->message) {
253 SetError(kMissingRequiredPropertiesForCreateNotification); 265 SetError(kMissingRequiredPropertiesForCreateNotification);
254 return false; 266 return false;
255 } 267 }
256 268
269 NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
270
271 float image_scale =
272 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
273
257 // Extract required fields: type, title, message, and icon. 274 // Extract required fields: type, title, message, and icon.
258 message_center::NotificationType type = 275 message_center::NotificationType type =
259 MapApiTemplateTypeToType(options->type); 276 MapApiTemplateTypeToType(options->type);
260 const base::string16 title(base::UTF8ToUTF16(*options->title)); 277 const base::string16 title(base::UTF8ToUTF16(*options->title));
261 const base::string16 message(base::UTF8ToUTF16(*options->message)); 278 const base::string16 message(base::UTF8ToUTF16(*options->message));
262 gfx::Image icon; 279 gfx::Image icon;
263 280
264 // TODO(dewittj): Return error if this fails. 281 if (!NotificationBitmapToGfxImage(image_scale,
265 NotificationBitmapToGfxImage(options->icon_bitmap.get(), &icon); 282 bitmap_sizes.icon_size,
283 options->icon_bitmap.get(),
284 &icon)) {
285 SetError(kUnableToDecodeIconError);
286 return false;
287 }
266 288
267 // Then, handle any optional data that's been provided. 289 // Then, handle any optional data that's been provided.
268 message_center::RichNotificationData optional_fields; 290 message_center::RichNotificationData optional_fields;
269 if (options->priority.get()) 291 if (options->priority.get())
270 optional_fields.priority = *options->priority; 292 optional_fields.priority = *options->priority;
271 293
272 if (options->event_time.get()) 294 if (options->event_time.get())
273 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time); 295 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time);
274 296
275 if (options->buttons.get()) { 297 if (options->buttons.get()) {
276 // Currently we allow up to 2 buttons. 298 // Currently we allow up to 2 buttons.
277 size_t number_of_buttons = options->buttons->size(); 299 size_t number_of_buttons = options->buttons->size();
278 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; 300 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
279 301
280 for (size_t i = 0; i < number_of_buttons; i++) { 302 for (size_t i = 0; i < number_of_buttons; i++) {
281 message_center::ButtonInfo info( 303 message_center::ButtonInfo info(
282 base::UTF8ToUTF16((*options->buttons)[i]->title)); 304 base::UTF8ToUTF16((*options->buttons)[i]->title));
283 NotificationBitmapToGfxImage((*options->buttons)[i]->icon_bitmap.get(), 305 NotificationBitmapToGfxImage(image_scale,
284 &info.icon); 306 bitmap_sizes.button_icon_size,
307 (*options->buttons)[i]->icon_bitmap.get(),
308 &info.icon);
285 optional_fields.buttons.push_back(info); 309 optional_fields.buttons.push_back(info);
286 } 310 }
287 } 311 }
288 312
289 if (options->context_message) { 313 if (options->context_message) {
290 optional_fields.context_message = 314 optional_fields.context_message =
291 base::UTF8ToUTF16(*options->context_message); 315 base::UTF8ToUTF16(*options->context_message);
292 } 316 }
293 317
294 bool has_image = NotificationBitmapToGfxImage(options->image_bitmap.get(), 318 bool has_image = NotificationBitmapToGfxImage(image_scale,
319 bitmap_sizes.image_size,
320 options->image_bitmap.get(),
295 &optional_fields.image); 321 &optional_fields.image);
296 // We should have an image if and only if the type is an image type. 322 // We should have an image if and only if the type is an image type.
297 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) 323 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) {
324 SetError(kExtraImageProvided);
298 return false; 325 return false;
326 }
299 327
300 // We should have list items if and only if the type is a multiple type. 328 // We should have list items if and only if the type is a multiple type.
301 bool has_list_items = options->items.get() && options->items->size() > 0; 329 bool has_list_items = options->items.get() && options->items->size() > 0;
302 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) 330 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) {
331 SetError(kExtraListItemsProvided);
303 return false; 332 return false;
333 }
304 334
305 if (options->progress.get() != NULL) { 335 if (options->progress.get() != NULL) {
306 // We should have progress if and only if the type is a progress type. 336 // We should have progress if and only if the type is a progress type.
307 if (type != message_center::NOTIFICATION_TYPE_PROGRESS) { 337 if (type != message_center::NOTIFICATION_TYPE_PROGRESS) {
308 SetError(kUnexpectedProgressValueForNonProgressType); 338 SetError(kUnexpectedProgressValueForNonProgressType);
309 return false; 339 return false;
310 } 340 }
311 optional_fields.progress = *options->progress; 341 optional_fields.progress = *options->progress;
312 // Progress value should range from 0 to 100. 342 // Progress value should range from 0 to 100.
313 if (optional_fields.progress < 0 || optional_fields.progress > 100) { 343 if (optional_fields.progress < 0 || optional_fields.progress > 100) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 api_delegate); 378 api_delegate);
349 379
350 g_browser_process->notification_ui_manager()->Add(notification, GetProfile()); 380 g_browser_process->notification_ui_manager()->Add(notification, GetProfile());
351 return true; 381 return true;
352 } 382 }
353 383
354 bool NotificationsApiFunction::UpdateNotification( 384 bool NotificationsApiFunction::UpdateNotification(
355 const std::string& id, 385 const std::string& id,
356 api::notifications::NotificationOptions* options, 386 api::notifications::NotificationOptions* options,
357 Notification* notification) { 387 Notification* notification) {
388 NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
389 float image_scale =
390 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
391
358 // Update optional fields if provided. 392 // Update optional fields if provided.
359 if (options->type != api::notifications::TEMPLATE_TYPE_NONE) 393 if (options->type != api::notifications::TEMPLATE_TYPE_NONE)
360 notification->set_type(MapApiTemplateTypeToType(options->type)); 394 notification->set_type(MapApiTemplateTypeToType(options->type));
361 if (options->title) 395 if (options->title)
362 notification->set_title(base::UTF8ToUTF16(*options->title)); 396 notification->set_title(base::UTF8ToUTF16(*options->title));
363 if (options->message) 397 if (options->message)
364 notification->set_message(base::UTF8ToUTF16(*options->message)); 398 notification->set_message(base::UTF8ToUTF16(*options->message));
365 399
366 // TODO(dewittj): Return error if this fails. 400 // TODO(dewittj): Return error if this fails.
367 if (options->icon_bitmap) { 401 if (options->icon_bitmap) {
368 gfx::Image icon; 402 gfx::Image icon;
369 NotificationBitmapToGfxImage(options->icon_bitmap.get(), &icon); 403 NotificationBitmapToGfxImage(
404 image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon);
370 notification->set_icon(icon); 405 notification->set_icon(icon);
371 } 406 }
372 407
373 if (options->priority) 408 if (options->priority)
374 notification->set_priority(*options->priority); 409 notification->set_priority(*options->priority);
375 410
376 if (options->event_time) 411 if (options->event_time)
377 notification->set_timestamp(base::Time::FromJsTime(*options->event_time)); 412 notification->set_timestamp(base::Time::FromJsTime(*options->event_time));
378 413
379 if (options->buttons) { 414 if (options->buttons) {
380 // Currently we allow up to 2 buttons. 415 // Currently we allow up to 2 buttons.
381 size_t number_of_buttons = options->buttons->size(); 416 size_t number_of_buttons = options->buttons->size();
382 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; 417 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
383 418
384 std::vector<message_center::ButtonInfo> buttons; 419 std::vector<message_center::ButtonInfo> buttons;
385 for (size_t i = 0; i < number_of_buttons; i++) { 420 for (size_t i = 0; i < number_of_buttons; i++) {
386 message_center::ButtonInfo button( 421 message_center::ButtonInfo button(
387 base::UTF8ToUTF16((*options->buttons)[i]->title)); 422 base::UTF8ToUTF16((*options->buttons)[i]->title));
388 NotificationBitmapToGfxImage((*options->buttons)[i]->icon_bitmap.get(), 423 NotificationBitmapToGfxImage(image_scale,
389 &button.icon); 424 bitmap_sizes.button_icon_size,
425 (*options->buttons)[i]->icon_bitmap.get(),
426 &button.icon);
390 buttons.push_back(button); 427 buttons.push_back(button);
391 } 428 }
392 notification->set_buttons(buttons); 429 notification->set_buttons(buttons);
393 } 430 }
394 431
395 if (options->context_message) { 432 if (options->context_message) {
396 notification->set_context_message( 433 notification->set_context_message(
397 base::UTF8ToUTF16(*options->context_message)); 434 base::UTF8ToUTF16(*options->context_message));
398 } 435 }
399 436
400 gfx::Image image; 437 gfx::Image image;
401 if (NotificationBitmapToGfxImage(options->image_bitmap.get(), &image)) { 438 bool has_image = NotificationBitmapToGfxImage(image_scale,
439 bitmap_sizes.image_size,
440 options->image_bitmap.get(),
441 &image);
442 if (has_image) {
402 // We should have an image if and only if the type is an image type. 443 // We should have an image if and only if the type is an image type.
403 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) 444 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) {
445 SetError(kExtraImageProvided);
404 return false; 446 return false;
447 }
405 notification->set_image(image); 448 notification->set_image(image);
406 } 449 }
407 450
408 if (options->progress) { 451 if (options->progress) {
409 // We should have progress if and only if the type is a progress type. 452 // We should have progress if and only if the type is a progress type.
410 if (notification->type() != message_center::NOTIFICATION_TYPE_PROGRESS) { 453 if (notification->type() != message_center::NOTIFICATION_TYPE_PROGRESS) {
411 SetError(kUnexpectedProgressValueForNonProgressType); 454 SetError(kUnexpectedProgressValueForNonProgressType);
412 return false; 455 return false;
413 } 456 }
414 int progress = *options->progress; 457 int progress = *options->progress;
415 // Progress value should range from 0 to 100. 458 // Progress value should range from 0 to 100.
416 if (progress < 0 || progress > 100) { 459 if (progress < 0 || progress > 100) {
417 SetError(kInvalidProgressValue); 460 SetError(kInvalidProgressValue);
418 return false; 461 return false;
419 } 462 }
420 notification->set_progress(progress); 463 notification->set_progress(progress);
421 } 464 }
422 465
423 if (options->items.get() && options->items->size() > 0) { 466 if (options->items.get() && options->items->size() > 0) {
424 // We should have list items if and only if the type is a multiple type. 467 // We should have list items if and only if the type is a multiple type.
425 if (notification->type() != message_center::NOTIFICATION_TYPE_MULTIPLE) 468 if (notification->type() != message_center::NOTIFICATION_TYPE_MULTIPLE) {
469 SetError(kExtraListItemsProvided);
426 return false; 470 return false;
471 }
427 472
428 std::vector<message_center::NotificationItem> items; 473 std::vector<message_center::NotificationItem> items;
429 using api::notifications::NotificationItem; 474 using api::notifications::NotificationItem;
430 std::vector<linked_ptr<NotificationItem> >::iterator i; 475 std::vector<linked_ptr<NotificationItem> >::iterator i;
431 for (i = options->items->begin(); i != options->items->end(); ++i) { 476 for (i = options->items->begin(); i != options->items->end(); ++i) {
432 message_center::NotificationItem item( 477 message_center::NotificationItem item(
433 base::UTF8ToUTF16(i->get()->title), 478 base::UTF8ToUTF16(i->get()->title),
434 base::UTF8ToUTF16(i->get()->message)); 479 base::UTF8ToUTF16(i->get()->message));
435 items.push_back(item); 480 items.push_back(item);
436 } 481 }
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 ? api::notifications::PERMISSION_LEVEL_GRANTED 669 ? api::notifications::PERMISSION_LEVEL_GRANTED
625 : api::notifications::PERMISSION_LEVEL_DENIED; 670 : api::notifications::PERMISSION_LEVEL_DENIED;
626 671
627 SetResult(new base::StringValue(api::notifications::ToString(result))); 672 SetResult(new base::StringValue(api::notifications::ToString(result)));
628 SendResponse(true); 673 SendResponse(true);
629 674
630 return true; 675 return true;
631 } 676 }
632 677
633 } // namespace extensions 678 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/extensions/api/notifications/notifications_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698