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// 7var binding = require('binding').Binding.create('notifications'); 8 9var sendRequest = require('sendRequest').sendRequest; 10var imageUtil = require('imageUtil'); 11var lastError = require('lastError'); 12var notificationsPrivate = requireNative('notifications_private'); 13 14function 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|. 30function 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 // |appIconMaskUrl| is optional. 44 if (notificationDetails.appIconMaskUrl) { 45 $Array.push(urlSpecs, { 46 path: notificationDetails.appIconMaskUrl, 47 width: imageSizes.appIconMask.width * imageSizes.scaleFactor, 48 height: imageSizes.appIconMask.height * imageSizes.scaleFactor, 49 callback: imageDataSetter(notificationDetails, 'appIconMaskBitmap') 50 }); 51 } 52 53 // |imageUrl| is optional. 54 if (notificationDetails.imageUrl) { 55 $Array.push(urlSpecs, { 56 path: notificationDetails.imageUrl, 57 width: imageSizes.image.width * imageSizes.scaleFactor, 58 height: imageSizes.image.height * imageSizes.scaleFactor, 59 callback: imageDataSetter(notificationDetails, 'imageBitmap') 60 }); 61 } 62 63 // Each button has an optional icon. 64 var buttonList = notificationDetails.buttons; 65 if (buttonList && typeof buttonList.length === 'number') { 66 var numButtons = buttonList.length; 67 for (var i = 0; i < numButtons; i++) { 68 if (buttonList[i].iconUrl) { 69 $Array.push(urlSpecs, { 70 path: buttonList[i].iconUrl, 71 width: imageSizes.buttonIcon.width * imageSizes.scaleFactor, 72 height: imageSizes.buttonIcon.height * imageSizes.scaleFactor, 73 callback: imageDataSetter(buttonList[i], 'iconBitmap') 74 }); 75 } 76 } 77 } 78 79 return urlSpecs; 80} 81 82function replaceNotificationOptionURLs(notification_details, callback) { 83 var imageSizes = notificationsPrivate.GetNotificationImageSizes(); 84 var url_specs = getUrlSpecs(imageSizes, notification_details); 85 if (!url_specs.length) { 86 callback(true); 87 return; 88 } 89 90 var errors = 0; 91 92 imageUtil.loadAllImages(url_specs, { 93 onerror: function(index) { 94 errors++; 95 }, 96 oncomplete: function(imageData) { 97 if (errors > 0) { 98 callback(false); 99 return; 100 } 101 for (var index = 0; index < url_specs.length; index++) { 102 var url_spec = url_specs[index]; 103 url_spec.callback(imageData[index]); 104 } 105 callback(true); 106 } 107 }); 108} 109 110function genHandle(name, failure_function) { 111 return function(id, input_notification_details, callback) { 112 // TODO(dewittj): Remove this hack. This is used as a way to deep 113 // copy a complex JSON object. 114 var notification_details = JSON.parse( 115 JSON.stringify(input_notification_details)); 116 var that = this; 117 replaceNotificationOptionURLs(notification_details, function(success) { 118 if (success) { 119 sendRequest(that.name, 120 [id, notification_details, callback], 121 that.definition.parameters); 122 return; 123 } 124 lastError.run(name, 125 'Unable to download all specified images.', 126 null, 127 failure_function, [callback, id]) 128 }); 129 }; 130} 131 132var handleCreate = genHandle('notifications.create', 133 function(callback, id) { callback(id); }); 134var handleUpdate = genHandle('notifications.update', 135 function(callback, id) { callback(false); }); 136 137var notificationsCustomHook = function(bindingsAPI, extensionId) { 138 var apiFunctions = bindingsAPI.apiFunctions; 139 apiFunctions.setHandleRequest('create', handleCreate); 140 apiFunctions.setHandleRequest('update', handleUpdate); 141}; 142 143binding.registerCustomHook(notificationsCustomHook); 144 145exports.binding = binding.generate(); 146