1 // Copyright 2013 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 // Custom bindings for the notifications API. 6 // 7 var binding = require('binding').Binding.create('notifications'); 8 9 var sendRequest = require('sendRequest').sendRequest; 10 var imageUtil = require('imageUtil'); 11 var lastError = require('lastError'); 12 var notificationsPrivate = requireNative('notifications_private'); 13 14 function imageDataSetter(context, key) { 15 var f = function(val) { 16 this[key] = val; 17 }; 18 return $Function.bind(f, context); 19 } 20 21 // A URL Spec is an object with the following keys: 22 // path: The resource to be downloaded. 23 // width: (optional) The maximum width of the image to be downloaded in device 24 // pixels. 25 // height: (optional) The maximum height of the image to be downloaded in 26 // device pixels. 27 // callback: A function to be called when the URL is complete. It 28 // should accept an ImageData object and set the appropriate 29 // field in |notificationDetails|. 30 function getUrlSpecs(imageSizes, notificationDetails) { 31 var urlSpecs = []; 32 33 // |iconUrl| might be optional for notification updates. 34 if (notificationDetails.iconUrl) { 35 $Array.push(urlSpecs, { 36 path: notificationDetails.iconUrl, 37 width: imageSizes.icon.width * imageSizes.scaleFactor, 38 height: imageSizes.icon.height * imageSizes.scaleFactor, 39 callback: imageDataSetter(notificationDetails, 'iconBitmap') 40 }); 41 } 42 43 // |imageUrl| is optional. 44 if (notificationDetails.imageUrl) { 45 $Array.push(urlSpecs, { 46 path: notificationDetails.imageUrl, 47 width: imageSizes.image.width * imageSizes.scaleFactor, 48 height: imageSizes.image.height * imageSizes.scaleFactor, 49 callback: imageDataSetter(notificationDetails, 'imageBitmap') 50 }); 51 } 52 53 // Each button has an optional icon. 54 var buttonList = notificationDetails.buttons; 55 if (buttonList && typeof buttonList.length === 'number') { 56 var numButtons = buttonList.length; 57 for (var i = 0; i < numButtons; i++) { 58 if (buttonList[i].iconUrl) { 59 $Array.push(urlSpecs, { 60 path: buttonList[i].iconUrl, 61 width: imageSizes.buttonIcon.width * imageSizes.scaleFactor, 62 height: imageSizes.buttonIcon.height * imageSizes.scaleFactor, 63 callback: imageDataSetter(buttonList[i], 'iconBitmap') 64 }); 65 } 66 } 67 } 68 69 return urlSpecs; 70 } 71 72 function replaceNotificationOptionURLs(notification_details, callback) { 73 var imageSizes = notificationsPrivate.GetNotificationImageSizes(); 74 var url_specs = getUrlSpecs(imageSizes, notification_details); 75 if (!url_specs.length) { 76 callback(true); 77 return; 78 } 79 80 var errors = 0; 81 82 imageUtil.loadAllImages(url_specs, { 83 onerror: function(index) { 84 errors++; 85 }, 86 oncomplete: function(imageData) { 87 if (errors > 0) { 88 callback(false); 89 return; 90 } 91 for (var index = 0; index < url_specs.length; index++) { 92 var url_spec = url_specs[index]; 93 url_spec.callback(imageData[index]); 94 } 95 callback(true); 96 } 97 }); 98 } 99 100 function genHandle(name, failure_function) { 101 return function(id, input_notification_details, callback) { 102 // TODO(dewittj): Remove this hack. This is used as a way to deep 103 // copy a complex JSON object. 104 var notification_details = JSON.parse( 105 JSON.stringify(input_notification_details)); 106 var that = this; 107 replaceNotificationOptionURLs(notification_details, function(success) { 108 if (success) { 109 sendRequest(that.name, 110 [id, notification_details, callback], 111 that.definition.parameters); 112 return; 113 } 114 lastError.run(name, 115 'Unable to download all specified images.', 116 null, 117 failure_function, [callback, id]) 118 }); 119 }; 120 } 121 122 var handleCreate = genHandle('notifications.create', 123 function(callback, id) { callback(id); }); 124 var handleUpdate = genHandle('notifications.update', 125 function(callback, id) { callback(false); }); 126 127 var notificationsCustomHook = function(bindingsAPI, extensionId) { 128 var apiFunctions = bindingsAPI.apiFunctions; 129 apiFunctions.setHandleRequest('create', handleCreate); 130 apiFunctions.setHandleRequest('update', handleUpdate); 131 }; 132 133 binding.registerCustomHook(notificationsCustomHook); 134 135 exports.binding = binding.generate(); 136