| OLD | NEW |
| 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_conversion_helper.h" | |
| 18 #include "chrome/browser/notifications/notification_ui_manager.h" | 17 #include "chrome/browser/notifications/notification_ui_manager.h" |
| 19 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 20 #include "chrome/common/chrome_version_info.h" | 19 #include "chrome/common/chrome_version_info.h" |
| 21 #include "chrome/common/extensions/api/notifications/notification_style.h" | 20 #include "chrome/common/extensions/api/notifications/notification_style.h" |
| 22 #include "content/public/browser/render_process_host.h" | 21 #include "content/public/browser/render_process_host.h" |
| 23 #include "content/public/browser/render_view_host.h" | 22 #include "content/public/browser/render_view_host.h" |
| 24 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 25 #include "extensions/browser/event_router.h" | 24 #include "extensions/browser/event_router.h" |
| 26 #include "extensions/common/extension.h" | 25 #include "extensions/common/extension.h" |
| 27 #include "extensions/common/features/feature.h" | 26 #include "extensions/common/features/feature.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 47 "Unable to successfully use the provided image."; | 46 "Unable to successfully use the provided image."; |
| 48 const char kUnexpectedProgressValueForNonProgressType[] = | 47 const char kUnexpectedProgressValueForNonProgressType[] = |
| 49 "The progress value should not be specified for non-progress notification"; | 48 "The progress value should not be specified for non-progress notification"; |
| 50 const char kInvalidProgressValue[] = | 49 const char kInvalidProgressValue[] = |
| 51 "The progress value should range from 0 to 100"; | 50 "The progress value should range from 0 to 100"; |
| 52 const char kExtraListItemsProvided[] = | 51 const char kExtraListItemsProvided[] = |
| 53 "List items provided for notification type != list"; | 52 "List items provided for notification type != list"; |
| 54 const char kExtraImageProvided[] = | 53 const char kExtraImageProvided[] = |
| 55 "Image resource provided for notification type != image"; | 54 "Image resource provided for notification type != image"; |
| 56 | 55 |
| 56 // Converts an object with width, height, and data in RGBA format into an |
| 57 // gfx::Image (in ARGB format). |
| 58 bool NotificationBitmapToGfxImage( |
| 59 float max_scale, |
| 60 const gfx::Size& target_size_dips, |
| 61 api::notifications::NotificationBitmap* notification_bitmap, |
| 62 gfx::Image* return_image) { |
| 63 if (!notification_bitmap) |
| 64 return false; |
| 65 |
| 66 const int max_device_pixel_width = target_size_dips.width() * max_scale; |
| 67 const int max_device_pixel_height = target_size_dips.height() * max_scale; |
| 68 |
| 69 const int BYTES_PER_PIXEL = 4; |
| 70 |
| 71 const int width = notification_bitmap->width; |
| 72 const int height = notification_bitmap->height; |
| 73 |
| 74 if (width < 0 || height < 0 || width > max_device_pixel_width || |
| 75 height > max_device_pixel_height) |
| 76 return false; |
| 77 |
| 78 // Ensure we have rgba data. |
| 79 std::string* rgba_data = notification_bitmap->data.get(); |
| 80 if (!rgba_data) |
| 81 return false; |
| 82 |
| 83 const size_t rgba_data_length = rgba_data->length(); |
| 84 const size_t rgba_area = width * height; |
| 85 |
| 86 if (rgba_data_length != rgba_area * BYTES_PER_PIXEL) |
| 87 return false; |
| 88 |
| 89 SkBitmap bitmap; |
| 90 // Allocate the actual backing store with the sanitized dimensions. |
| 91 if (!bitmap.allocN32Pixels(width, height)) |
| 92 return false; |
| 93 |
| 94 // Ensure that our bitmap and our data now refer to the same number of pixels. |
| 95 if (rgba_data_length != bitmap.getSafeSize()) |
| 96 return false; |
| 97 |
| 98 uint32_t* pixels = bitmap.getAddr32(0, 0); |
| 99 const char* c_rgba_data = rgba_data->data(); |
| 100 |
| 101 for (size_t t = 0; t < rgba_area; ++t) { |
| 102 // |c_rgba_data| is RGBA, pixels is ARGB. |
| 103 size_t rgba_index = t * BYTES_PER_PIXEL; |
| 104 pixels[t] = SkPreMultiplyColor( |
| 105 ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) | |
| 106 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) | |
| 107 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) | |
| 108 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); |
| 109 } |
| 110 |
| 111 // TODO(dewittj): Handle HiDPI images with more than one scale factor |
| 112 // representation. |
| 113 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); |
| 114 *return_image = gfx::Image(skia); |
| 115 return true; |
| 116 } |
| 117 |
| 57 // Given an extension id and another id, returns an id that is unique | 118 // Given an extension id and another id, returns an id that is unique |
| 58 // relative to other extensions. | 119 // relative to other extensions. |
| 59 std::string CreateScopedIdentifier(const std::string& extension_id, | 120 std::string CreateScopedIdentifier(const std::string& extension_id, |
| 60 const std::string& id) { | 121 const std::string& id) { |
| 61 return extension_id + "-" + id; | 122 return extension_id + "-" + id; |
| 62 } | 123 } |
| 63 | 124 |
| 64 // Removes the unique internal identifier to send the ID as the | 125 // Removes the unique internal identifier to send the ID as the |
| 65 // extension expects it. | 126 // extension expects it. |
| 66 std::string StripScopeFromIdentifier(const std::string& extension_id, | 127 std::string StripScopeFromIdentifier(const std::string& extension_id, |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 float image_scale = | 268 float image_scale = |
| 208 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back()); | 269 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back()); |
| 209 | 270 |
| 210 // Extract required fields: type, title, message, and icon. | 271 // Extract required fields: type, title, message, and icon. |
| 211 message_center::NotificationType type = | 272 message_center::NotificationType type = |
| 212 MapApiTemplateTypeToType(options->type); | 273 MapApiTemplateTypeToType(options->type); |
| 213 const base::string16 title(base::UTF8ToUTF16(*options->title)); | 274 const base::string16 title(base::UTF8ToUTF16(*options->title)); |
| 214 const base::string16 message(base::UTF8ToUTF16(*options->message)); | 275 const base::string16 message(base::UTF8ToUTF16(*options->message)); |
| 215 gfx::Image icon; | 276 gfx::Image icon; |
| 216 | 277 |
| 217 if (!NotificationConversionHelper::NotificationBitmapToGfxImage( | 278 if (!NotificationBitmapToGfxImage(image_scale, |
| 218 image_scale, | 279 bitmap_sizes.icon_size, |
| 219 bitmap_sizes.icon_size, | 280 options->icon_bitmap.get(), |
| 220 options->icon_bitmap.get(), | 281 &icon)) { |
| 221 &icon)) { | |
| 222 SetError(kUnableToDecodeIconError); | 282 SetError(kUnableToDecodeIconError); |
| 223 return false; | 283 return false; |
| 224 } | 284 } |
| 225 | 285 |
| 226 // Then, handle any optional data that's been provided. | 286 // Then, handle any optional data that's been provided. |
| 227 message_center::RichNotificationData optional_fields; | 287 message_center::RichNotificationData optional_fields; |
| 228 if (options->app_icon_mask_url.get()) { | 288 if (options->app_icon_mask_url.get()) { |
| 229 if (!NotificationConversionHelper::NotificationBitmapToGfxImage( | 289 if (!NotificationBitmapToGfxImage(image_scale, |
| 230 image_scale, | 290 bitmap_sizes.app_icon_mask_size, |
| 231 bitmap_sizes.app_icon_mask_size, | 291 options->app_icon_mask_bitmap.get(), |
| 232 options->app_icon_mask_bitmap.get(), | 292 &optional_fields.small_image)) { |
| 233 &optional_fields.small_image)) { | |
| 234 SetError(kUnableToDecodeIconError); | 293 SetError(kUnableToDecodeIconError); |
| 235 return false; | 294 return false; |
| 236 } | 295 } |
| 237 } | 296 } |
| 238 | 297 |
| 239 if (options->priority.get()) | 298 if (options->priority.get()) |
| 240 optional_fields.priority = *options->priority; | 299 optional_fields.priority = *options->priority; |
| 241 | 300 |
| 242 if (options->event_time.get()) | 301 if (options->event_time.get()) |
| 243 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time); | 302 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time); |
| 244 | 303 |
| 245 if (options->buttons.get()) { | 304 if (options->buttons.get()) { |
| 246 // Currently we allow up to 2 buttons. | 305 // Currently we allow up to 2 buttons. |
| 247 size_t number_of_buttons = options->buttons->size(); | 306 size_t number_of_buttons = options->buttons->size(); |
| 248 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; | 307 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; |
| 249 | 308 |
| 250 for (size_t i = 0; i < number_of_buttons; i++) { | 309 for (size_t i = 0; i < number_of_buttons; i++) { |
| 251 message_center::ButtonInfo info( | 310 message_center::ButtonInfo info( |
| 252 base::UTF8ToUTF16((*options->buttons)[i]->title)); | 311 base::UTF8ToUTF16((*options->buttons)[i]->title)); |
| 253 NotificationConversionHelper::NotificationBitmapToGfxImage( | 312 NotificationBitmapToGfxImage(image_scale, |
| 254 image_scale, | 313 bitmap_sizes.button_icon_size, |
| 255 bitmap_sizes.button_icon_size, | 314 (*options->buttons)[i]->icon_bitmap.get(), |
| 256 (*options->buttons)[i]->icon_bitmap.get(), | 315 &info.icon); |
| 257 &info.icon); | |
| 258 optional_fields.buttons.push_back(info); | 316 optional_fields.buttons.push_back(info); |
| 259 } | 317 } |
| 260 } | 318 } |
| 261 | 319 |
| 262 if (options->context_message) { | 320 if (options->context_message) { |
| 263 optional_fields.context_message = | 321 optional_fields.context_message = |
| 264 base::UTF8ToUTF16(*options->context_message); | 322 base::UTF8ToUTF16(*options->context_message); |
| 265 } | 323 } |
| 266 | 324 |
| 267 bool has_image = NotificationConversionHelper::NotificationBitmapToGfxImage( | 325 bool has_image = NotificationBitmapToGfxImage(image_scale, |
| 268 image_scale, | 326 bitmap_sizes.image_size, |
| 269 bitmap_sizes.image_size, | 327 options->image_bitmap.get(), |
| 270 options->image_bitmap.get(), | 328 &optional_fields.image); |
| 271 &optional_fields.image); | |
| 272 // We should have an image if and only if the type is an image type. | 329 // We should have an image if and only if the type is an image type. |
| 273 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) { | 330 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) { |
| 274 SetError(kExtraImageProvided); | 331 SetError(kExtraImageProvided); |
| 275 return false; | 332 return false; |
| 276 } | 333 } |
| 277 | 334 |
| 278 // We should have list items if and only if the type is a multiple type. | 335 // We should have list items if and only if the type is a multiple type. |
| 279 bool has_list_items = options->items.get() && options->items->size() > 0; | 336 bool has_list_items = options->items.get() && options->items->size() > 0; |
| 280 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) { | 337 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) { |
| 281 SetError(kExtraListItemsProvided); | 338 SetError(kExtraListItemsProvided); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 if (options->type != api::notifications::TEMPLATE_TYPE_NONE) | 400 if (options->type != api::notifications::TEMPLATE_TYPE_NONE) |
| 344 notification->set_type(MapApiTemplateTypeToType(options->type)); | 401 notification->set_type(MapApiTemplateTypeToType(options->type)); |
| 345 if (options->title) | 402 if (options->title) |
| 346 notification->set_title(base::UTF8ToUTF16(*options->title)); | 403 notification->set_title(base::UTF8ToUTF16(*options->title)); |
| 347 if (options->message) | 404 if (options->message) |
| 348 notification->set_message(base::UTF8ToUTF16(*options->message)); | 405 notification->set_message(base::UTF8ToUTF16(*options->message)); |
| 349 | 406 |
| 350 // TODO(dewittj): Return error if this fails. | 407 // TODO(dewittj): Return error if this fails. |
| 351 if (options->icon_bitmap) { | 408 if (options->icon_bitmap) { |
| 352 gfx::Image icon; | 409 gfx::Image icon; |
| 353 NotificationConversionHelper::NotificationBitmapToGfxImage( | 410 NotificationBitmapToGfxImage( |
| 354 image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon); | 411 image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon); |
| 355 notification->set_icon(icon); | 412 notification->set_icon(icon); |
| 356 } | 413 } |
| 357 | 414 |
| 358 gfx::Image app_icon_mask; | 415 gfx::Image app_icon_mask; |
| 359 if (NotificationConversionHelper::NotificationBitmapToGfxImage( | 416 if (NotificationBitmapToGfxImage(image_scale, |
| 360 image_scale, | 417 bitmap_sizes.app_icon_mask_size, |
| 361 bitmap_sizes.app_icon_mask_size, | 418 options->app_icon_mask_bitmap.get(), |
| 362 options->app_icon_mask_bitmap.get(), | 419 &app_icon_mask)) { |
| 363 &app_icon_mask)) { | |
| 364 notification->set_small_image(app_icon_mask); | 420 notification->set_small_image(app_icon_mask); |
| 365 } | 421 } |
| 366 | 422 |
| 367 if (options->priority) | 423 if (options->priority) |
| 368 notification->set_priority(*options->priority); | 424 notification->set_priority(*options->priority); |
| 369 | 425 |
| 370 if (options->event_time) | 426 if (options->event_time) |
| 371 notification->set_timestamp(base::Time::FromJsTime(*options->event_time)); | 427 notification->set_timestamp(base::Time::FromJsTime(*options->event_time)); |
| 372 | 428 |
| 373 if (options->buttons) { | 429 if (options->buttons) { |
| 374 // Currently we allow up to 2 buttons. | 430 // Currently we allow up to 2 buttons. |
| 375 size_t number_of_buttons = options->buttons->size(); | 431 size_t number_of_buttons = options->buttons->size(); |
| 376 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; | 432 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; |
| 377 | 433 |
| 378 std::vector<message_center::ButtonInfo> buttons; | 434 std::vector<message_center::ButtonInfo> buttons; |
| 379 for (size_t i = 0; i < number_of_buttons; i++) { | 435 for (size_t i = 0; i < number_of_buttons; i++) { |
| 380 message_center::ButtonInfo button( | 436 message_center::ButtonInfo button( |
| 381 base::UTF8ToUTF16((*options->buttons)[i]->title)); | 437 base::UTF8ToUTF16((*options->buttons)[i]->title)); |
| 382 NotificationConversionHelper::NotificationBitmapToGfxImage( | 438 NotificationBitmapToGfxImage(image_scale, |
| 383 image_scale, | 439 bitmap_sizes.button_icon_size, |
| 384 bitmap_sizes.button_icon_size, | 440 (*options->buttons)[i]->icon_bitmap.get(), |
| 385 (*options->buttons)[i]->icon_bitmap.get(), | 441 &button.icon); |
| 386 &button.icon); | |
| 387 buttons.push_back(button); | 442 buttons.push_back(button); |
| 388 } | 443 } |
| 389 notification->set_buttons(buttons); | 444 notification->set_buttons(buttons); |
| 390 } | 445 } |
| 391 | 446 |
| 392 if (options->context_message) { | 447 if (options->context_message) { |
| 393 notification->set_context_message( | 448 notification->set_context_message( |
| 394 base::UTF8ToUTF16(*options->context_message)); | 449 base::UTF8ToUTF16(*options->context_message)); |
| 395 } | 450 } |
| 396 | 451 |
| 397 gfx::Image image; | 452 gfx::Image image; |
| 398 bool has_image = NotificationConversionHelper::NotificationBitmapToGfxImage( | 453 bool has_image = NotificationBitmapToGfxImage(image_scale, |
| 399 image_scale, | 454 bitmap_sizes.image_size, |
| 400 bitmap_sizes.image_size, | 455 options->image_bitmap.get(), |
| 401 options->image_bitmap.get(), | 456 &image); |
| 402 &image); | |
| 403 if (has_image) { | 457 if (has_image) { |
| 404 // We should have an image if and only if the type is an image type. | 458 // We should have an image if and only if the type is an image type. |
| 405 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) { | 459 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) { |
| 406 SetError(kExtraImageProvided); | 460 SetError(kExtraImageProvided); |
| 407 return false; | 461 return false; |
| 408 } | 462 } |
| 409 notification->set_image(image); | 463 notification->set_image(image); |
| 410 } | 464 } |
| 411 | 465 |
| 412 if (options->progress) { | 466 if (options->progress) { |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 ? api::notifications::PERMISSION_LEVEL_GRANTED | 684 ? api::notifications::PERMISSION_LEVEL_GRANTED |
| 631 : api::notifications::PERMISSION_LEVEL_DENIED; | 685 : api::notifications::PERMISSION_LEVEL_DENIED; |
| 632 | 686 |
| 633 SetResult(new base::StringValue(api::notifications::ToString(result))); | 687 SetResult(new base::StringValue(api::notifications::ToString(result))); |
| 634 SendResponse(true); | 688 SendResponse(true); |
| 635 | 689 |
| 636 return true; | 690 return true; |
| 637 } | 691 } |
| 638 | 692 |
| 639 } // namespace extensions | 693 } // namespace extensions |
| OLD | NEW |