Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 /** | 5 /** |
| 6 * @type {number} | 6 * @type {number} |
| 7 * @const | 7 * @const |
| 8 */ | 8 */ |
| 9 var FEEDBACK_WIDTH = 500; | 9 var FEEDBACK_WIDTH = 500; |
| 10 /** | 10 /** |
| 11 * @type {number} | 11 * @type {number} |
| 12 * @const | 12 * @const |
| 13 */ | 13 */ |
| 14 var FEEDBACK_HEIGHT = 585; | 14 var FEEDBACK_HEIGHT = 585; |
| 15 | 15 |
| 16 /** | 16 /** |
| 17 * @type {string} | 17 * @type {string} |
| 18 * @const | 18 * @const |
| 19 */ | 19 */ |
| 20 var FEEDBACK_DEFAULT_WINDOW_ID = 'default_window'; | 20 var FEEDBACK_DEFAULT_WINDOW_ID = 'default_window'; |
| 21 | 21 |
| 22 /** | |
| 23 * The feedback info received initially when the feedback UI was first requested | |
| 24 * to start. | |
| 25 * @type {Object} | |
| 26 */ | |
| 27 var initialFeedbackInfo = null; | |
| 28 | |
| 29 /** | |
| 30 * The feedbak info that is ready to be sent later when the system information | |
| 31 * becomes available. | |
| 32 * @type {Object} | |
| 33 */ | |
| 34 var finalFeedbackInfo = null; | |
| 35 | |
| 36 /** | |
| 37 * The system information received from the C++ side. | |
| 38 * @type {Object} | |
| 39 */ | |
| 40 var systemInfo = null; | |
| 41 | |
| 42 /** | |
| 43 * True if the system information has been received, false otherwise. | |
| 44 * @type {boolean} | |
| 45 */ | |
| 46 var isSystemInfoReady = false; | |
| 47 | |
| 48 /** | |
| 49 * A callback to be invoked when the system information is ready. | |
| 50 * @type {function(sysInfo)} | |
| 51 */ | |
| 52 var onSystemInfoReadyCallback = null; | |
| 53 | |
| 54 // To generate a hashed extension ID, use a sha-256 hash, all in lower case. | 22 // To generate a hashed extension ID, use a sha-256 hash, all in lower case. |
| 55 // Example: | 23 // Example: |
| 56 // echo -n 'abcdefghijklmnopqrstuvwxyzabcdef' | sha1sum | \ | 24 // echo -n 'abcdefghijklmnopqrstuvwxyzabcdef' | sha1sum | \ |
| 57 // awk '{print toupper($1)}' | 25 // awk '{print toupper($1)}' |
| 58 var whitelistedExtensionIds = [ | 26 var whitelistedExtensionIds = [ |
| 59 '12E618C3C6E97495AAECF2AC12DEB082353241C6', // QuickOffice | 27 '12E618C3C6E97495AAECF2AC12DEB082353241C6', // QuickOffice |
| 60 '3727DD3E564B6055387425027AD74C58784ACC15', // QuickOffice | 28 '3727DD3E564B6055387425027AD74C58784ACC15', // QuickOffice |
| 61 '2FC374607C2DF285634B67C64A2E356C607091C3', // QuickOffice | 29 '2FC374607C2DF285634B67C64A2E356C607091C3', // QuickOffice |
| 62 '2843C1E82A9B6C6FB49308FDDF4E157B6B44BC2B', // G+ Photos | 30 '2843C1E82A9B6C6FB49308FDDF4E157B6B44BC2B', // G+ Photos |
| 63 '5B5DA6D054D10DB917AF7D9EAE3C56044D1B0B03', // G+ Photos | 31 '5B5DA6D054D10DB917AF7D9EAE3C56044D1B0B03', // G+ Photos |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 104 'A8208CCC87F8261AFAEB6B85D5E8D47372DDEA6B', // http://crbug.com/478929 | 72 'A8208CCC87F8261AFAEB6B85D5E8D47372DDEA6B', // http://crbug.com/478929 |
| 105 'B620CF4203315F9F2E046EDED22C7571A935958D', // http://crbug.com/510270 | 73 'B620CF4203315F9F2E046EDED22C7571A935958D', // http://crbug.com/510270 |
| 106 'B206D8716769728278D2D300349C6CB7D7DE2EF9', // http://crbug.com/510270 | 74 'B206D8716769728278D2D300349C6CB7D7DE2EF9', // http://crbug.com/510270 |
| 107 'EFCF5358672FEE04789FD2EC3638A67ADEDB6C8C', // http://crbug.com/514696 | 75 'EFCF5358672FEE04789FD2EC3638A67ADEDB6C8C', // http://crbug.com/514696 |
| 108 'FAD85BC419FE00995D196312F53448265EFA86F1', // http://crbug.com/516527 | 76 'FAD85BC419FE00995D196312F53448265EFA86F1', // http://crbug.com/516527 |
| 109 'F33B037DEDA65F226B7409C2ADB0CF3F8565AB03', // http://crbug.com/541769 | 77 'F33B037DEDA65F226B7409C2ADB0CF3F8565AB03', // http://crbug.com/541769 |
| 110 '969C788BCBC82FBBE04A17360CA165C23A419257', // http://crbug.com/541769 | 78 '969C788BCBC82FBBE04A17360CA165C23A419257', // http://crbug.com/541769 |
| 111 '3BC3740BFC58F06088B300274B4CFBEA20136342', // http://crbug.com/541769 | 79 '3BC3740BFC58F06088B300274B4CFBEA20136342', // http://crbug.com/541769 |
| 112 ]; | 80 ]; |
| 113 | 81 |
| 82 /** | |
| 83 * A FeedbackRequest object represents a unique feedback report, requested by an | |
| 84 * instance of the feedback window. It contains the system information specific | |
| 85 * to this report, the full feedbackInfo, and callbacks to send the report upon | |
| 86 * request. | |
| 87 */ | |
| 88 class FeedbackRequest { | |
|
xiyuan
2016/03/14 23:47:28
Are we allowed to use this ES6 feature? This seems
afakhry
2016/03/15 19:25:38
I asked sky@ who referred me to estade@ who referr
xiyuan
2016/03/15 19:54:06
Thank you for digging into this. I am fine as long
| |
| 89 constructor(requestId, feedbackInfo) { | |
| 90 this.id_ = requestId; | |
| 91 this.feedbackInfo_ = feedbackInfo; | |
| 92 this.onSystemInfoReadyCallback_ = null; | |
| 93 this.isSystemInfoReady_ = false; | |
| 94 } | |
| 95 | |
| 96 /** | |
| 97 * Called when the system information is sent from the C++ side. | |
| 98 * @param {Object} sysInfo The received system information. | |
| 99 */ | |
| 100 getSystemInformationCallback(sysInfo) { | |
| 101 this.isSystemInfoReady_ = true; | |
| 102 | |
| 103 // Combine the newly received system information with whatever system | |
| 104 // information we have in the feedback info (if any). | |
| 105 if (this.feedbackInfo_.systemInformation) { | |
| 106 this.feedbackInfo_.systemInformation = | |
| 107 this.feedbackInfo_.systemInformation.concat(sysInfo); | |
| 108 } else { | |
| 109 this.feedbackInfo_.systemInformation = sysInfo; | |
| 110 } | |
|
xiyuan
2016/03/14 23:47:28
Just to double check with you that changes here on
afakhry
2016/03/15 19:25:38
Yes I made sure they refer to the same thing, and
| |
| 111 | |
| 112 if (this.onSystemInfoReadyCallback_ != null) { | |
| 113 this.onSystemInfoReadyCallback_(); | |
| 114 this.onSystemInfoReadyCallback_ = null; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * Retrieves the system information for this request object. | |
| 120 * @param {function()} callback Invoked to notify the listener that the system | |
| 121 * information has been received. | |
| 122 */ | |
| 123 getSystemInformation(callback) { | |
| 124 if (this.isSystemInfoReady_) { | |
| 125 callback(); | |
| 126 return; | |
| 127 } | |
| 128 | |
| 129 this.onSystemInfoReadyCallback_ = callback; | |
| 130 // The C++ side must reply to the callback specific to this object. | |
| 131 var boundCallback = this.getSystemInformationCallback.bind(this); | |
| 132 chrome.feedbackPrivate.getSystemInformation(boundCallback); | |
| 133 } | |
| 134 | |
| 135 /** | |
| 136 * Sends the feedback report represented by the object, either now if system | |
| 137 * information is ready, or later once it is. | |
| 138 * @param {boolean} useSystemInfo True if the user would like the system | |
| 139 * information to be sent with the report. | |
| 140 */ | |
| 141 sendReport(useSystemInfo) { | |
| 142 if (useSystemInfo && !this.isSystemInfoReady_) { | |
| 143 this.onSystemInfoReadyCallback_ = this.sendReportNow; | |
|
xiyuan
2016/03/14 23:47:28
Think we need to bind here, i.e. this.sendReportNo
afakhry
2016/03/15 19:25:38
It works without this bind, since it will be calle
xiyuan
2016/03/15 19:54:06
Interesting. Just tried it and it works as you des
| |
| 144 return; | |
| 145 } | |
| 146 | |
| 147 this.sendReportNow(); | |
| 148 } | |
| 149 | |
| 150 /** | |
| 151 * Sends the report immediately and removes this object once the report is | |
| 152 * sent. | |
| 153 */ | |
| 154 sendReportNow() { | |
| 155 /** @const */ var ID = this.id_; | |
| 156 chrome.feedbackPrivate.sendFeedback(this.feedbackInfo_, | |
| 157 function(result) { | |
| 158 console.log('Feedback: Report sent for request with ID ' + ID); | |
| 159 | |
| 160 // The following deletes this FeedbackRequest object. | |
| 161 feedbackRequestsMap.delete(ID); | |
| 162 }); | |
| 163 } | |
| 164 }; | |
| 165 | |
| 166 /** | |
| 167 * Maps each FeedbackRequest object by its unique ID. | |
| 168 * @type {Map} | |
| 169 */ | |
| 170 var feedbackRequestsMap = new Map(); | |
| 171 | |
| 172 /** | |
| 173 * Used to generate unique IDs for FeedbackRequest objects. | |
| 174 * @type {number} | |
| 175 */ | |
| 176 var lastUsedId = 0; | |
| 114 | 177 |
| 115 /** | 178 /** |
| 116 * Function to determine whether or not a given extension id is whitelisted to | 179 * Function to determine whether or not a given extension id is whitelisted to |
| 117 * invoke the feedback UI. If the extension is whitelisted, the callback to | 180 * invoke the feedback UI. If the extension is whitelisted, the callback to |
| 118 * start the Feedback UI will be called. | 181 * start the Feedback UI will be called. |
| 119 * @param {string} id the id of the sender extension. | 182 * @param {string} id the id of the sender extension. |
| 120 * @param {Function} startFeedbackCallback The callback function that will | 183 * @param {Function} startFeedbackCallback The callback function that will |
| 121 * will start the feedback UI. | 184 * will start the feedback UI. |
| 122 * @param {Object} feedbackInfo The feedback info object to pass to the | 185 * @param {Object} feedbackInfo The feedback info object to pass to the |
| 123 * start feedback UI callback. | 186 * start feedback UI callback. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 138 } | 201 } |
| 139 | 202 |
| 140 /** | 203 /** |
| 141 * Callback which gets notified once our feedback UI has loaded and is ready to | 204 * Callback which gets notified once our feedback UI has loaded and is ready to |
| 142 * receive its initial feedback info object. | 205 * receive its initial feedback info object. |
| 143 * @param {Object} request The message request object. | 206 * @param {Object} request The message request object. |
| 144 * @param {Object} sender The sender of the message. | 207 * @param {Object} sender The sender of the message. |
| 145 * @param {function(Object)} sendResponse Callback for sending a response. | 208 * @param {function(Object)} sendResponse Callback for sending a response. |
| 146 */ | 209 */ |
| 147 function feedbackReadyHandler(request, sender, sendResponse) { | 210 function feedbackReadyHandler(request, sender, sendResponse) { |
| 148 if (request.ready) { | 211 if (request.ready) |
| 149 chrome.runtime.sendMessage( | 212 chrome.runtime.sendMessage({sentFromEventPage: true}); |
| 150 {sentFromEventPage: true, data: initialFeedbackInfo}); | |
| 151 } | |
| 152 } | 213 } |
| 153 | 214 |
| 154 | |
| 155 /** | 215 /** |
| 156 * Callback which gets notified if another extension is requesting feedback. | 216 * Callback which gets notified if another extension is requesting feedback. |
| 157 * @param {Object} request The message request object. | 217 * @param {Object} request The message request object. |
| 158 * @param {Object} sender The sender of the message. | 218 * @param {Object} sender The sender of the message. |
| 159 * @param {function(Object)} sendResponse Callback for sending a response. | 219 * @param {function(Object)} sendResponse Callback for sending a response. |
| 160 */ | 220 */ |
| 161 function requestFeedbackHandler(request, sender, sendResponse) { | 221 function requestFeedbackHandler(request, sender, sendResponse) { |
| 162 if (request.requestFeedback) | 222 if (request.requestFeedback) |
| 163 senderWhitelisted(sender.id, startFeedbackUI, request.feedbackInfo); | 223 senderWhitelisted(sender.id, startFeedbackUI, request.feedbackInfo); |
| 164 } | 224 } |
| 165 | 225 |
| 166 /** | 226 /** |
| 167 * Called when the system information is sent from the C++ side. | |
| 168 * @param {Object} sysInfo The received system information. | |
| 169 */ | |
| 170 | |
| 171 function getSystemInformationCallback(sysInfo) { | |
| 172 systemInfo = sysInfo; | |
| 173 isSystemInfoReady = true; | |
| 174 if (onSystemInfoReadyCallback != null) | |
| 175 onSystemInfoReadyCallback(sysInfo); | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * If the user requested to send the report before the system information was | |
| 180 * received, this callback will be invoked once the system information is ready | |
| 181 * to send the report then. | |
| 182 * @param {Object} sysInfo The received system information. | |
| 183 */ | |
| 184 | |
| 185 function onSysInfoReadyForSend(sysInfo) { | |
| 186 // Combine the newly received system information with whatever system | |
| 187 // information we have in the final feedback info (if any). | |
| 188 if (finalFeedbackInfo.systemInformation) { | |
| 189 finalFeedbackInfo.systemInformation = | |
| 190 finalFeedbackInfo.systemInformation.concat(sysInfo); | |
| 191 } else { | |
| 192 finalFeedbackInfo.systemInformation = sysInfo; | |
| 193 } | |
| 194 | |
| 195 chrome.feedbackPrivate.sendFeedback(finalFeedbackInfo, function(result) {}); | |
| 196 } | |
| 197 | |
| 198 /** | |
| 199 * Callback which starts up the feedback UI. | 227 * Callback which starts up the feedback UI. |
| 200 * @param {Object} feedbackInfo Object containing any initial feedback info. | 228 * @param {Object} feedbackInfo Object containing any initial feedback info. |
| 201 */ | 229 */ |
| 202 function startFeedbackUI(feedbackInfo) { | 230 function startFeedbackUI(feedbackInfo) { |
| 203 var win = chrome.app.window.get(FEEDBACK_DEFAULT_WINDOW_ID); | 231 var win = chrome.app.window.get(FEEDBACK_DEFAULT_WINDOW_ID); |
| 204 if (win) { | 232 if (win) { |
| 205 win.show(); | 233 win.show(); |
| 206 return; | 234 return; |
| 207 } | 235 } |
| 208 chrome.app.window.create('html/default.html', { | 236 chrome.app.window.create('html/default.html', { |
| 209 frame: 'none', | 237 frame: 'none', |
| 210 id: FEEDBACK_DEFAULT_WINDOW_ID, | 238 id: FEEDBACK_DEFAULT_WINDOW_ID, |
| 211 width: FEEDBACK_WIDTH, | 239 width: FEEDBACK_WIDTH, |
| 212 height: FEEDBACK_HEIGHT, | 240 height: FEEDBACK_HEIGHT, |
| 213 hidden: true, | 241 hidden: true, |
| 214 resizable: false }, | 242 resizable: false }, |
| 215 function(appWindow) { | 243 function(appWindow) { |
| 216 // Initialize the state of the app only once upon the creation of the | 244 // Generate a unique feedback request ID for this feedback window. |
| 217 // feedback UI window. | 245 // A FeedbackRequest object is used to represent this instance of the |
| 218 initialFeedbackInfo = feedbackInfo; | 246 // feedback window. |
| 219 finalFeedbackInfo = null; | 247 /** @const */ var ID = ++lastUsedId; |
| 220 systemInfo = null; | 248 feedbackRequestsMap.set(ID, new FeedbackRequest(ID, feedbackInfo)); |
|
xiyuan
2016/03/14 23:47:28
It seems |feedbackRequestsMap| could be optimized
afakhry
2016/03/15 19:25:38
Yes, thanks for the suggestion. Done.
However, we
xiyuan
2016/03/15 19:54:06
I don't think we need to manage this explicitly. I
afakhry
2016/03/16 00:45:34
Right. I removed the map, and it works. My brain n
| |
| 221 isSystemInfoReady = false; | 249 // The feedbackInfo member of the new window should refer to the one in |
| 222 onSystemInfoReadyCallback = null; | 250 // its corresponding FeedbackRequest object to avoid copying and |
| 251 // duplicatations. | |
| 252 appWindow.contentWindow.feedbackInfo = | |
| 253 feedbackRequestsMap.get(ID).feedbackInfo_; | |
| 254 | |
| 255 // When this instance of the feedback window is closed, the | |
| 256 // corresponding FeedbackRequest object must be deleted unless it needs | |
| 257 // to be kept alive until the report is sent later. | |
| 258 var deferRequestdeleteUntilSent = false; | |
| 223 | 259 |
| 224 // Define some functions for the new window so that it can call back | 260 // Define some functions for the new window so that it can call back |
| 225 // into here. | 261 // into here. |
| 226 | 262 |
| 227 // Define a function for the new window to get the system information. | 263 // Define a function for the new window to get the system information. |
| 228 appWindow.contentWindow.getSystemInformation = function(callback) { | 264 appWindow.contentWindow.getSystemInformation = function(callback) { |
| 229 if (!isSystemInfoReady) { | 265 var request = feedbackRequestsMap.get(ID); |
| 230 onSystemInfoReadyCallback = callback; | 266 if (request == undefined) { |
| 231 chrome.feedbackPrivate.getSystemInformation( | 267 console.log('Feedback Error: Invalid request ID ' + ID); |
| 232 getSystemInformationCallback); | |
| 233 return; | 268 return; |
| 234 } | 269 } |
| 235 | 270 |
| 236 callback(systemInfo); | 271 request.getSystemInformation(callback); |
| 237 }; | 272 }; |
| 238 | 273 |
| 239 // Define a function to be called by the new window when the report is | 274 // Define a function to request sending the feedback report. |
| 240 // not ready yet, and has to be sent later when the system information | 275 appWindow.contentWindow.sendFeedbackReport = function(useSystemInfo) { |
| 241 // is received. | 276 var request = feedbackRequestsMap.get(ID); |
| 242 appWindow.contentWindow.sendReportLater = function(feedbackInfo) { | 277 if (request == undefined) { |
| 243 finalFeedbackInfo = feedbackInfo; | 278 console.log('Feedback Error: Invalid request ID ' + ID); |
| 244 if (!isSystemInfoReady) { | |
| 245 onSystemInfoReadyCallback = onSysInfoReadyForSend; | |
| 246 return; | 279 return; |
| 247 } | 280 } |
| 248 | 281 |
| 249 onSysInfoReadyForSend(systemInfo); | 282 // The report will be sent by the request object. Keep it alive until |
| 283 // the report is sent. | |
| 284 deferRequestdeleteUntilSent = true; | |
| 285 request.sendReport(useSystemInfo); | |
| 250 }; | 286 }; |
| 251 | 287 |
| 252 // Returns whether the system information has been received or not. | 288 // Observe when the window is closed. |
| 253 appWindow.contentWindow.isSystemInfoReady = function() { | 289 appWindow.onClosed.addListener(function() { |
| 254 return isSystemInfoReady; | 290 if (!deferRequestdeleteUntilSent) |
| 255 }; | 291 feedbackRequestsMap.delete(appWindow.contentWindow.REQUEST_ID); |
| 292 }); | |
| 256 }); | 293 }); |
| 257 } | 294 } |
| 258 | 295 |
| 259 chrome.runtime.onMessage.addListener(feedbackReadyHandler); | 296 chrome.runtime.onMessage.addListener(feedbackReadyHandler); |
| 260 chrome.runtime.onMessageExternal.addListener(requestFeedbackHandler); | 297 chrome.runtime.onMessageExternal.addListener(requestFeedbackHandler); |
| 261 chrome.feedbackPrivate.onFeedbackRequested.addListener(startFeedbackUI); | 298 chrome.feedbackPrivate.onFeedbackRequested.addListener(startFeedbackUI); |
| OLD | NEW |