910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_API_DEVICE_PERMISSIONS_PROMPT_H_
#define EXTENSIONS_BROWSER_API_DEVICE_PERMISSIONS_PROMPT_H_

#include <stddef.h>

#include <memory>
#include <string>
#include <vector>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "services/device/public/mojom/usb_device.mojom.h"
#include "services/device/public/mojom/usb_manager.mojom.h"

namespace content {
class BrowserContext;
class WebContents;
}

namespace device {
class HidDeviceFilter;
}

namespace extensions {

class Extension;

// Platform-independent interface for displaing a UI for choosing devices
// (similar to choosing files).
class DevicePermissionsPrompt {
 public:
  using UsbDevicesCallback =
      base::OnceCallback<void(std::vector<device::mojom::UsbDeviceInfoPtr>)>;
  using HidDevicesCallback =
      base::OnceCallback<void(std::vector<device::mojom::HidDeviceInfoPtr>)>;

  // Context information available to the UI implementation.
  class Prompt : public base::RefCounted<Prompt> {
   public:
    // This class stores the device information displayed in the UI. It should
    // be extended to support particular device types.
    class DeviceInfo {
     public:
      DeviceInfo();
      virtual ~DeviceInfo();

      const std::u16string& name() const { return name_; }
      const std::u16string& serial_number() const { return serial_number_; }
      bool granted() const { return granted_; }
      void set_granted() { granted_ = true; }

     protected:
      std::u16string name_;
      std::u16string serial_number_;

     private:
      bool granted_ = false;
    };

    // Since the set of devices can change while the UI is visible an
    // implementation should register an observer.
    class Observer {
     public:
      // Must be called after OnDeviceAdded() has been called for the final time
      // to create the initial set of options.
      virtual void OnDevicesInitialized() = 0;
      virtual void OnDeviceAdded(size_t index,
                                 const std::u16string& device_name) = 0;
      virtual void OnDeviceRemoved(size_t index,
                                   const std::u16string& device_name) = 0;

     protected:
      virtual ~Observer();
    };

    Prompt(const Extension* extension,
           content::BrowserContext* context,
           bool multiple);

    Prompt(const Prompt&) = delete;
    Prompt& operator=(const Prompt&) = delete;

    // Only one observer may be registered at a time.
    virtual void SetObserver(Observer* observer);

    size_t GetDeviceCount() const { return devices_.size(); }
    std::u16string GetDeviceName(size_t index) const;
    std::u16string GetDeviceSerialNumber(size_t index) const;

    // Notifies the DevicePermissionsManager for the current extension that
    // access to the device at the given index is now granted.
    void GrantDevicePermission(size_t index);

    virtual void Dismissed() = 0;

    // Allow the user to select multiple devices.
    bool multiple() const { return multiple_; }

   protected:
    virtual ~Prompt();

    void AddDevice(std::unique_ptr<DeviceInfo> device);

    const Extension* extension() const { return extension_; }
    Observer* observer() const { return observer_; }
    content::BrowserContext* browser_context() const {
      return browser_context_;
    }

    // Subclasses may fill this with a particular subclass of DeviceInfo and may
    // assume that only that instances of that type are stored here.
    std::vector<std::unique_ptr<DeviceInfo>> devices_;

   private:
    friend class base::RefCounted<Prompt>;

    raw_ptr<const extensions::Extension, DanglingUntriaged> extension_ =
        nullptr;
    raw_ptr<Observer, DanglingUntriaged> observer_ = nullptr;
    raw_ptr<content::BrowserContext, DanglingUntriaged> browser_context_ =
        nullptr;
    bool multiple_ = false;
  };

  explicit DevicePermissionsPrompt(content::WebContents* web_contents);

  DevicePermissionsPrompt(const DevicePermissionsPrompt&) = delete;
  DevicePermissionsPrompt& operator=(const DevicePermissionsPrompt&) = delete;

  virtual ~DevicePermissionsPrompt();

  void AskForUsbDevices(const Extension* extension,
                        content::BrowserContext* context,
                        bool multiple,
                        std::vector<device::mojom::UsbDeviceFilterPtr> filters,
                        UsbDevicesCallback callback);

  void AskForHidDevices(const Extension* extension,
                        content::BrowserContext* context,
                        bool multiple,
                        const std::vector<device::HidDeviceFilter>& filters,
                        HidDevicesCallback callback);

  static scoped_refptr<Prompt> CreateHidPromptForTest(
      const Extension* extension,
      bool multiple);
  static scoped_refptr<Prompt> CreateUsbPromptForTest(
      const Extension* extension,
      bool multiple);

  // Allows tests to override how the HidManager interface is bound.
  using HidManagerBinder = base::RepeatingCallback<void(
      mojo::PendingReceiver<device::mojom::HidManager> receiver)>;
  static void OverrideHidManagerBinderForTesting(HidManagerBinder binder);

 protected:
  virtual void ShowDialog() = 0;

  content::WebContents* web_contents() { return web_contents_; }
  scoped_refptr<Prompt> prompt() { return prompt_; }

 private:
  // Parent web contents of the device permissions UI dialog.
  raw_ptr<content::WebContents> web_contents_;

  // Parameters available to the UI implementation.
  scoped_refptr<Prompt> prompt_;
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_API_DEVICE_PERMISSIONS_PROMPT_H_