summaryrefslogtreecommitdiffstats
path: root/chrome/browser/usb/usb_chooser_bubble_controller.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/usb/usb_chooser_bubble_controller.cc')
-rw-r--r--chrome/browser/usb/usb_chooser_bubble_controller.cc203
1 files changed, 203 insertions, 0 deletions
diff --git a/chrome/browser/usb/usb_chooser_bubble_controller.cc b/chrome/browser/usb/usb_chooser_bubble_controller.cc
new file mode 100644
index 0000000..b4cce8f
--- /dev/null
+++ b/chrome/browser/usb/usb_chooser_bubble_controller.cc
@@ -0,0 +1,203 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/usb/usb_chooser_bubble_controller.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/usb/usb_chooser_context.h"
+#include "chrome/browser/usb/usb_chooser_context_factory.h"
+#include "chrome/common/url_constants.h"
+#include "components/bubble/bubble_controller.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "device/core/device_client.h"
+#include "device/usb/mojo/type_converters.h"
+#include "device/usb/usb_device.h"
+#include "device/usb/usb_device_filter.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Reasons the chooser may be closed. These are used in histograms so do not
+// remove/reorder entries. Only add at the end just before
+// WEBUSB_CHOOSER_CLOSED_MAX. Also remember to update the enum listing in
+// tools/metrics/histograms/histograms.xml.
+enum WebUsbChooserClosed {
+ // The user cancelled the permission prompt without selecting a device.
+ WEBUSB_CHOOSER_CLOSED_CANCELLED = 0,
+ // The user probably cancelled the permission prompt without selecting a
+ // device because there were no devices to select.
+ WEBUSB_CHOOSER_CLOSED_CANCELLED_NO_DEVICES,
+ // The user granted permission to access a device.
+ WEBUSB_CHOOSER_CLOSED_PERMISSION_GRANTED,
+ // The user granted permission to access a device but that permission will be
+ // revoked when the device is disconnected.
+ WEBUSB_CHOOSER_CLOSED_EPHEMERAL_PERMISSION_GRANTED,
+ // Maximum value for the enum.
+ WEBUSB_CHOOSER_CLOSED_MAX
+};
+
+void RecordChooserClosure(WebUsbChooserClosed disposition) {
+ UMA_HISTOGRAM_ENUMERATION("WebUsb.ChooserClosed", disposition,
+ WEBUSB_CHOOSER_CLOSED_MAX);
+}
+
+// Check if the origin is allowed.
+bool FindInAllowedOrigins(const device::WebUsbAllowedOrigins* allowed_origins,
+ const GURL& origin) {
+ if (!allowed_origins)
+ return false;
+
+ if (ContainsValue(allowed_origins->origins, origin))
+ return true;
+
+ for (const auto& config : allowed_origins->configurations) {
+ if (ContainsValue(config.origins, origin))
+ return true;
+
+ for (const auto& function : config.functions) {
+ if (ContainsValue(function.origins, origin))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+UsbChooserBubbleController::UsbChooserBubbleController(
+ content::RenderFrameHost* owner,
+ mojo::Array<device::usb::DeviceFilterPtr> device_filters,
+ content::RenderFrameHost* render_frame_host,
+ const webusb::WebUsbPermissionBubble::GetPermissionCallback& callback)
+ : ChooserBubbleController(owner),
+ render_frame_host_(render_frame_host),
+ callback_(callback),
+ usb_service_observer_(this),
+ weak_factory_(this) {
+ device::UsbService* usb_service =
+ device::DeviceClient::Get()->GetUsbService();
+ if (!usb_service)
+ return;
+
+ if (!usb_service_observer_.IsObserving(usb_service))
+ usb_service_observer_.Add(usb_service);
+
+ if (!device_filters.is_null())
+ filters_ = device_filters.To<std::vector<device::UsbDeviceFilter>>();
+
+ usb_service->GetDevices(
+ base::Bind(&UsbChooserBubbleController::GotUsbDeviceList,
+ weak_factory_.GetWeakPtr()));
+}
+
+UsbChooserBubbleController::~UsbChooserBubbleController() {
+ if (!callback_.is_null())
+ callback_.Run(nullptr);
+}
+
+size_t UsbChooserBubbleController::NumOptions() const {
+ return devices_.size();
+}
+
+const base::string16& UsbChooserBubbleController::GetOption(
+ size_t index) const {
+ DCHECK_LT(index, devices_.size());
+ return devices_[index].second;
+}
+
+void UsbChooserBubbleController::Select(size_t index) {
+ DCHECK_LT(index, devices_.size());
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host_);
+ GURL embedding_origin =
+ web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin();
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents->GetBrowserContext());
+ UsbChooserContext* chooser_context =
+ UsbChooserContextFactory::GetForProfile(profile);
+ chooser_context->GrantDevicePermission(
+ render_frame_host_->GetLastCommittedURL().GetOrigin(), embedding_origin,
+ devices_[index].first->guid());
+
+ device::usb::DeviceInfoPtr device_info_ptr =
+ device::usb::DeviceInfo::From(*devices_[index].first);
+ callback_.Run(std::move(device_info_ptr));
+ callback_.reset(); // Reset |callback_| so that it is only run once.
+
+ RecordChooserClosure(devices_[index].first->serial_number().empty()
+ ? WEBUSB_CHOOSER_CLOSED_EPHEMERAL_PERMISSION_GRANTED
+ : WEBUSB_CHOOSER_CLOSED_PERMISSION_GRANTED);
+
+ if (bubble_reference_)
+ bubble_reference_->CloseBubble(BUBBLE_CLOSE_ACCEPTED);
+}
+
+void UsbChooserBubbleController::Cancel() {
+ RecordChooserClosure(devices_.size() == 0
+ ? WEBUSB_CHOOSER_CLOSED_CANCELLED_NO_DEVICES
+ : WEBUSB_CHOOSER_CLOSED_CANCELLED);
+
+ if (bubble_reference_)
+ bubble_reference_->CloseBubble(BUBBLE_CLOSE_CANCELED);
+}
+
+void UsbChooserBubbleController::Close() {}
+
+void UsbChooserBubbleController::OnDeviceAdded(
+ scoped_refptr<device::UsbDevice> device) {
+ if (device::UsbDeviceFilter::MatchesAny(device, filters_) &&
+ FindInAllowedOrigins(
+ device->webusb_allowed_origins(),
+ render_frame_host_->GetLastCommittedURL().GetOrigin())) {
+ devices_.push_back(std::make_pair(device, device->product_string()));
+ if (observer())
+ observer()->OnOptionAdded(devices_.size() - 1);
+ }
+}
+
+GURL UsbChooserBubbleController::GetHelpCenterUrl() const {
+ return GURL(chrome::kChooserUsbOverviewURL);
+}
+
+void UsbChooserBubbleController::OnDeviceRemoved(
+ scoped_refptr<device::UsbDevice> device) {
+ for (auto it = devices_.begin(); it != devices_.end(); ++it) {
+ if (it->first == device) {
+ size_t index = it - devices_.begin();
+ devices_.erase(it);
+ if (observer())
+ observer()->OnOptionRemoved(index);
+ return;
+ }
+ }
+}
+
+// Get a list of devices that can be shown in the chooser bubble UI for
+// user to grant permsssion.
+void UsbChooserBubbleController::GotUsbDeviceList(
+ const std::vector<scoped_refptr<device::UsbDevice>>& devices) {
+ for (const auto& device : devices) {
+ if (device::UsbDeviceFilter::MatchesAny(device, filters_) &&
+ FindInAllowedOrigins(
+ device->webusb_allowed_origins(),
+ render_frame_host_->GetLastCommittedURL().GetOrigin())) {
+ devices_.push_back(std::make_pair(device, device->product_string()));
+ }
+ }
+ if (observer())
+ observer()->OnOptionsInitialized();
+}
+
+void UsbChooserBubbleController::set_bubble_reference(
+ BubbleReference bubble_reference) {
+ bubble_reference_ = bubble_reference;
+}