1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef EXTENSIONS_BROWSER_API_HID_HID_DEVICE_MANAGER_H_
6 #define EXTENSIONS_BROWSER_API_HID_HID_DEVICE_MANAGER_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/scoped_observer.h"
17 #include "base/threading/thread_checker.h"
18 #include "extensions/browser/browser_context_keyed_api_factory.h"
19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_event_histogram_value.h"
21 #include "extensions/common/api/hid.h"
22 #include "mojo/public/cpp/bindings/associated_receiver.h"
23 #include "mojo/public/cpp/bindings/pending_remote.h"
24 #include "mojo/public/cpp/bindings/remote.h"
25 #include "services/device/public/mojom/hid.mojom.h"
26 
27 namespace device {
28 class HidDeviceFilter;
29 }
30 
31 namespace extensions {
32 
33 class Extension;
34 
35 // This class maps devices enumerated by device::HidManager to resource IDs
36 // returned by the chrome.hid API.
37 class HidDeviceManager : public BrowserContextKeyedAPI,
38                          public device::mojom::HidManagerClient,
39                          public EventRouter::Observer {
40  public:
41   typedef base::Callback<void(std::unique_ptr<base::ListValue>)>
42       GetApiDevicesCallback;
43 
44   using ConnectCallback = device::mojom::HidManager::ConnectCallback;
45 
46   explicit HidDeviceManager(content::BrowserContext* context);
47   ~HidDeviceManager() override;
48 
49   // BrowserContextKeyedAPI implementation.
50   static BrowserContextKeyedAPIFactory<HidDeviceManager>* GetFactoryInstance();
51 
52   // Convenience method to get the HidDeviceManager for a profile.
Get(content::BrowserContext * context)53   static HidDeviceManager* Get(content::BrowserContext* context) {
54     return BrowserContextKeyedAPIFactory<HidDeviceManager>::Get(context);
55   }
56 
57   // Enumerates available devices, taking into account the permissions held by
58   // the given extension and the filters provided. The provided callback will
59   // be posted to the calling thread's task runner with a list of device info
60   // objects.
61   void GetApiDevices(const Extension* extension,
62                      const std::vector<device::HidDeviceFilter>& filters,
63                      const GetApiDevicesCallback& callback);
64 
65   // Converts a list of device::mojom::HidDeviceInfo objects into a value that
66   // can be returned through the API.
67   std::unique_ptr<base::ListValue> GetApiDevicesFromList(
68       std::vector<device::mojom::HidDeviceInfoPtr> devices);
69 
70   const device::mojom::HidDeviceInfo* GetDeviceInfo(int resource_id);
71 
72   void Connect(const std::string& device_guid, ConnectCallback callback);
73 
74   // Checks if |extension| has permission to open |device_info|. Set
75   // |update_last_used| to update the timestamp in the DevicePermissionsManager.
76   bool HasPermission(const Extension* extension,
77                      const device::mojom::HidDeviceInfo& device_info,
78                      bool update_last_used);
79 
80   // Lazily perform an initial enumeration and set client to HidManager when
81   // the first API customer makes a request or registers an event listener.
82   virtual void LazyInitialize();
83 
84   // Allows tests to override where this class binds a HidManager receiver.
85   using HidManagerBinder = base::RepeatingCallback<void(
86       mojo::PendingReceiver<device::mojom::HidManager>)>;
87   static void OverrideHidManagerBinderForTesting(HidManagerBinder binder);
88 
89  private:
90   friend class BrowserContextKeyedAPIFactory<HidDeviceManager>;
91 
92   typedef std::map<int, device::mojom::HidDeviceInfoPtr>
93       ResourceIdToDeviceInfoMap;
94   typedef std::map<std::string, int> DeviceIdToResourceIdMap;
95 
96   struct GetApiDevicesParams;
97 
98   // KeyedService:
99   void Shutdown() override;
100 
101   // BrowserContextKeyedAPI:
service_name()102   static const char* service_name() { return "HidDeviceManager"; }
103   static const bool kServiceHasOwnInstanceInIncognito = true;
104 
105   // EventRouter::Observer:
106   void OnListenerAdded(const EventListenerInfo& details) override;
107 
108   // device::mojom::HidManagerClient implementation:
109   void DeviceAdded(device::mojom::HidDeviceInfoPtr device) override;
110   void DeviceRemoved(device::mojom::HidDeviceInfoPtr device) override;
111 
112   // Builds a list of device info objects representing the currently enumerated
113   // devices, taking into account the permissions held by the given extension
114   // and the filters provided.
115   std::unique_ptr<base::ListValue> CreateApiDeviceList(
116       const Extension* extension,
117       const std::vector<device::HidDeviceFilter>& filters);
118   void OnEnumerationComplete(
119       std::vector<device::mojom::HidDeviceInfoPtr> devices);
120 
121   void DispatchEvent(events::HistogramValue histogram_value,
122                      const std::string& event_name,
123                      std::unique_ptr<base::ListValue> event_args,
124                      const device::mojom::HidDeviceInfo& device_info);
125 
126   base::ThreadChecker thread_checker_;
127   content::BrowserContext* browser_context_ = nullptr;
128   EventRouter* event_router_ = nullptr;
129   bool initialized_ = false;
130   mojo::Remote<device::mojom::HidManager> hid_manager_;
131   mojo::AssociatedReceiver<device::mojom::HidManagerClient> receiver_{this};
132   bool enumeration_ready_ = false;
133   std::vector<std::unique_ptr<GetApiDevicesParams>> pending_enumerations_;
134   int next_resource_id_ = 0;
135   ResourceIdToDeviceInfoMap devices_;
136   DeviceIdToResourceIdMap resource_ids_;
137   base::WeakPtrFactory<HidDeviceManager> weak_factory_{this};
138 
139   DISALLOW_COPY_AND_ASSIGN(HidDeviceManager);
140 };
141 
142 }  // namespace extensions
143 
144 #endif  // EXTENSIONS_BROWSER_API_HID_HID_DEVICE_MANAGER_H_
145