summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 03:41:12 +0000
committerhirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 03:41:12 +0000
commitf69a9b74a20cd02137d339cea3c8624ea238cd9c (patch)
tree2c9afdf1d81c3dfaaf4a64aff7016b8ac5aa35ba
parent544258dd28cd649107cf9f8aa356b95da88edc1a (diff)
downloadchromium_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
-rw-r--r--chrome/browser/resources/file_manager/background/js/device_handler.js67
-rw-r--r--chrome/test/data/file_manager/unit_tests/device_handler_unittest.html2
-rw-r--r--chrome/test/data/file_manager/unit_tests/device_handler_unittest.js30
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);
}