diff --git a/browser/modules/PermissionUI.jsm b/browser/modules/PermissionUI.jsm index bd94dfd24d..238b64a605 100644 --- a/browser/modules/PermissionUI.jsm +++ b/browser/modules/PermissionUI.jsm @@ -490,19 +490,24 @@ function USBPermissionPrompt(request) { function getUSBDeviceChoices(request) { let choices = []; - let types = request.types.QueryInterface(Ci.nsIArray); - if (!types.length) { - return choices; - } + try { + let types = request.types.QueryInterface(Ci.nsIArray); + if (!types.length) { + return choices; + } - let type = types.queryElementAt(0, Ci.nsIContentPermissionType); - let options = type.options; - if (!options) { - return choices; - } + let type = types.queryElementAt(0, Ci.nsIContentPermissionType); + let options = type.options; + if (!options) { + return choices; + } - for (let i = 0; i < options.length; ++i) { - choices.push(options.queryElementAt(i, Ci.nsISupportsString).data); + for (let i = 0; i < options.length; ++i) { + let option = options.queryElementAt(i, Ci.nsISupportsString); + choices.push(option.data || "USB device"); + } + } catch (ex) { + Cu.reportError("Unable to read WebUSB device choices: " + ex); } return choices; } @@ -510,6 +515,37 @@ function getUSBDeviceChoices(request) { USBPermissionPrompt.prototype = { __proto__: PermissionPromptForRequestPrototype, + // UXP builds do not always expose the requesting through + // nsIContentPermissionRequest.element. Resolve the active browser window + // here so the USB doorhanger is still shown for those requests. + get browser() { + let element = this.request.element; + if (element && element.ownerGlobal && element.ownerGlobal.PopupNotifications) { + return element; + } + + try { + let window = this.request.window; + if (window) { + let browser = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; + if (browser && browser.ownerGlobal && + browser.ownerGlobal.PopupNotifications) { + return browser; + } + } + } catch (ex) { + // Fall through to the most recent browser window below. + } + + let chromeWindow = Services.wm.getMostRecentWindow("navigator:browser"); + return chromeWindow && chromeWindow.gBrowser + ? chromeWindow.gBrowser.selectedBrowser + : element; + }, + get notificationID() { return "web-usb"; }, diff --git a/dom/usb/USB.cpp b/dom/usb/USB.cpp index 842e8d5acf..c2a5bca384 100644 --- a/dom/usb/USB.cpp +++ b/dom/usb/USB.cpp @@ -53,7 +53,11 @@ bool MatchesRequest(const USBDeviceInfo& aDevice, const USBDeviceRequestOptions& aOptions) { - bool included = false; + // Chromium accepts a chooser request that has no restrictive filters and + // lets the user select from the enumerated USB devices. Keep that useful + // behaviour in UXP as well; an empty filter list must not suppress the + // permission prompt entirely. + bool included = aOptions.mFilters.IsEmpty(); for (const auto& filter : aOptions.mFilters) { if (MatchesFilter(aDevice, filter)) { included = true;