diff options
author | hirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-07 03:41:12 +0000 |
---|---|---|
committer | hirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-07 03:41:12 +0000 |
commit | f69a9b74a20cd02137d339cea3c8624ea238cd9c (patch) | |
tree | 2c9afdf1d81c3dfaaf4a64aff7016b8ac5aa35ba | |
parent | 544258dd28cd649107cf9f8aa356b95da88edc1a (diff) | |
download | chromium_src-f69a9b74a20cd02137d339cea3c8624ea238cd9c.zip chromium_src-f69a9b74a20cd02137d339cea3c8624ea238cd9c.tar.gz chromium_src-f69a9b74a20cd02137d339cea3c8624ea238cd9c.tar.bz2 |
Merge 265906 "Files.app: Fix race in the device handler."
> Files.app: Fix race in the device handler.
>
> There is a race like:
>
> 1. deviceAdded, call notification.show().
> 2. diskAdded and it is not mounted. call notification.hide, before
> notification.show complates.
>
> This CL queues notification.show and notificaiton.hide, and delays
> notification.show to prevent blink of the notification.
>
> BUG=344036
> TEST=manually
>
> Review URL: https://codereview.chromium.org/248823002
TBR=hirono@chromium.org
Review URL: https://codereview.chromium.org/266813002
git-svn-id: svn://svn.chromium.org/chrome/branches/1916/src@268664 0039d316-1c4b-4281-b951-d872f2087c98
3 files changed, 86 insertions, 13 deletions
diff --git a/chrome/browser/resources/file_manager/background/js/device_handler.js b/chrome/browser/resources/file_manager/background/js/device_handler.js index a6197bb..4906ff2 100644 --- a/chrome/browser/resources/file_manager/background/js/device_handler.js +++ b/chrome/browser/resources/file_manager/background/js/device_handler.js @@ -50,7 +50,21 @@ DeviceHandler.Notification = function(prefix, title, message) { */ this.message = message; - Object.freeze(this); + /** + * Queue of API call. + * @type {AsyncUtil.Queue} + * @private + */ + this.queue_ = new AsyncUtil.Queue(); + + /** + * Timeout ID. + * @type {number} + * @private + */ + this.pendingShowTimerId_ = 0; + + Object.seal(this); }; /** @@ -112,17 +126,32 @@ DeviceHandler.Notification.FORMAT_FAIL = new DeviceHandler.Notification( * Shows the notification for the device path. * @param {string} devicePath Device path. * @param {string=} opt_message Message overrides the default message. + * @return {string} Notification ID. */ DeviceHandler.Notification.prototype.show = function(devicePath, opt_message) { - chrome.notifications.create( - this.makeId_(devicePath), - { - type: 'basic', - title: str(this.title), - message: opt_message || str(this.message), - iconUrl: chrome.runtime.getURL('/common/images/icon96.png') - }, - function() {}); + this.clearTimeout_(); + var notificationId = this.makeId_(devicePath); + this.queue_.run(function(callback) { + chrome.notifications.create( + notificationId, + { + type: 'basic', + title: str(this.title), + message: opt_message || str(this.message), + iconUrl: chrome.runtime.getURL('/common/images/icon96.png') + }, + callback); + }.bind(this)); + return notificationId; +}; + +/** + * Shows the notificaiton after 5 seconds. + * @param {string} devicePath Device path. + */ +DeviceHandler.Notification.prototype.showLater = function(devicePath) { + this.clearTimeout_(); + this.pendingShowTimerId_ = setTimeout(this.show.bind(this, devicePath), 5000); }; /** @@ -130,7 +159,10 @@ DeviceHandler.Notification.prototype.show = function(devicePath, opt_message) { * @param {string} devicePath Device path. */ DeviceHandler.Notification.prototype.hide = function(devicePath) { - chrome.notifications.clear(this.makeId_(devicePath), function() {}); + this.clearTimeout_(); + this.queue_.run(function(callback) { + chrome.notifications.clear(this.makeId_(devicePath), callback); + }.bind(this)); }; /** @@ -144,6 +176,17 @@ DeviceHandler.Notification.prototype.makeId_ = function(devicePath) { }; /** + * Cancels the timeout request. + * @private + */ +DeviceHandler.Notification.prototype.clearTimeout_ = function() { + if (this.pendingShowTimerId_) { + clearTimeout(this.pendingShowTimerId_); + this.pendingShowTimerId_ = 0; + } +}; + +/** * Handles notifications from C++ sides. * @param {DeviceEvent} event Device event. * @private @@ -151,7 +194,7 @@ DeviceHandler.Notification.prototype.makeId_ = function(devicePath) { DeviceHandler.prototype.onDeviceChanged_ = function(event) { switch (event.type) { case 'added': - DeviceHandler.Notification.DEVICE.show(event.devicePath); + DeviceHandler.Notification.DEVICE.showLater(event.devicePath); this.mountStatus_[event.devicePath] = DeviceHandler.MountStatus.NO_RESULT; break; case 'disabled': diff --git a/chrome/test/data/file_manager/unit_tests/device_handler_unittest.html b/chrome/test/data/file_manager/unit_tests/device_handler_unittest.html index 8b8b1b6..707158d 100644 --- a/chrome/test/data/file_manager/unit_tests/device_handler_unittest.html +++ b/chrome/test/data/file_manager/unit_tests/device_handler_unittest.html @@ -9,6 +9,8 @@ <script src="../../../../../ui/webui/resources/js/load_time_data.js"></script> +<!-- Need to load async_util.js before device_handler.js --> +<script src="../../../../browser/resources/file_manager/common/js/async_util.js"></script> <script src="../../../../browser/resources/file_manager/background/js/device_handler.js"></script> <script src="../../../../browser/resources/file_manager/common/js/util.js"></script> diff --git a/chrome/test/data/file_manager/unit_tests/device_handler_unittest.js b/chrome/test/data/file_manager/unit_tests/device_handler_unittest.js index 2fb362c..8bd41c1 100644 --- a/chrome/test/data/file_manager/unit_tests/device_handler_unittest.js +++ b/chrome/test/data/file_manager/unit_tests/device_handler_unittest.js @@ -14,6 +14,12 @@ var handler; */ var chrome; +/** + * Callbacks registered by setTimeout. + * @type {Array.<function>} + */ +var timeoutCallbacks; + // Set up the test components. function setUp() { // Set up string assets. @@ -50,8 +56,9 @@ function setUp() { create: function(id, params, callback) { assertFalse(!!this.items[id]); this.items[id] = params; + callback(); }, - clear: function(id) { delete this.items[id]; }, + clear: function(id, callback) { delete this.items[id]; callback(); }, items: {} }, runtime: { @@ -59,15 +66,36 @@ function setUp() { } }; + // Reset timeout callbacks. + timeoutCallbacks = []; + // Make a device handler. handler = new DeviceHandler(); } +/** + * Overrided setTimoeut funciton. + */ +window.setTimeout = function(func) { + timeoutCallbacks.push(func); +}; + +/** + * Call all pending timeout functions. + */ +function callTimeoutCallbacks() { + while (timeoutCallbacks.length) { + timeoutCallbacks.shift()(); + } +} + function registerTypicalDevice() { chrome.fileBrowserPrivate.onDeviceChanged.dispatch({ type: 'added', devicePath: '/device/path' }); + assertFalse('device:/device/path' in chrome.notifications.items); + callTimeoutCallbacks(); assertEquals('Scanning...', chrome.notifications.items['device:/device/path'].message); } |